Files
eatvio_app/lib/features/settings/presentation/pages/settings_screen.dart
2025-06-04 15:26:34 +03:00

502 lines
17 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
import 'package:eatvio_app/core/widgets/loader.dart';
import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart';
import 'package:eatvio_app/features/settings/entities/settings_entity.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/core/locator_service.dart';
import 'package:eatvio_app/core/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';
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
final SettingsCubit settingsCubit = sl<SettingsCubit>()..init();
late bool updatesNotificationsSwitchState;
late bool fillDiaryNotificationsSwitchState;
late bool bedTimeSwitchState;
late bool moodSwitchState;
@override
Widget build(BuildContext context) {
return BlocProvider<SettingsCubit>(
create: (BuildContext context) => settingsCubit,
child: 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;
bedTimeSwitchState = state.profileSettings.isBedtimeFillable;
moodSwitchState = state.profileSettings.isMoodFillable;
}
},
builder: (BuildContext context, SettingsState state) {
if (state is SettingsStateLoaded) {
return Scaffold(
appBar: AppBar(
title: const Text('Настройки'),
),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(vertical: 16),
physics: const BouncingScrollPhysics(),
child: Column(
children: [
_additionalInfo(state),
const SizedBox(height: 12),
_notifications(state),
const SizedBox(height: 12),
_aboutEatvio(state),
const SizedBox(height: 12),
_becomeConsultantButton(state),
_deleteAccountButton(state),
],
),
),
),
);
}
if (state is SettingsStateError) {
return Scaffold(
appBar: AppBar(
title: const Text('Настройки'),
),
body: DataErrorWidget(onReload: () => settingsCubit.init()),
);
}
return Scaffold(
appBar: AppBar(
title: const Text('Настройки'),
),
body: const Loader(),
);
},
),
);
}
_additionalInfo(SettingsStateLoaded state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text(
'Дополнительаная информация',
style: TextStyle(
fontSize: 16,
height: 1,
color: Colors.grey,
fontFamily: 'Mulish',
),
),
),
_tile(
onTap: () => GoRouter.of(context).pushNamed(
'generalInfoScreen',
extra: SettingsEntity(
profileSettingsModel: state.profileSettings,
profileDetailsModel: state.profileDetails,
settingsCubit: settingsCubit,
),
),
title: 'Общая информация',
),
_divider(context),
_tile(
onTap: () => GoRouter.of(context).pushNamed(
'physicalFormScreen',
extra: SettingsEntity(
profileSettingsModel: state.profileSettings,
profileDetailsModel: state.profileDetails,
settingsCubit: settingsCubit,
),
),
title: 'Физическая форма',
),
_divider(context),
_tile(
onTap: () => GoRouter.of(context).pushNamed(
'pressureScreen',
extra: SettingsEntity(
profileSettingsModel: state.profileSettings,
profileDetailsModel: state.profileDetails,
settingsCubit: settingsCubit,
),
),
title: 'Давление',
),
_divider(context),
_tile(
onTap: () => GoRouter.of(context).pushNamed(
'otherInfoScreen',
extra: SettingsEntity(
profileSettingsModel: state.profileSettings,
profileDetailsModel: state.profileDetails,
settingsCubit: settingsCubit,
),
),
title: 'Прочая информация',
),
_divider(context),
_tile(
onTap: () => GoRouter.of(context).pushNamed(
'physicalActivityScreen',
extra: SettingsEntity(
profileSettingsModel: state.profileSettings,
profileDetailsModel: state.profileDetails,
settingsCubit: settingsCubit,
),
),
title: 'Физическая нагрузка',
),
_divider(context),
_tile(
onTap: () => GoRouter.of(context).pushNamed(
'changePasswordScreen',
extra: SettingsEntity(
profileSettingsModel: state.profileSettings,
profileDetailsModel: state.profileDetails,
settingsCubit: settingsCubit,
),
),
title: 'Сменить пароль',
),
_divider(context),
_tile(
onTap: () => GoRouter.of(context).pushNamed(
'changeEmailScreen',
extra: SettingsEntity(
profileSettingsModel: state.profileSettings,
profileDetailsModel: state.profileDetails,
settingsCubit: settingsCubit,
),
),
title: 'Сменить Email',
),
],
);
}
_notifications(SettingsStateLoaded state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text(
'Уведомления',
style: TextStyle(
fontSize: 16,
height: 1,
color: Colors.grey,
),
),
),
_tile(
padding: const EdgeInsets.symmetric(horizontal: 16),
onTap: () {
setState(() {
updatesNotificationsSwitchState = !updatesNotificationsSwitchState;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: state.profileSettings.copyWith(
newUpdatesNotifications: updatesNotificationsSwitchState,
),
);
},
title: 'Уведомление о новых обновлениях',
trailing: CupertinoSwitch(
value: updatesNotificationsSwitchState,
activeTrackColor: appTheme.blueA400,
onChanged: (newValue) {
setState(() {
updatesNotificationsSwitchState = newValue;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: state.profileSettings.copyWith(
newUpdatesNotifications: updatesNotificationsSwitchState,
),
);
},
),
),
_divider(context),
_tile(
padding: const EdgeInsets.symmetric(horizontal: 16),
onTap: () {
setState(() {
fillDiaryNotificationsSwitchState = !fillDiaryNotificationsSwitchState;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: state.profileSettings.copyWith(
diaryReminderNotifications: fillDiaryNotificationsSwitchState,
),
);
},
title: 'Напоминание о заполнении дневника',
trailing: CupertinoSwitch(
value: fillDiaryNotificationsSwitchState,
activeTrackColor: appTheme.blueA400,
onChanged: (newValue) {
setState(() {
fillDiaryNotificationsSwitchState = newValue;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: state.profileSettings.copyWith(
diaryReminderNotifications: fillDiaryNotificationsSwitchState,
),
);
},
),
),
_divider(context),
_tile(
padding: const EdgeInsets.symmetric(horizontal: 16),
onTap: () {
setState(() {
moodSwitchState = !moodSwitchState;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: state.profileSettings.copyWith(
isMoodFillable: moodSwitchState,
),
);
},
title: 'Указывать “настроение” в заполнение дневника',
trailing: CupertinoSwitch(
value: moodSwitchState,
activeTrackColor: appTheme.blueA400,
onChanged: (newValue) {
setState(() {
moodSwitchState = newValue;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: state.profileSettings.copyWith(
isMoodFillable: moodSwitchState,
),
);
},
),
),
_divider(context),
_tile(
padding: const EdgeInsets.symmetric(horizontal: 16),
onTap: () {
setState(() {
bedTimeSwitchState = !bedTimeSwitchState;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: state.profileSettings.copyWith(
isBedtimeFillable: bedTimeSwitchState,
),
);
},
title: 'Указывать “отход ко сну” в заполнение дневника',
trailing: CupertinoSwitch(
value: bedTimeSwitchState,
activeTrackColor: appTheme.blueA400,
onChanged: (newValue) {
setState(() {
bedTimeSwitchState = newValue;
});
settingsCubit.updateProfileSettings(
profileSettingsModel: state.profileSettings.copyWith(
isBedtimeFillable: bedTimeSwitchState,
),
);
},
),
),
],
);
}
_aboutEatvio(SettingsStateLoaded state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text(
'О Eatvio',
style: TextStyle(
fontSize: 16,
height: 1,
color: Colors.grey,
),
),
),
_tile(
title: 'О компании',
onTap: () async => await launchUrl(Uri.parse('$baseUrl/ru/company-details')),
),
_divider(context),
_tile(
title: 'Пользовательское соглашение',
onTap: () async => await launchUrl(Uri.parse('$baseUrl/oferta_bs.pdf')),
),
],
);
}
_becomeConsultantButton(SettingsStateLoaded state) {
if (state.consultationRequestModel == null) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(bottom: 8),
child: InkWell(
onTap: () => GoRouter.of(context).pushNamed('becomeConsultantScreen'),
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: const Center(
child: Text(
'Стать консультантом',
style: TextStyle(
color: Colors.white,
height: 1,
fontSize: 18,
),
),
),
),
),
);
} else {
if (state.consultationRequestModel!.educationModel.requestState == ModerationStatus.created) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(bottom: 8),
child: Ink(
height: 52,
width: MediaQuery.of(context).size.width - 16,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: const Color(0xFFEAEAEA),
),
child: const Center(
child: Text(
'Данные на проверке',
style: TextStyle(
color: Colors.black,
height: 1,
fontSize: 18,
),
),
),
),
);
} else if (state.consultationRequestModel!.educationModel.requestState == ModerationStatus.canceled) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(bottom: 8),
child: InkWell(
onTap: () => GoRouter.of(context).pushNamed('stepperBecomeConsultantScreen', extra: state.profile.slug),
borderRadius: BorderRadius.circular(20),
child: Ink(
height: 52,
width: MediaQuery.of(context).size.width - 16,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: const Color(0x33FFCC00),
),
child: const Center(
child: Text(
'Заявка обработана',
style: TextStyle(
color: Colors.black,
height: 1,
fontSize: 18,
),
),
),
),
),
);
}
}
return const SizedBox.shrink();
}
_deleteAccountButton(SettingsStateLoaded state) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: InkWell(
onTap: () {},
borderRadius: BorderRadius.circular(20),
child: Ink(
height: 52,
width: MediaQuery.of(context).size.width - 16,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: const Color(0xFFEAEAEA),
),
child: const Center(
child: Text(
'Удалить аккаунт',
style: TextStyle(
color: Colors.black,
height: 1,
fontSize: 18,
),
),
),
),
),
);
}
_tile({
required String title,
required Function() onTap,
Widget? trailing,
EdgeInsets? padding,
}) {
return ListTile(
contentPadding: padding,
onTap: onTap,
title: Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
height: 1,
),
),
trailing: trailing ??
const Icon(
Icons.arrow_forward_ios_rounded,
size: 12,
color: Colors.black38,
),
);
}
_divider(BuildContext context) {
return Center(
child: Container(
height: 0.4,
width: MediaQuery.of(context).size.width - 32,
decoration: BoxDecoration(
color: Colors.black26,
borderRadius: BorderRadius.circular(16),
),
),
);
}
}