Files
eatvio_app/lib/widgets/custom_expandable_list.dart

421 lines
15 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:flutter/material.dart';
import 'package:eatvio_app/core/app_export.dart';
import 'package:eatvio_app/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart';
import 'package:eatvio_app/widgets/custom_hyper_switch.dart';
import 'package:eatvio_app/widgets/custom_hypo_switch.dart';
import 'package:intl/intl.dart';
import 'package:eatvio_app/widgets/next_step_button.dart';
import 'dart:convert';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:hive/hive.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
class ExpandableList extends StatefulWidget {
final String title;
ExpandableList(this.title);
@override
_ExpandableListState createState() => _ExpandableListState();
}
class _ExpandableListState extends State<ExpandableList> {
bool isExpanded = false;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
GestureDetector(
onTap: toggleExpand(),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.title,
style: TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.bold),
),
Icon(isExpanded ? Icons.arrow_drop_up : Icons.arrow_drop_down),
],
),
),
if (isExpanded)
Padding(
padding: const EdgeInsets.only(left: 16.0),
child: BlocBuilder<MyProfileBloc, MyProfileState>(
builder: (context, state) {
if (state is MyProfileInitialState) {
// Это начальное состояние, данные ещё не загружены.
return CircularProgressIndicator(
color: Colors.white,
backgroundColor: Colors.white,
);
} else if (state is MyProfileLoadedState) {
// Данные загружены, можно строить форму.
return _buildForm(context, state);
} else if (state is MyProfileErrorState) {
// Произошла ошибка при загрузке данных.
return Center(child: Text(state.errorMessage));
} else {
// Другие состояния, если они есть.
return Container(); // Пустой контейнер для необработанных состояний.
}
}),
),
Divider(),
],
);
}
toggleExpand() {
return () {
setState(() {
isExpanded = !isExpanded;
});
};
}
_buildForm(BuildContext context, MyProfileLoadedState state) {
List<String> cities = [
'Москва',
'Санкт-Петербург',
'Новосибирск',
'Екатеринбург',
'Нижний Новгород',
'Казань',
'Челябинск',
'Омск',
'Самара',
'Ростов-на-Дону',
'Уфа',
'Красноярск',
'Воронеж',
'Пермь',
'Волгоград',
'Краснодар',
'Саратов',
'Тюмень',
'Тольятти',
'Ижевск',
'Барнаул',
'Ульяновск',
'Иркутск',
'Хабаровск',
'Ярославль',
'Владивосток',
'Махачкала',
'Томск',
'Оренбург',
'Кемерово',
];
List<String> countries = [
'Россия',
];
List<String> activities = [
'сидячий',
'низкий (1-3 тренировки в неделю по 20 мин)',
'умеренный (3-4 тренировки в неделю по 30-60 мин)',
'высокий (5-7 тренировок по 30-60 мин)',
'экстремальный (несколько интенсивных тренировок в день)'
];
final digitsOnly = FilteringTextInputFormatter.digitsOnly;
return Column(children: [
TextField(
controller: state.firstNameFormController,
decoration: InputDecoration(labelText: 'first_name'.tr),
),
TextField(
controller: state.lastNameFormController,
decoration: InputDecoration(labelText: 'last_name'.tr),
),
TextField(
decoration: InputDecoration(labelText: 'date_of_birth'.tr),
controller: state.dateFormController,
onTap: inputTime(context, state)),
DropdownButtonFormField<String>(
value: state.selectedCountry,
hint: Text(state.selectedCountry ?? "Не выбрано"),
onChanged: setCountry(state),
items: countries.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
decoration: InputDecoration(labelText: 'country'.tr),
),
DropdownButtonFormField<String>(
hint: Text(state.selectedCity ?? "Не выбрано"),
value: state.selectedCity,
onChanged: setCity(state),
items: cities.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
decoration: InputDecoration(labelText: 'city_of_living'.tr),
),
TextField(
controller: state.weightFormController,
decoration: InputDecoration(labelText: 'weight_measurements'.tr),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[digitsOnly]),
TextField(
controller: state.heightFormController,
decoration: InputDecoration(labelText: 'height_measurements'.tr),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[digitsOnly]),
TextField(
controller: state.chestCircumferenceFormController,
decoration: InputDecoration(labelText: 'chest_circumference'.tr),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[digitsOnly]),
TextField(
controller: state.waistCircumferenceFormController,
decoration: InputDecoration(labelText: 'waist_circumference'.tr),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[digitsOnly]),
TextField(
controller: state.hipCircumferenceFormController,
decoration: InputDecoration(labelText: 'hip_circumference'.tr),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[digitsOnly]),
TextField(
controller: state.upPressureFormController,
decoration: InputDecoration(labelText: 'up_pressure'.tr),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[digitsOnly]),
TextField(
controller: state.downPressureFormController,
decoration: InputDecoration(labelText: 'down_pressure'.tr),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[digitsOnly]),
TextField(
controller: state.allergiesFormController,
decoration: InputDecoration(labelText: 'allergies_presence'.tr),
maxLines: null,
),
TextField(
controller: state.pillsFormController,
decoration: InputDecoration(labelText: 'do_you_take_pills'.tr),
maxLines: null,
),
TextField(
controller: state.sportsFormController,
decoration: InputDecoration(labelText: 'your_favorite_sports'.tr),
maxLines: null,
),
TextField(
controller: state.favoriteFormController,
decoration: InputDecoration(labelText: 'favorite_foods'.tr),
maxLines: null,
),
TextField(
controller: state.unfavoriteFormController,
decoration: InputDecoration(labelText: 'unfavorite_foods'.tr),
maxLines: null,
),
TextField(
controller: state.additionalFormController,
decoration: InputDecoration(labelText: 'additional_information'.tr),
maxLines: null,
),
DropdownButtonFormField<String>(
hint: Text(state.selectedActivity ?? "Не выбрано"),
value: state.selectedActivity,
onChanged: setActivity(state),
items: activities.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: SizedBox(
// Используем SizedBox для ограничения ширины элемента списка
width: MediaQuery.of(context).size.width *
0.8, // Устанавливаем желаемую ширину элемента списка
child: Text(value),
),
);
}).toList(),
isExpanded: true, // Расширяем список на всю доступную ширину
decoration: InputDecoration(labelText: 'Активность'),
),
Row(
children: [
HypoSwitch('do_you_have_hypotension_tendency'.tr, state),
],
),
Row(
children: [
HyperSwitch('do_you_have_hypertension_tendency'.tr, state),
],
),
NextStepButton(
onPressed: () => sendProfileData(state),
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
text: "save".tr.toUpperCase(),
margin: EdgeInsets.only(top: 20.h, bottom: 20.h)),
]);
}
sendData(MyProfileLoadedState state) {
return () {
sendProfileData(state);
};
}
setCity(MyProfileLoadedState state) {
return (newValue) {
// Обработчик изменения выбранного города
setSelectedCity(state, newValue);
};
}
setCountry(MyProfileLoadedState state) {
return (newValue) {
// Обработчик изменения выбранной страны
setSelectedCountry(state, newValue);
};
}
setActivity(MyProfileLoadedState state) {
return (newValue) {
// Обработчик изменения выбранной страны
setSelectedActivity(state, newValue);
};
}
inputTime(BuildContext context, MyProfileLoadedState state) {
return () {
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1900),
lastDate: DateTime.now(),
).then((selectedDate) {
if (selectedDate != null) {
setState(() {
state.dateFormController!.text =
DateFormat('dd-MM-yyyy').format(selectedDate);
});
}
});
};
}
void setSelectedCity(MyProfileLoadedState? state, String? newValue) {
setState(() {
state!.selectedCity = newValue;
});
}
void setSelectedCountry(MyProfileLoadedState? state, String? newValue) {
setState(() {
state!.selectedCountry = newValue;
});
}
void setSelectedActivity(MyProfileLoadedState? state, String? newValue) {
setState(() {
state!.selectedActivity = newValue;
});
}
Future<void> sendProfileData(MyProfileLoadedState? state) async {
print("asd");
try {
// Создаем JSON объект с данными профиля
Map<String, dynamic> profileData = {
'first_name': state?.firstNameFormController?.text,
'last_name': state?.lastNameFormController?.text,
'chest_circumference': state?.chestCircumferenceFormController?.text,
'waist_circumference': state?.waistCircumferenceFormController?.text,
'hip_circumference': state?.hipCircumferenceFormController?.text,
'birthdate': state?.dateFormController?.text,
'height': state?.heightFormController?.text,
'weight': state?.weightFormController?.text,
'blood_pressure_up': state?.upPressureFormController?.text,
'blood_pressure_down': state?.downPressureFormController?.text,
'about_alergy': state?.allergiesFormController?.text ?? 'Нет аллергий',
'about_taking_pils': state?.pillsFormController?.text,
'about_sport_hobbies': state?.sportsFormController?.text,
'favorite_foods': state?.favoriteFormController?.text,
'unfavorite_foods': state?.unfavoriteFormController?.text,
'additional_info': state?.additionalFormController?.text,
'country': state?.selectedCountry ?? 'Россия',
'city': state?.selectedCity ?? 'Москва',
'has_hypo': state?.hypoFormController,
'has_hyper': state?.hyperFormController,
'activity_coefficient':
determineActivityFactor(state?.selectedActivity ?? 'сидячий'),
};
final box = await Hive.openBox('token');
final token = box.get('token');
String apiUrl = dotenv.env['SERVER_ROOT']! + '/profile/update';
http.Response response = await http.post(
Uri.parse(apiUrl),
body: json.encode(profileData),
encoding: utf8,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
},
);
print(response.body);
if (response.statusCode == 200) {
Navigator.pushNamed(
context,
AppRoutes.myProfile,
);
} else {
var res = await jsonDecode(response.body);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Ошибка'),
content: Text(res['message']),
actions: [
TextButton(
onPressed: onTapOk(context),
child: Text('OK'),
),
],
),
);
throw Exception('Ошибка при отправке данных профиля');
}
} catch (error) {
throw Exception('Ошибка при отправке данных профиля: $error');
}
}
onTapOk(BuildContext context) {
return () {
Navigator.pop(context);
};
}
double determineActivityFactor(String activityLevel) {
switch (activityLevel) {
case "сидячий":
return 1.2;
case "низкий (1-3 тренировки в неделю по 20 мин)":
return 1.375;
case "умеренный (3-4 тренировки в неделю по 30-60 мин)":
return 1.55;
case "высокий (5-7 тренировок по 30-60 мин)":
return 1.7;
case "экстремальный (несколько интенсивных тренировок в день)":
return 1.9;
default:
return 1.2; // Возвращаемое значение по умолчанию, если уровень активности не распознан
}
}
}