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

@@ -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,
),
);
},
),
),