feat: add settings

This commit is contained in:
mso7nueh
2024-09-30 12:54:55 +03:00
parent 346404503e
commit 860036c35f
18 changed files with 1052 additions and 106 deletions

View File

@@ -17,6 +17,7 @@ import 'package:eatvio_app/features/menu/presentation/pages/menu_screen.dart';
import 'package:eatvio_app/features/notifications/presentation/pages/notifications_screen.dart';
import 'package:eatvio_app/features/plans/models/plan_pagination_model.dart';
import 'package:eatvio_app/features/plans/presentation/pages/about_plan_screen.dart';
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/features/profile/presentation/pages/profile_screen.dart';
import 'package:eatvio_app/features/recipes/presentation/pages/about_recipes_screen.dart';
import 'package:eatvio_app/features/recipes/presentation/pages/recipe_create_screen.dart';
@@ -173,27 +174,37 @@ class AppRouter {
GoRoute(
path: 'general-info-screen',
name: 'generalInfoScreen',
builder: (context, state) => GeneralInfoScreen(),
builder: (context, state) => GeneralInfoScreen(
profileDetailsModel: state.extra as ProfileDetailsModel,
),
),
GoRoute(
path: 'other-info-screen',
name: 'otherInfoScreen',
builder: (context, state) => OtherInfoScreen(),
builder: (context, state) => OtherInfoScreen(
profileDetailsModel: state.extra as ProfileDetailsModel,
),
),
GoRoute(
path: 'physical-activity-screen',
name: 'physicalActivityScreen',
builder: (context, state) => PhysicalActivityScreen(),
builder: (context, state) => PhysicalActivityScreen(
profileDetailsModel: state.extra as ProfileDetailsModel,
),
),
GoRoute(
path: 'physical-form-screen',
name: 'physicalFormScreen',
builder: (context, state) => PhysicalFormScreen(),
builder: (context, state) => PhysicalFormScreen(
profileDetailsModel: state.extra as ProfileDetailsModel,
),
),
GoRoute(
path: 'pressure-screen',
name: 'pressureScreen',
builder: (context, state) => PressureScreen(),
builder: (context, state) => PressureScreen(
profileDetailsModel: state.extra as ProfileDetailsModel,
),
),
],
),

View File

@@ -0,0 +1,18 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'profile_settings_model.freezed.dart';
part 'profile_settings_model.g.dart';
@freezed
class ProfileSettingsModel with _$ProfileSettingsModel {
const factory ProfileSettingsModel({
@JsonKey(name: "new_updates_notifications") required dynamic newUpdatesNotifications,
@JsonKey(name: "diary_reminder_notifications") required dynamic diaryReminderNotifications,
@JsonKey(name: "is_mood_fillable") required bool isMoodFillable,
@JsonKey(name: "is_bedtime_fillable") required bool isBedtimeFillable,
@JsonKey(name: "is_public_profile") required bool isPublicProfile,
}) = _ProfileSettingsModel;
factory ProfileSettingsModel.fromJson(Map<String, dynamic> json) => _$ProfileSettingsModelFromJson(json);
}

View File

@@ -0,0 +1,287 @@
// 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 'profile_settings_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');
ProfileSettingsModel _$ProfileSettingsModelFromJson(Map<String, dynamic> json) {
return _ProfileSettingsModel.fromJson(json);
}
/// @nodoc
mixin _$ProfileSettingsModel {
@JsonKey(name: "new_updates_notifications")
dynamic get newUpdatesNotifications => throw _privateConstructorUsedError;
@JsonKey(name: "diary_reminder_notifications")
dynamic get diaryReminderNotifications => throw _privateConstructorUsedError;
@JsonKey(name: "is_mood_fillable")
bool get isMoodFillable => throw _privateConstructorUsedError;
@JsonKey(name: "is_bedtime_fillable")
bool get isBedtimeFillable => throw _privateConstructorUsedError;
@JsonKey(name: "is_public_profile")
bool get isPublicProfile => throw _privateConstructorUsedError;
/// Serializes this ProfileSettingsModel to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of ProfileSettingsModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ProfileSettingsModelCopyWith<ProfileSettingsModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ProfileSettingsModelCopyWith<$Res> {
factory $ProfileSettingsModelCopyWith(ProfileSettingsModel value,
$Res Function(ProfileSettingsModel) then) =
_$ProfileSettingsModelCopyWithImpl<$Res, ProfileSettingsModel>;
@useResult
$Res call(
{@JsonKey(name: "new_updates_notifications")
dynamic newUpdatesNotifications,
@JsonKey(name: "diary_reminder_notifications")
dynamic diaryReminderNotifications,
@JsonKey(name: "is_mood_fillable") bool isMoodFillable,
@JsonKey(name: "is_bedtime_fillable") bool isBedtimeFillable,
@JsonKey(name: "is_public_profile") bool isPublicProfile});
}
/// @nodoc
class _$ProfileSettingsModelCopyWithImpl<$Res,
$Val extends ProfileSettingsModel>
implements $ProfileSettingsModelCopyWith<$Res> {
_$ProfileSettingsModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ProfileSettingsModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? newUpdatesNotifications = freezed,
Object? diaryReminderNotifications = freezed,
Object? isMoodFillable = null,
Object? isBedtimeFillable = null,
Object? isPublicProfile = null,
}) {
return _then(_value.copyWith(
newUpdatesNotifications: freezed == newUpdatesNotifications
? _value.newUpdatesNotifications
: newUpdatesNotifications // ignore: cast_nullable_to_non_nullable
as dynamic,
diaryReminderNotifications: freezed == diaryReminderNotifications
? _value.diaryReminderNotifications
: diaryReminderNotifications // ignore: cast_nullable_to_non_nullable
as dynamic,
isMoodFillable: null == isMoodFillable
? _value.isMoodFillable
: isMoodFillable // ignore: cast_nullable_to_non_nullable
as bool,
isBedtimeFillable: null == isBedtimeFillable
? _value.isBedtimeFillable
: isBedtimeFillable // ignore: cast_nullable_to_non_nullable
as bool,
isPublicProfile: null == isPublicProfile
? _value.isPublicProfile
: isPublicProfile // ignore: cast_nullable_to_non_nullable
as bool,
) as $Val);
}
}
/// @nodoc
abstract class _$$ProfileSettingsModelImplCopyWith<$Res>
implements $ProfileSettingsModelCopyWith<$Res> {
factory _$$ProfileSettingsModelImplCopyWith(_$ProfileSettingsModelImpl value,
$Res Function(_$ProfileSettingsModelImpl) then) =
__$$ProfileSettingsModelImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{@JsonKey(name: "new_updates_notifications")
dynamic newUpdatesNotifications,
@JsonKey(name: "diary_reminder_notifications")
dynamic diaryReminderNotifications,
@JsonKey(name: "is_mood_fillable") bool isMoodFillable,
@JsonKey(name: "is_bedtime_fillable") bool isBedtimeFillable,
@JsonKey(name: "is_public_profile") bool isPublicProfile});
}
/// @nodoc
class __$$ProfileSettingsModelImplCopyWithImpl<$Res>
extends _$ProfileSettingsModelCopyWithImpl<$Res, _$ProfileSettingsModelImpl>
implements _$$ProfileSettingsModelImplCopyWith<$Res> {
__$$ProfileSettingsModelImplCopyWithImpl(_$ProfileSettingsModelImpl _value,
$Res Function(_$ProfileSettingsModelImpl) _then)
: super(_value, _then);
/// Create a copy of ProfileSettingsModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? newUpdatesNotifications = freezed,
Object? diaryReminderNotifications = freezed,
Object? isMoodFillable = null,
Object? isBedtimeFillable = null,
Object? isPublicProfile = null,
}) {
return _then(_$ProfileSettingsModelImpl(
newUpdatesNotifications: freezed == newUpdatesNotifications
? _value.newUpdatesNotifications
: newUpdatesNotifications // ignore: cast_nullable_to_non_nullable
as dynamic,
diaryReminderNotifications: freezed == diaryReminderNotifications
? _value.diaryReminderNotifications
: diaryReminderNotifications // ignore: cast_nullable_to_non_nullable
as dynamic,
isMoodFillable: null == isMoodFillable
? _value.isMoodFillable
: isMoodFillable // ignore: cast_nullable_to_non_nullable
as bool,
isBedtimeFillable: null == isBedtimeFillable
? _value.isBedtimeFillable
: isBedtimeFillable // ignore: cast_nullable_to_non_nullable
as bool,
isPublicProfile: null == isPublicProfile
? _value.isPublicProfile
: isPublicProfile // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// @nodoc
@JsonSerializable()
class _$ProfileSettingsModelImpl implements _ProfileSettingsModel {
const _$ProfileSettingsModelImpl(
{@JsonKey(name: "new_updates_notifications")
required this.newUpdatesNotifications,
@JsonKey(name: "diary_reminder_notifications")
required this.diaryReminderNotifications,
@JsonKey(name: "is_mood_fillable") required this.isMoodFillable,
@JsonKey(name: "is_bedtime_fillable") required this.isBedtimeFillable,
@JsonKey(name: "is_public_profile") required this.isPublicProfile});
factory _$ProfileSettingsModelImpl.fromJson(Map<String, dynamic> json) =>
_$$ProfileSettingsModelImplFromJson(json);
@override
@JsonKey(name: "new_updates_notifications")
final dynamic newUpdatesNotifications;
@override
@JsonKey(name: "diary_reminder_notifications")
final dynamic diaryReminderNotifications;
@override
@JsonKey(name: "is_mood_fillable")
final bool isMoodFillable;
@override
@JsonKey(name: "is_bedtime_fillable")
final bool isBedtimeFillable;
@override
@JsonKey(name: "is_public_profile")
final bool isPublicProfile;
@override
String toString() {
return 'ProfileSettingsModel(newUpdatesNotifications: $newUpdatesNotifications, diaryReminderNotifications: $diaryReminderNotifications, isMoodFillable: $isMoodFillable, isBedtimeFillable: $isBedtimeFillable, isPublicProfile: $isPublicProfile)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ProfileSettingsModelImpl &&
const DeepCollectionEquality().equals(
other.newUpdatesNotifications, newUpdatesNotifications) &&
const DeepCollectionEquality().equals(
other.diaryReminderNotifications, diaryReminderNotifications) &&
(identical(other.isMoodFillable, isMoodFillable) ||
other.isMoodFillable == isMoodFillable) &&
(identical(other.isBedtimeFillable, isBedtimeFillable) ||
other.isBedtimeFillable == isBedtimeFillable) &&
(identical(other.isPublicProfile, isPublicProfile) ||
other.isPublicProfile == isPublicProfile));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(newUpdatesNotifications),
const DeepCollectionEquality().hash(diaryReminderNotifications),
isMoodFillable,
isBedtimeFillable,
isPublicProfile);
/// Create a copy of ProfileSettingsModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ProfileSettingsModelImplCopyWith<_$ProfileSettingsModelImpl>
get copyWith =>
__$$ProfileSettingsModelImplCopyWithImpl<_$ProfileSettingsModelImpl>(
this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$ProfileSettingsModelImplToJson(
this,
);
}
}
abstract class _ProfileSettingsModel implements ProfileSettingsModel {
const factory _ProfileSettingsModel(
{@JsonKey(name: "new_updates_notifications")
required final dynamic newUpdatesNotifications,
@JsonKey(name: "diary_reminder_notifications")
required final dynamic diaryReminderNotifications,
@JsonKey(name: "is_mood_fillable") required final bool isMoodFillable,
@JsonKey(name: "is_bedtime_fillable")
required final bool isBedtimeFillable,
@JsonKey(name: "is_public_profile")
required final bool isPublicProfile}) = _$ProfileSettingsModelImpl;
factory _ProfileSettingsModel.fromJson(Map<String, dynamic> json) =
_$ProfileSettingsModelImpl.fromJson;
@override
@JsonKey(name: "new_updates_notifications")
dynamic get newUpdatesNotifications;
@override
@JsonKey(name: "diary_reminder_notifications")
dynamic get diaryReminderNotifications;
@override
@JsonKey(name: "is_mood_fillable")
bool get isMoodFillable;
@override
@JsonKey(name: "is_bedtime_fillable")
bool get isBedtimeFillable;
@override
@JsonKey(name: "is_public_profile")
bool get isPublicProfile;
/// Create a copy of ProfileSettingsModel
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ProfileSettingsModelImplCopyWith<_$ProfileSettingsModelImpl>
get copyWith => throw _privateConstructorUsedError;
}

View File

@@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'profile_settings_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$ProfileSettingsModelImpl _$$ProfileSettingsModelImplFromJson(
Map<String, dynamic> json) =>
_$ProfileSettingsModelImpl(
newUpdatesNotifications: json['new_updates_notifications'],
diaryReminderNotifications: json['diary_reminder_notifications'],
isMoodFillable: json['is_mood_fillable'] as bool,
isBedtimeFillable: json['is_bedtime_fillable'] as bool,
isPublicProfile: json['is_public_profile'] as bool,
);
Map<String, dynamic> _$$ProfileSettingsModelImplToJson(
_$ProfileSettingsModelImpl instance) =>
<String, dynamic>{
'new_updates_notifications': instance.newUpdatesNotifications,
'diary_reminder_notifications': instance.diaryReminderNotifications,
'is_mood_fillable': instance.isMoodFillable,
'is_bedtime_fillable': instance.isBedtimeFillable,
'is_public_profile': instance.isPublicProfile,
};

View File

@@ -1,6 +1,39 @@
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
import 'package:eatvio_app/features/settings/models/profile_settings_model.dart';
import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_state.dart';
import 'package:eatvio_app/features/settings/repositories/service_repository.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class SettingsCubit extends Cubit {
SettingsCubit() : super(SettingsState());
}
class SettingsCubit extends Cubit<SettingsState> {
final ProfileRepository profileRepository;
final SettingsRepository settingsRepository;
SettingsCubit({
required this.profileRepository,
required this.settingsRepository,
}) : super(SettingsState.loading());
init() async {
try {
emit(SettingsState.loaded(
profileSettings: await settingsRepository.getProfileSettings(),
profileDetails: await profileRepository.getMyProfileDetails(),
));
} catch (e) {
emit(SettingsState.error(errorMessage: e.toString()));
}
}
updateProfileSettings({
required ProfileSettingsModel profileSettingsModel
}) async {
try {
await settingsRepository.updateProfileSettings(
profileSettingsModel: profileSettingsModel,
);
} catch (e) {
print(e);
rethrow;
}
}
}

View File

@@ -1,3 +1,5 @@
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/features/settings/models/profile_settings_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'settings_state.freezed.dart';
@@ -5,8 +7,14 @@ part 'settings_state.freezed.dart';
@freezed
abstract class SettingsState with _$SettingsState {
const factory SettingsState() = _SettingsState;
const factory SettingsState.loading() = SettingsStateLoading;
const factory SettingsState.loaded() = SettingsStateLoaded;
const factory SettingsState.loaded({
required ProfileSettingsModel profileSettings,
required ProfileDetailsModel profileDetails,
}) = SettingsStateLoaded;
const factory SettingsState.error({
required String errorMessage,
}) = SettingsStateError;

View File

@@ -20,7 +20,9 @@ mixin _$SettingsState {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function() loaded,
required TResult Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)
loaded,
required TResult Function(String errorMessage) error,
}) =>
throw _privateConstructorUsedError;
@@ -28,7 +30,9 @@ mixin _$SettingsState {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function()? loaded,
TResult? Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)?
loaded,
TResult? Function(String errorMessage)? error,
}) =>
throw _privateConstructorUsedError;
@@ -36,7 +40,9 @@ mixin _$SettingsState {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function()? loaded,
TResult Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) =>
@@ -132,7 +138,9 @@ class _$SettingsStateImpl implements _SettingsState {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function() loaded,
required TResult Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)
loaded,
required TResult Function(String errorMessage) error,
}) {
return $default();
@@ -143,7 +151,9 @@ class _$SettingsStateImpl implements _SettingsState {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function()? loaded,
TResult? Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
return $default?.call();
@@ -154,7 +164,9 @@ class _$SettingsStateImpl implements _SettingsState {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function()? loaded,
TResult Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {
@@ -250,7 +262,9 @@ class _$SettingsStateLoadingImpl implements SettingsStateLoading {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function() loaded,
required TResult Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)
loaded,
required TResult Function(String errorMessage) error,
}) {
return loading();
@@ -261,7 +275,9 @@ class _$SettingsStateLoadingImpl implements SettingsStateLoading {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function()? loaded,
TResult? Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
return loading?.call();
@@ -272,7 +288,9 @@ class _$SettingsStateLoadingImpl implements SettingsStateLoading {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function()? loaded,
TResult Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {
@@ -329,6 +347,13 @@ abstract class _$$SettingsStateLoadedImplCopyWith<$Res> {
factory _$$SettingsStateLoadedImplCopyWith(_$SettingsStateLoadedImpl value,
$Res Function(_$SettingsStateLoadedImpl) then) =
__$$SettingsStateLoadedImplCopyWithImpl<$Res>;
@useResult
$Res call(
{ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails});
$ProfileSettingsModelCopyWith<$Res> get profileSettings;
$ProfileDetailsModelCopyWith<$Res> get profileDetails;
}
/// @nodoc
@@ -341,37 +366,95 @@ class __$$SettingsStateLoadedImplCopyWithImpl<$Res>
/// Create a copy of SettingsState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? profileSettings = null,
Object? profileDetails = null,
}) {
return _then(_$SettingsStateLoadedImpl(
profileSettings: null == profileSettings
? _value.profileSettings
: profileSettings // ignore: cast_nullable_to_non_nullable
as ProfileSettingsModel,
profileDetails: null == profileDetails
? _value.profileDetails
: profileDetails // ignore: cast_nullable_to_non_nullable
as ProfileDetailsModel,
));
}
/// Create a copy of SettingsState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$ProfileSettingsModelCopyWith<$Res> get profileSettings {
return $ProfileSettingsModelCopyWith<$Res>(_value.profileSettings, (value) {
return _then(_value.copyWith(profileSettings: value));
});
}
/// Create a copy of SettingsState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$ProfileDetailsModelCopyWith<$Res> get profileDetails {
return $ProfileDetailsModelCopyWith<$Res>(_value.profileDetails, (value) {
return _then(_value.copyWith(profileDetails: value));
});
}
}
/// @nodoc
class _$SettingsStateLoadedImpl implements SettingsStateLoaded {
const _$SettingsStateLoadedImpl();
const _$SettingsStateLoadedImpl(
{required this.profileSettings, required this.profileDetails});
@override
final ProfileSettingsModel profileSettings;
@override
final ProfileDetailsModel profileDetails;
@override
String toString() {
return 'SettingsState.loaded()';
return 'SettingsState.loaded(profileSettings: $profileSettings, profileDetails: $profileDetails)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$SettingsStateLoadedImpl);
other is _$SettingsStateLoadedImpl &&
(identical(other.profileSettings, profileSettings) ||
other.profileSettings == profileSettings) &&
(identical(other.profileDetails, profileDetails) ||
other.profileDetails == profileDetails));
}
@override
int get hashCode => runtimeType.hashCode;
int get hashCode => Object.hash(runtimeType, profileSettings, profileDetails);
/// Create a copy of SettingsState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$SettingsStateLoadedImplCopyWith<_$SettingsStateLoadedImpl> get copyWith =>
__$$SettingsStateLoadedImplCopyWithImpl<_$SettingsStateLoadedImpl>(
this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function() loaded,
required TResult Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)
loaded,
required TResult Function(String errorMessage) error,
}) {
return loaded();
return loaded(profileSettings, profileDetails);
}
@override
@@ -379,10 +462,12 @@ class _$SettingsStateLoadedImpl implements SettingsStateLoaded {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function()? loaded,
TResult? Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
return loaded?.call();
return loaded?.call(profileSettings, profileDetails);
}
@override
@@ -390,12 +475,14 @@ class _$SettingsStateLoadedImpl implements SettingsStateLoaded {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function()? loaded,
TResult Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {
if (loaded != null) {
return loaded();
return loaded(profileSettings, profileDetails);
}
return orElse();
}
@@ -439,7 +526,19 @@ class _$SettingsStateLoadedImpl implements SettingsStateLoaded {
}
abstract class SettingsStateLoaded implements SettingsState {
const factory SettingsStateLoaded() = _$SettingsStateLoadedImpl;
const factory SettingsStateLoaded(
{required final ProfileSettingsModel profileSettings,
required final ProfileDetailsModel profileDetails}) =
_$SettingsStateLoadedImpl;
ProfileSettingsModel get profileSettings;
ProfileDetailsModel get profileDetails;
/// Create a copy of SettingsState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$SettingsStateLoadedImplCopyWith<_$SettingsStateLoadedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
@@ -514,7 +613,9 @@ class _$SettingsStateErrorImpl implements SettingsStateError {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function() loaded,
required TResult Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)
loaded,
required TResult Function(String errorMessage) error,
}) {
return error(errorMessage);
@@ -525,7 +626,9 @@ class _$SettingsStateErrorImpl implements SettingsStateError {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function()? loaded,
TResult? Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
return error?.call(errorMessage);
@@ -536,7 +639,9 @@ class _$SettingsStateErrorImpl implements SettingsStateError {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function()? loaded,
TResult Function(ProfileSettingsModel profileSettings,
ProfileDetailsModel profileDetails)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {

View File

@@ -1,4 +1,5 @@
import 'package:eatvio_app/core/utils/date_time_utils.dart';
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:eatvio_app/widgets/custom_text_form_field.dart';
@@ -7,7 +8,12 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class GeneralInfoScreen extends StatefulWidget {
const GeneralInfoScreen({super.key});
final ProfileDetailsModel profileDetailsModel;
const GeneralInfoScreen({
super.key,
required this.profileDetailsModel,
});
@override
State<GeneralInfoScreen> createState() => _GeneralInfoScreenState();
@@ -22,6 +28,9 @@ class _GeneralInfoScreenState extends State<GeneralInfoScreen> {
void initState() {
super.initState();
selectedDate = DateTime.now();
firstNameController.text = widget.profileDetailsModel.firstName;
lastNameController.text = widget.profileDetailsModel.lastName;
selectedDate = DateTime.parse(widget.profileDetailsModel.birthdate);
}
@override
@@ -35,7 +44,7 @@ class _GeneralInfoScreenState extends State<GeneralInfoScreen> {
bottomSheet: _saveButton(),
body: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.only(top: 16, bottom: 80, left: 8, right: 8),
padding: EdgeInsets.all(16) + EdgeInsets.only(bottom: 64),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -145,7 +154,7 @@ class _GeneralInfoScreenState extends State<GeneralInfoScreen> {
borderRadius: BorderRadius.circular(20),
child: Ink(
height: 52,
width: MediaQuery.of(context).size.width - 16,
width: MediaQuery.of(context).size.width - 32,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: appTheme.blueA400,

View File

@@ -1,7 +1,17 @@
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:eatvio_app/widgets/custom_text_form_field.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class OtherInfoScreen extends StatefulWidget {
const OtherInfoScreen({super.key});
final ProfileDetailsModel profileDetailsModel;
const OtherInfoScreen({
super.key,
required this.profileDetailsModel,
});
@override
State<OtherInfoScreen> createState() => _OtherInfoScreenState();
@@ -10,6 +20,107 @@ class OtherInfoScreen extends StatefulWidget {
class _OtherInfoScreenState extends State<OtherInfoScreen> {
@override
Widget build(BuildContext context) {
return Scaffold();
final s = S.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Прочая информаиця'),
),
bottomSheet: _saveButton(),
body: SingleChildScrollView(
padding: EdgeInsets.all(16) + EdgeInsets.only(bottom: 64),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(s.allergies_presence),
SizedBox(height: 4),
CustomTextFormField(
hintText: 'Например: орехи, мёд и т.д.',
autofocus: true,
minLines: 2,
maxLines: 8,
onChanged: (newValue) {},
),
SizedBox(height: 16),
Text(s.do_you_take_pills),
SizedBox(height: 4),
CustomTextFormField(
hintText: s.enter_information,
autofocus: true,
minLines: 2,
maxLines: 8,
onChanged: (newValue) {},
),
SizedBox(height: 16),
Text(s.your_favorite_sports),
SizedBox(height: 4),
CustomTextFormField(
hintText:
"Я занимаюсь плаванием , почти каждый вечер прогулки на свежем воздухе, пару раз в месяц играю в волейбол. Стараюсь не сидеть на месте!",
autofocus: true,
maxLines: 8,
onChanged: (newValue) {},
),
SizedBox(height: 16),
Text(s.favorite_foods),
SizedBox(height: 4),
CustomTextFormField(
hintText: s.enter_information,
maxLines: 7,
minLines: 2,
onChanged: (newValue) {},
),
SizedBox(height: 16),
Text(s.unfavorite_foods),
SizedBox(height: 4),
CustomTextFormField(
hintText: s.enter_information,
maxLines: 7,
minLines: 2,
onChanged: (newValue) {},
),
SizedBox(height: 16),
Text(
'Дополнительная информация',
maxLines: 2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.start,
),
SizedBox(height: 4),
CustomTextFormField(
hintText: "У меня крепкое здоровье, но последнее время часто утомляюсь, однако, это мне не мешает радоваться жизни",
maxLines: 8,
onChanged: (newValue) {},
),
],
),
),
);
}
}
_saveButton() {
return InkWell(
onTap: () => GoRouter.of(context).pop(),
borderRadius: BorderRadius.circular(20),
child: Ink(
height: 52,
width: MediaQuery.of(context).size.width - 16,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: appTheme.blueA400,
),
child: Center(
child: Text(
'Сохранить',
style: TextStyle(
color: Colors.white,
height: 1,
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
),
),
);
}
}

View File

@@ -1,7 +1,15 @@
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class PhysicalActivityScreen extends StatefulWidget {
const PhysicalActivityScreen({super.key});
final ProfileDetailsModel profileDetailsModel;
const PhysicalActivityScreen({
super.key,
required this.profileDetailsModel,
});
@override
State<PhysicalActivityScreen> createState() => _PhysicalActivityScreenState();
@@ -18,10 +26,14 @@ class _PhysicalActivityScreenState extends State<PhysicalActivityScreen> {
appBar: AppBar(
title: Text('Физическая нагрузка'),
),
bottomSheet: _saveButton(),
body: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.only(top: 16, bottom: 80, left: 8, right: 16),
child: Column(
children: [
RadioListTile<PhysicalActivity>(
contentPadding: EdgeInsets.zero,
title: const Text('1,2 — минимальный (сидячая работа, отсутствие физических нагрузок);'),
value: PhysicalActivity.minimum,
groupValue: _physicalActivity,
@@ -32,6 +44,7 @@ class _PhysicalActivityScreenState extends State<PhysicalActivityScreen> {
},
),
RadioListTile<PhysicalActivity>(
contentPadding: EdgeInsets.zero,
title: const Text('1,375 — низкий (тренировки не менее 20 мин 1–3 раза в неделю);'),
value: PhysicalActivity.low,
groupValue: _physicalActivity,
@@ -42,6 +55,7 @@ class _PhysicalActivityScreenState extends State<PhysicalActivityScreen> {
},
),
RadioListTile<PhysicalActivity>(
contentPadding: EdgeInsets.zero,
title: const Text('1,55 — умеренный (тренировки 30–60 мин 3–4 раза в неделю);'),
value: PhysicalActivity.medium,
groupValue: _physicalActivity,
@@ -52,6 +66,7 @@ class _PhysicalActivityScreenState extends State<PhysicalActivityScreen> {
},
),
RadioListTile<PhysicalActivity>(
contentPadding: EdgeInsets.zero,
title: const Text('1,7 — высокий (тренировки 30–60 мин 5–7 раза в неделю; тяжёлая физическая работа);'),
value: PhysicalActivity.high,
groupValue: _physicalActivity,
@@ -62,6 +77,7 @@ class _PhysicalActivityScreenState extends State<PhysicalActivityScreen> {
},
),
RadioListTile<PhysicalActivity>(
contentPadding: EdgeInsets.zero,
title: const Text('1,9 — экстремальный (несколько интенсивных тренировок в день'),
value: PhysicalActivity.extreme,
groupValue: _physicalActivity,
@@ -72,6 +88,7 @@ class _PhysicalActivityScreenState extends State<PhysicalActivityScreen> {
},
),
RadioListTile<PhysicalActivity>(
contentPadding: EdgeInsets.zero,
title: const Text('1,9 6–7 раз в неделю; очень трудоёмкая работа).'),
value: PhysicalActivity.hardWork,
groupValue: _physicalActivity,
@@ -86,4 +103,30 @@ class _PhysicalActivityScreenState extends State<PhysicalActivityScreen> {
),
);
}
_saveButton() {
return InkWell(
onTap: () => GoRouter.of(context).pop(),
borderRadius: BorderRadius.circular(20),
child: Ink(
height: 52,
width: MediaQuery.of(context).size.width - 32,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: appTheme.blueA400,
),
child: Center(
child: Text(
'Сохранить',
style: TextStyle(
color: Colors.white,
height: 1,
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
),
),
);
}
}

View File

@@ -1,3 +1,4 @@
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:eatvio_app/widgets/custom_text_form_field.dart';
@@ -6,7 +7,12 @@ import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
class PhysicalFormScreen extends StatefulWidget {
const PhysicalFormScreen({super.key});
final ProfileDetailsModel profileDetailsModel;
const PhysicalFormScreen({
super.key,
required this.profileDetailsModel,
});
@override
State<PhysicalFormScreen> createState() => _PhysicalFormScreenState();
@@ -29,7 +35,7 @@ class _PhysicalFormScreenState extends State<PhysicalFormScreen> {
bottomSheet: _saveButton(),
body: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: EdgeInsets.symmetric(vertical: 16, horizontal: 8),
padding: EdgeInsets.all(16) + EdgeInsets.only(bottom: 64),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -69,7 +75,7 @@ class _PhysicalFormScreenState extends State<PhysicalFormScreen> {
borderRadius: BorderRadius.circular(20),
child: Ink(
height: 52,
width: MediaQuery.of(context).size.width - 16,
width: MediaQuery.of(context).size.width - 32,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: appTheme.blueA400,

View File

@@ -1,15 +1,20 @@
import 'package:eatvio_app/core/utils/image_constant.dart';
import 'package:eatvio_app/data/models/selectionPopupModel/selection_popup_model.dart';
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:eatvio_app/widgets/custom_drop_down.dart';
import 'package:eatvio_app/widgets/custom_image_view.dart';
import 'package:eatvio_app/widgets/custom_text_form_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
class PressureScreen extends StatefulWidget {
const PressureScreen({super.key});
final ProfileDetailsModel profileDetailsModel;
const PressureScreen({
super.key,
required this.profileDetailsModel,
});
@override
State<PressureScreen> createState() => _PressureScreenState();
@@ -20,6 +25,16 @@ class _PressureScreenState extends State<PressureScreen> {
final chestCircumferenceController = TextEditingController();
final waistCircumferenceController = TextEditingController();
final hipCircumferenceController = TextEditingController();
final List<SelectionPopupModel> selectionPopupList = [
SelectionPopupModel(
id: 1,
title: "Да",
),
SelectionPopupModel(
id: 0,
title: "Нет",
),
];
@override
Widget build(BuildContext context) {
@@ -27,12 +42,12 @@ class _PressureScreenState extends State<PressureScreen> {
return Scaffold(
appBar: AppBar(
title: Text('Физическая форма'),
title: Text('Давление'),
),
bottomSheet: _saveButton(),
body: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: EdgeInsets.symmetric(vertical: 16, horizontal: 8),
padding: EdgeInsets.all(16) + EdgeInsets.only(bottom: 64),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -55,17 +70,8 @@ class _PressureScreenState extends State<PressureScreen> {
Text(s.do_you_have_hypotension_tendency),
SizedBox(height: 4),
CustomDropDown(
icon: Container(
margin: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
),
child: CustomImageView(
imagePath: ImageConstant.imgFavorite,
height: 16,
width: 16,
),
),
items: selectionPopupList,
value: selectionPopupList[0],
hintText: "Не выбрано",
onChanged: (newPopup) {
setState(() {});
@@ -75,17 +81,8 @@ class _PressureScreenState extends State<PressureScreen> {
Text(s.do_you_have_hypertension_tendency),
SizedBox(height: 4),
CustomDropDown(
icon: Container(
margin: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
),
child: CustomImageView(
imagePath: ImageConstant.imgFavorite,
height: 16,
width: 16,
),
),
items: selectionPopupList,
value: selectionPopupList[0],
hintText: "Не выбрано",
onChanged: (newPopup) {
setState(() {});
@@ -103,7 +100,7 @@ class _PressureScreenState extends State<PressureScreen> {
borderRadius: BorderRadius.circular(20),
child: Ink(
height: 52,
width: MediaQuery.of(context).size.width - 16,
width: MediaQuery.of(context).size.width - 32,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: appTheme.blueA400,

View File

@@ -1,7 +1,11 @@
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart';
import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_state.dart';
import 'package:eatvio_app/locator_service.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -13,32 +17,59 @@ class SettingsScreen extends StatefulWidget {
}
class _SettingsScreenState extends State<SettingsScreen> {
bool updatesNotificationsSwitchState = true;
bool fillDiaryNotificationsSwitchState = true;
final SettingsCubit settingsCubit = sl<SettingsCubit>()..init();
late bool updatesNotificationsSwitchState;
late bool fillDiaryNotificationsSwitchState;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Настройки'),
),
body: SingleChildScrollView(
padding: EdgeInsets.symmetric(vertical: 16),
physics: const BouncingScrollPhysics(),
child: Column(
children: [
_additionalInfo(),
const SizedBox(height: 12),
_notifications(),
const SizedBox(height: 12),
_aboutEatvio(),
const SizedBox(height: 12),
_becomeConsultantButton(),
const SizedBox(height: 8),
_deleteAccountButton(),
],
),
),
return BlocConsumer<SettingsCubit, SettingsState>(
bloc: settingsCubit,
listener: (BuildContext context, SettingsState state) {
if (state is SettingsStateLoaded) {
updatesNotificationsSwitchState = state.profileSettings.newUpdatesNotifications == 1 ? true : false;
fillDiaryNotificationsSwitchState = state.profileSettings.diaryReminderNotifications == 1 ? true : false;
}
},
builder: (BuildContext context, SettingsState state) {
if (state is SettingsStateLoaded) {
return Scaffold(
appBar: AppBar(
title: Text('Настройки'),
),
body: SingleChildScrollView(
padding: EdgeInsets.symmetric(vertical: 16),
physics: const BouncingScrollPhysics(),
child: Column(
children: [
_additionalInfo(),
const SizedBox(height: 12),
_notifications(),
const SizedBox(height: 12),
_aboutEatvio(),
const SizedBox(height: 12),
_becomeConsultantButton(),
const SizedBox(height: 8),
_deleteAccountButton(),
],
),
),
);
}
if (state is SettingsStateError) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(16),
child: Center(child: Text(state.errorMessage)),
),
);
}
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
},
);
}
@@ -59,27 +90,42 @@ class _SettingsScreenState extends State<SettingsScreen> {
),
),
_tile(
onTap: () => GoRouter.of(context).pushNamed('generalInfoScreen'),
onTap: () => GoRouter.of(context).pushNamed(
'generalInfoScreen',
extra: (settingsCubit.state as SettingsStateLoaded).profileDetails,
),
title: 'Общая информация',
),
_divider(context),
_tile(
onTap: () => GoRouter.of(context).pushNamed('physicalFormScreen'),
onTap: () => GoRouter.of(context).pushNamed(
'physicalFormScreen',
extra: (settingsCubit.state as SettingsStateLoaded).profileDetails,
),
title: 'Физическая форма',
),
_divider(context),
_tile(
onTap: () => GoRouter.of(context).pushNamed('pressureScreen'),
onTap: () => GoRouter.of(context).pushNamed(
'pressureScreen',
extra: (settingsCubit.state as SettingsStateLoaded).profileDetails,
),
title: 'Давление',
),
_divider(context),
_tile(
onTap: () => GoRouter.of(context).pushNamed('otherInfoScreen'),
onTap: () => GoRouter.of(context).pushNamed(
'otherInfoScreen',
extra: (settingsCubit.state as SettingsStateLoaded).profileDetails,
),
title: 'Прочая информация',
),
_divider(context),
_tile(
onTap: () => GoRouter.of(context).pushNamed('physicalActivityScreen'),
onTap: () => GoRouter.of(context).pushNamed(
'physicalActivityScreen',
extra: (settingsCubit.state as SettingsStateLoaded).profileDetails,
),
title: 'Физическая нагрузка',
),
],
@@ -106,6 +152,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
setState(() {
updatesNotificationsSwitchState = !updatesNotificationsSwitchState;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: (settingsCubit.state as SettingsStateLoaded).profileSettings.copyWith(
newUpdatesNotifications: updatesNotificationsSwitchState,
),
);
},
title: 'Уведомление о новых обновлениях',
trailing: CupertinoSwitch(
@@ -115,6 +166,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
setState(() {
updatesNotificationsSwitchState = newValue;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: (settingsCubit.state as SettingsStateLoaded).profileSettings.copyWith(
newUpdatesNotifications: updatesNotificationsSwitchState,
),
);
},
),
),
@@ -124,6 +180,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
setState(() {
fillDiaryNotificationsSwitchState = !fillDiaryNotificationsSwitchState;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: (settingsCubit.state as SettingsStateLoaded).profileSettings.copyWith(
diaryReminderNotifications: fillDiaryNotificationsSwitchState,
),
);
},
title: 'Напоминание о заполнении дневника',
trailing: CupertinoSwitch(
@@ -133,6 +194,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
setState(() {
fillDiaryNotificationsSwitchState = newValue;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: (settingsCubit.state as SettingsStateLoaded).profileSettings.copyWith(
diaryReminderNotifications: fillDiaryNotificationsSwitchState,
),
);
},
),
),

View File

@@ -0,0 +1,39 @@
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/features/settings/models/profile_settings_model.dart';
import 'package:eatvio_app/features/settings/services/settings_service.dart';
class SettingsRepository {
final SettingsService settingsService;
const SettingsRepository({required this.settingsService});
Future<ProfileSettingsModel> getProfileSettings() async {
try {
return await settingsService.getProfileSettings();
} catch (e) {
rethrow;
}
}
Future<ProfileSettingsModel> updateProfileSettings({
required ProfileSettingsModel profileSettingsModel,
}) async {
try {
return await settingsService.updateProfileSettings(
data: profileSettingsModel.toJson(),
);
} catch (e) {
rethrow;
}
}
Future<ProfileDetailsModel> updateProfileDetails({
required ProfileDetailsModel profileDetailsModel,
}) async {
try {
return await settingsService.updateProfileDetails(profileDetailsModel: profileDetailsModel);
} catch (e) {
rethrow;
}
}
}

View File

@@ -0,0 +1,24 @@
import 'package:dio/dio.dart';
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/features/settings/models/profile_settings_model.dart';
import 'package:retrofit/retrofit.dart';
part 'settings_service.g.dart';
@RestApi()
abstract class SettingsService {
factory SettingsService(Dio dio, {String baseUrl}) = _SettingsService;
@GET('/api/profile/settings')
Future<ProfileSettingsModel> getProfileSettings();
@POST('/api/profile/settings/update')
Future<ProfileSettingsModel> updateProfileSettings({
@Body() required Map<String, dynamic> data,
});
@POST('/api/profile/update')
Future<ProfileDetailsModel> updateProfileDetails({
@MultiPart() required ProfileDetailsModel profileDetailsModel,
});
}

View File

@@ -0,0 +1,155 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'settings_service.dart';
// **************************************************************************
// RetrofitGenerator
// **************************************************************************
// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element
class _SettingsService implements SettingsService {
_SettingsService(
this._dio, {
this.baseUrl,
this.errorLogger,
});
final Dio _dio;
String? baseUrl;
final ParseErrorLogger? errorLogger;
@override
Future<ProfileSettingsModel> getProfileSettings() async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ProfileSettingsModel>(Options(
method: 'GET',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/api/profile/settings',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(
_dio.options.baseUrl,
baseUrl,
)));
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
late ProfileSettingsModel _value;
try {
_value = ProfileSettingsModel.fromJson(_result.data!);
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
rethrow;
}
return _value;
}
@override
Future<ProfileSettingsModel> updateProfileSettings(
{required Map<String, dynamic> data}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(data);
final _options = _setStreamType<ProfileSettingsModel>(Options(
method: 'POST',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/api/profile/settings/update',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(
_dio.options.baseUrl,
baseUrl,
)));
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
late ProfileSettingsModel _value;
try {
_value = ProfileSettingsModel.fromJson(_result.data!);
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
rethrow;
}
return _value;
}
@override
Future<ProfileDetailsModel> updateProfileDetails(
{required ProfileDetailsModel profileDetailsModel}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ProfileDetailsModel>(Options(
method: 'POST',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/api/profile/update',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(
_dio.options.baseUrl,
baseUrl,
)));
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
late ProfileDetailsModel _value;
try {
_value = ProfileDetailsModel.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 ||
requestOptions.responseType == ResponseType.stream)) {
if (T == String) {
requestOptions.responseType = ResponseType.plain;
} else {
requestOptions.responseType = ResponseType.json;
}
}
return requestOptions;
}
String _combineBaseUrls(
String dioBaseUrl,
String? baseUrl,
) {
if (baseUrl == null || baseUrl.trim().isEmpty) {
return dioBaseUrl;
}
final url = Uri.parse(baseUrl);
if (url.isAbsolute) {
return url.toString();
}
return Uri.parse(dioBaseUrl).resolveUri(url).toString();
}
}

View File

@@ -32,6 +32,9 @@ import 'package:eatvio_app/features/recipes/services/recipe_service.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.dart';
import 'package:eatvio_app/features/registration/services/registration_service.dart';
import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart';
import 'package:eatvio_app/features/settings/repositories/service_repository.dart';
import 'package:eatvio_app/features/settings/services/settings_service.dart';
import 'package:get_it/get_it.dart';
final sl = GetIt.instance;
@@ -56,6 +59,7 @@ Future<void> init() async {
sl.registerFactory<CommentsCubit>(() => CommentsCubit(feedRepository: sl()));
sl.registerFactory<ChatSelectCubit>(() => ChatSelectCubit(chatRepository: sl()));
sl.registerFactory<PlansCubit>(() => PlansCubit(plansRepository: sl()));
sl.registerFactory<SettingsCubit>(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl()));
// Repository
sl.registerLazySingleton<ChatRepository>(() => ChatRepository(chatService: sl()));
@@ -66,6 +70,7 @@ Future<void> init() async {
sl.registerLazySingleton<ProfileRepository>(() => ProfileRepository(profileService: sl()));
sl.registerLazySingleton<RecipeRepository>(() => RecipeRepository(recipeService: sl()));
sl.registerLazySingleton<PlansRepository>(() => PlansRepository(plansService: sl()));
sl.registerLazySingleton<SettingsRepository>(() => SettingsRepository(settingsService: sl()));
// Services
sl.registerLazySingleton<ChatService>(() => ChatService(sl()));
@@ -76,6 +81,7 @@ Future<void> init() async {
sl.registerLazySingleton<ProfileService>(() => ProfileService(sl()));
sl.registerLazySingleton<RecipeService>(() => RecipeService(sl()));
sl.registerLazySingleton<PlansService>(() => PlansService(sl()));
sl.registerLazySingleton<SettingsService>(() => SettingsService(sl()));
// External
sl.registerLazySingleton(

View File

@@ -62,11 +62,12 @@ class CustomDropDown extends StatelessWidget {
icon: Icon(Icons.keyboard_arrow_down_rounded),
autofocus: autofocus!,
value: value,
isDense: true,
isExpanded: true,
style: textStyle ??
TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontWeight: FontWeight.w400,
),
items: items?.map((SelectionPopupModel item) {
return DropdownMenuItem<SelectionPopupModel>(
@@ -76,7 +77,7 @@ class CustomDropDown extends StatelessWidget {
style: hintStyle ??
TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontWeight: FontWeight.w400,
color: Colors.black,
),
),
@@ -98,29 +99,29 @@ class CustomDropDown extends StatelessWidget {
hintStyle: hintStyle ??
TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontWeight: FontWeight.w400,
color: Colors.grey.shade400,
height: 1,
),
prefixIcon: prefix,
prefixIconConstraints: prefixConstraints,
suffixIcon: suffix,
suffixIconConstraints: suffixConstraints,
isDense: true,
suffixIconConstraints: suffixConstraints,
contentPadding: EdgeInsets.symmetric(vertical: 16, horizontal: 12),
fillColor: fillColor ?? Theme.of(context).colorScheme.onPrimary,
fillColor: Color(0xFFF6F6F6),
filled: filled,
border: OutlineInputBorder(
borderRadius: const BorderRadius.all(Radius.circular(20)),
borderSide: BorderSide(color: Colors.grey, width: 0.2),
borderSide: BorderSide.none,
),
enabledBorder: OutlineInputBorder(
borderRadius: const BorderRadius.all(Radius.circular(20)),
borderSide: BorderSide(color: Colors.grey, width: 0.2),
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderRadius: const BorderRadius.all(Radius.circular(20)),
borderSide: BorderSide(color: Colors.grey, width: 0.2),
borderSide: BorderSide.none,
),
);
}