forked from eatvio/eatvio_app
feat: add settings
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
}) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user