forked from eatvio/eatvio_app
refactor(diary): Refactoring for settings done
This commit is contained in:
@@ -5,14 +5,12 @@ import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart';
|
||||
import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart';
|
||||
import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart';
|
||||
import 'package:eatvio_app/widgets/custom_bottom_bar.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:eatvio_app/widgets/next_step_button.dart';
|
||||
import 'package:eatvio_app/widgets/custom_about_list.dart';
|
||||
import 'package:eatvio_app/widgets/custom_expandable_list.dart';
|
||||
import 'package:eatvio_app/widgets/custom_notification_screen.dart';
|
||||
import 'package:eatvio_app/widgets/custom_section_title.dart';
|
||||
import 'package:eatvio_app/widgets/custom_language_drop_down.dart';
|
||||
import 'package:flutter/material.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 MySettingsScreen extends StatelessWidget {
|
||||
static Widget builder(BuildContext context) {
|
||||
@@ -43,27 +41,25 @@ class MySettingsScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSetingsScreen(BuildContext context, MyProfileLoadedState state) {
|
||||
_buildSetingsScreen(BuildContext context, MyProfileLoadedState state) {
|
||||
mediaQueryData = MediaQuery.of(context);
|
||||
|
||||
return SafeArea(
|
||||
SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: _buildAppBar(context, "my_settings".tr),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
SectionTitle('Язык'),
|
||||
LanguageDropdown(),
|
||||
SectionTitle('Уведомления'),
|
||||
NotificationSwitch('Уведомление об обновлениях'),
|
||||
NotificationSwitch('Напоминания о заполнении'),
|
||||
SectionTitle('Дополнительная информация'),
|
||||
ExpandableList('Персональные данные'),
|
||||
AboutList('О нас', ['ООО Итвио', '2023-н.в.']),
|
||||
],
|
||||
),
|
||||
child: ListView(
|
||||
children: [
|
||||
SectionTitle('Язык'),
|
||||
LanguageDropdown(),
|
||||
SectionTitle('Уведомления'),
|
||||
NotificationSwitch('Уведомление об обновлениях'),
|
||||
NotificationSwitch('Напоминания о заполнении'),
|
||||
SectionTitle('Дополнительная информация'),
|
||||
ExpandableList('Персональные данные'),
|
||||
AboutList('О нас', ['ООО Итвио', '2023-н.в.']),
|
||||
],
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: _buildBottomBar(context)));
|
||||
@@ -77,9 +73,7 @@ class MySettingsScreen extends StatelessWidget {
|
||||
leading: AppbarLeadingImage(
|
||||
imagePath: ImageConstant.imgArrowLeft,
|
||||
margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v),
|
||||
onTap: () {
|
||||
onTapArrowLeft(context);
|
||||
}),
|
||||
onTap: onTapBack(context)),
|
||||
title: Padding(
|
||||
padding: EdgeInsets.only(left: 20.h),
|
||||
child: Row(children: [
|
||||
@@ -90,7 +84,13 @@ class MySettingsScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBottomBar(BuildContext context) {
|
||||
Function onTapBack(BuildContext context) {
|
||||
return () {
|
||||
onTapArrowLeft(context);
|
||||
};
|
||||
}
|
||||
|
||||
_buildBottomBar(BuildContext context) {
|
||||
return CustomBottomBar(onChanged: (BottomBarEnum type) {});
|
||||
}
|
||||
|
||||
@@ -98,570 +98,3 @@ class MySettingsScreen extends StatelessWidget {
|
||||
NavigatorService.goBack();
|
||||
}
|
||||
}
|
||||
|
||||
class SectionTitle extends StatelessWidget {
|
||||
final String title;
|
||||
|
||||
SectionTitle(this.title);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LanguageDropdown extends StatefulWidget {
|
||||
@override
|
||||
_LanguageDropdownState createState() => _LanguageDropdownState();
|
||||
}
|
||||
|
||||
class _LanguageDropdownState extends State<LanguageDropdown> {
|
||||
String selectedLanguage = 'Русский';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DropdownButton<String>(
|
||||
value: selectedLanguage,
|
||||
onChanged: (newValue) {
|
||||
setState(() {
|
||||
selectedLanguage = newValue!;
|
||||
});
|
||||
},
|
||||
isDense: false, // Установите isDense в false
|
||||
selectedItemBuilder: (BuildContext context) {
|
||||
return ['Русский'].map<Widget>((String language) {
|
||||
return Align(
|
||||
alignment: Alignment.center, // Выравнивание текста по центру
|
||||
child: Text(
|
||||
language,
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
},
|
||||
items: ['Русский'].map((String language) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: language,
|
||||
child: Text(language),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationSwitch extends StatefulWidget {
|
||||
final String title;
|
||||
|
||||
NotificationSwitch(this.title);
|
||||
|
||||
@override
|
||||
_NotificationSwitchState createState() => _NotificationSwitchState();
|
||||
}
|
||||
|
||||
class _NotificationSwitchState extends State<NotificationSwitch> {
|
||||
bool switchValue = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
widget.title,
|
||||
style: TextStyle(
|
||||
color: Colors.black, fontSize: 14, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Switch(
|
||||
value: switchValue,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
switchValue = value;
|
||||
});
|
||||
},
|
||||
inactiveThumbColor: appTheme.blueA400,
|
||||
inactiveTrackColor: Colors.white,
|
||||
activeTrackColor: appTheme.blueA400,
|
||||
activeColor: Colors.white,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HyperSwitch extends StatefulWidget {
|
||||
final String title;
|
||||
final MyProfileLoadedState? state;
|
||||
HyperSwitch(this.title, this.state);
|
||||
|
||||
@override
|
||||
_HyperState createState() => _HyperState();
|
||||
}
|
||||
|
||||
class _HyperState extends State<HyperSwitch> {
|
||||
bool switchValue = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.state?.hyperFormController == '1') {
|
||||
switchValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
widget.title,
|
||||
style: TextStyle(
|
||||
color: Colors.black, fontSize: 14, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Switch(
|
||||
value: switchValue,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
switchValue = value;
|
||||
widget.state!.hyperFormController = value ? "1" : "0";
|
||||
});
|
||||
},
|
||||
inactiveThumbColor: appTheme.blueA400,
|
||||
inactiveTrackColor: Colors.white,
|
||||
activeTrackColor: appTheme.blueA400,
|
||||
activeColor: Colors.white,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HypoSwitch extends StatefulWidget {
|
||||
final String title;
|
||||
final MyProfileLoadedState? state;
|
||||
HypoSwitch(this.title, this.state);
|
||||
|
||||
@override
|
||||
_HypoState createState() => _HypoState();
|
||||
}
|
||||
|
||||
class _HypoState extends State<HypoSwitch> {
|
||||
bool switchValue = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.state?.hypoFormController == '1') {
|
||||
switchValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
widget.title,
|
||||
style: TextStyle(
|
||||
color: Colors.black, fontSize: 14, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Switch(
|
||||
value: switchValue,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
switchValue = value;
|
||||
widget.state!.hypoFormController = value ? "1" : "0";
|
||||
});
|
||||
},
|
||||
inactiveThumbColor: appTheme.blueA400,
|
||||
inactiveTrackColor: Colors.white,
|
||||
activeTrackColor: appTheme.blueA400,
|
||||
activeColor: Colors.white,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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: () {
|
||||
setState(() {
|
||||
isExpanded = !isExpanded;
|
||||
});
|
||||
},
|
||||
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(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildForm(BuildContext context, MyProfileLoadedState state) {
|
||||
List<String> cities = [
|
||||
'Москва',
|
||||
'Санкт-Петербург',
|
||||
'Новосибирск',
|
||||
'Екатеринбург',
|
||||
'Нижний Новгород',
|
||||
'Казань',
|
||||
'Челябинск',
|
||||
'Омск',
|
||||
'Самара',
|
||||
'Ростов-на-Дону',
|
||||
'Уфа',
|
||||
'Красноярск',
|
||||
'Воронеж',
|
||||
'Пермь',
|
||||
'Волгоград',
|
||||
'Краснодар',
|
||||
'Саратов',
|
||||
'Тюмень',
|
||||
'Тольятти',
|
||||
'Ижевск',
|
||||
'Барнаул',
|
||||
'Ульяновск',
|
||||
'Иркутск',
|
||||
'Хабаровск',
|
||||
'Ярославль',
|
||||
'Владивосток',
|
||||
'Махачкала',
|
||||
'Томск',
|
||||
'Оренбург',
|
||||
'Кемерово',
|
||||
];
|
||||
List<String> countries = [
|
||||
'Россия',
|
||||
];
|
||||
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: () {
|
||||
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);
|
||||
});
|
||||
}
|
||||
});
|
||||
}),
|
||||
DropdownButtonFormField<String>(
|
||||
value: state.selectedCountry,
|
||||
hint: Text(state.selectedCountry ?? "Не выбрано"),
|
||||
onChanged: (newValue) {
|
||||
// Обработчик изменения выбранной страны
|
||||
setSelectedCountry(state, newValue);
|
||||
},
|
||||
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: (newValue) {
|
||||
// Обработчик изменения выбранного города
|
||||
setSelectedCity(state, newValue);
|
||||
},
|
||||
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,
|
||||
),
|
||||
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)),
|
||||
]);
|
||||
}
|
||||
|
||||
void setSelectedCity(MyProfileLoadedState? state, String? newValue) {
|
||||
setState(() {
|
||||
state!.selectedCity = newValue;
|
||||
});
|
||||
}
|
||||
|
||||
void setSelectedCountry(MyProfileLoadedState? state, String? newValue) {
|
||||
setState(() {
|
||||
state!.selectedCountry = newValue;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> sendProfileData(MyProfileLoadedState? state) async {
|
||||
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,
|
||||
};
|
||||
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',
|
||||
'Authorization': 'Bearer $token',
|
||||
},
|
||||
);
|
||||
|
||||
print(response.body);
|
||||
if (response.statusCode == 200) {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
AppRoutes.myProfile,
|
||||
);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text('Ошибка'),
|
||||
content: Text('Ошибка при отправке данных профиля'.tr),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text('OK'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
throw Exception('Ошибка при отправке данных профиля');
|
||||
}
|
||||
} catch (error) {
|
||||
throw Exception('Ошибка при отправке данных профиля: $error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AboutList extends StatefulWidget {
|
||||
final String title;
|
||||
final List<String> items;
|
||||
|
||||
AboutList(this.title, this.items);
|
||||
|
||||
@override
|
||||
_AboutListState createState() => _AboutListState();
|
||||
}
|
||||
|
||||
class _AboutListState extends State<AboutList> {
|
||||
bool isExpanded = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isExpanded = !isExpanded;
|
||||
});
|
||||
},
|
||||
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: Column(
|
||||
//children: widget.items.map((item) => Text(item)).toList(),
|
||||
children: [Text(widget.items.join('\n'))]),
|
||||
),
|
||||
Divider(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
56
lib/widgets/custom_about_list.dart
Normal file
56
lib/widgets/custom_about_list.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AboutList extends StatefulWidget {
|
||||
final String title;
|
||||
final List<String> items;
|
||||
|
||||
AboutList(this.title, this.items);
|
||||
|
||||
@override
|
||||
_AboutListState createState() => _AboutListState();
|
||||
}
|
||||
|
||||
class _AboutListState extends State<AboutList> {
|
||||
bool isExpanded = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: toggleList(),
|
||||
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: Column(
|
||||
//children: widget.items.map((item) => Text(item)).toList(),
|
||||
children: [Text(widget.items.join('\n'))]),
|
||||
),
|
||||
Divider(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
toggleList() {
|
||||
return () {
|
||||
setState(() {
|
||||
isExpanded = !isExpanded;
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
360
lib/widgets/custom_expandable_list.dart
Normal file
360
lib/widgets/custom_expandable_list.dart
Normal file
@@ -0,0 +1,360 @@
|
||||
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;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Widget _buildForm(BuildContext context, MyProfileLoadedState state) {
|
||||
List<String> cities = [
|
||||
'Москва',
|
||||
'Санкт-Петербург',
|
||||
'Новосибирск',
|
||||
'Екатеринбург',
|
||||
'Нижний Новгород',
|
||||
'Казань',
|
||||
'Челябинск',
|
||||
'Омск',
|
||||
'Самара',
|
||||
'Ростов-на-Дону',
|
||||
'Уфа',
|
||||
'Красноярск',
|
||||
'Воронеж',
|
||||
'Пермь',
|
||||
'Волгоград',
|
||||
'Краснодар',
|
||||
'Саратов',
|
||||
'Тюмень',
|
||||
'Тольятти',
|
||||
'Ижевск',
|
||||
'Барнаул',
|
||||
'Ульяновск',
|
||||
'Иркутск',
|
||||
'Хабаровск',
|
||||
'Ярославль',
|
||||
'Владивосток',
|
||||
'Махачкала',
|
||||
'Томск',
|
||||
'Оренбург',
|
||||
'Кемерово',
|
||||
];
|
||||
List<String> countries = [
|
||||
'Россия',
|
||||
];
|
||||
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,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
HypoSwitch('do_you_have_hypotension_tendency'.tr, state),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
HyperSwitch('do_you_have_hypertension_tendency'.tr, state),
|
||||
],
|
||||
),
|
||||
NextStepButton(
|
||||
onPressed: sendData(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);
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> sendProfileData(MyProfileLoadedState? state) async {
|
||||
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,
|
||||
};
|
||||
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',
|
||||
'Authorization': 'Bearer $token',
|
||||
},
|
||||
);
|
||||
|
||||
print(response.body);
|
||||
if (response.statusCode == 200) {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
AppRoutes.myProfile,
|
||||
);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text('Ошибка'),
|
||||
content: Text('Ошибка при отправке данных профиля'.tr),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: onTapOk(context),
|
||||
child: Text('OK'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
throw Exception('Ошибка при отправке данных профиля');
|
||||
}
|
||||
} catch (error) {
|
||||
throw Exception('Ошибка при отправке данных профиля: $error');
|
||||
}
|
||||
}
|
||||
|
||||
onTapOk(BuildContext context) {
|
||||
return () {
|
||||
Navigator.pop(context);
|
||||
};
|
||||
}
|
||||
}
|
||||
55
lib/widgets/custom_hyper_switch.dart
Normal file
55
lib/widgets/custom_hyper_switch.dart
Normal file
@@ -0,0 +1,55 @@
|
||||
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';
|
||||
|
||||
class HyperSwitch extends StatefulWidget {
|
||||
final String title;
|
||||
final MyProfileLoadedState? state;
|
||||
HyperSwitch(this.title, this.state);
|
||||
|
||||
@override
|
||||
_HyperState createState() => _HyperState();
|
||||
}
|
||||
|
||||
class _HyperState extends State<HyperSwitch> {
|
||||
bool switchValue = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.state?.hyperFormController == '1') {
|
||||
switchValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
widget.title,
|
||||
style: TextStyle(
|
||||
color: Colors.black, fontSize: 14, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Switch(
|
||||
value: switchValue,
|
||||
onChanged: toggleSwitch(),
|
||||
inactiveThumbColor: appTheme.blueA400,
|
||||
inactiveTrackColor: Colors.white,
|
||||
activeTrackColor: appTheme.blueA400,
|
||||
activeColor: Colors.white,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
toggleSwitch() {
|
||||
return (value) {
|
||||
setState(() {
|
||||
switchValue = value;
|
||||
widget.state!.hyperFormController = value ? "1" : "0";
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
55
lib/widgets/custom_hypo_switch.dart
Normal file
55
lib/widgets/custom_hypo_switch.dart
Normal file
@@ -0,0 +1,55 @@
|
||||
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';
|
||||
|
||||
class HypoSwitch extends StatefulWidget {
|
||||
final String title;
|
||||
final MyProfileLoadedState? state;
|
||||
HypoSwitch(this.title, this.state);
|
||||
|
||||
@override
|
||||
_HypoState createState() => _HypoState();
|
||||
}
|
||||
|
||||
class _HypoState extends State<HypoSwitch> {
|
||||
bool switchValue = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.state?.hypoFormController == '1') {
|
||||
switchValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
widget.title,
|
||||
style: TextStyle(
|
||||
color: Colors.black, fontSize: 14, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Switch(
|
||||
value: switchValue,
|
||||
onChanged: toggleSwitch(),
|
||||
inactiveThumbColor: appTheme.blueA400,
|
||||
inactiveTrackColor: Colors.white,
|
||||
activeTrackColor: appTheme.blueA400,
|
||||
activeColor: Colors.white,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
toggleSwitch() {
|
||||
return (value) {
|
||||
setState(() {
|
||||
switchValue = value;
|
||||
widget.state!.hypoFormController = value ? "1" : "0";
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
48
lib/widgets/custom_language_drop_down.dart
Normal file
48
lib/widgets/custom_language_drop_down.dart
Normal file
@@ -0,0 +1,48 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LanguageDropdown extends StatefulWidget {
|
||||
@override
|
||||
_LanguageDropdownState createState() => _LanguageDropdownState();
|
||||
}
|
||||
|
||||
class _LanguageDropdownState extends State<LanguageDropdown> {
|
||||
String selectedLanguage = 'Русский';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DropdownButton<String>(
|
||||
value: selectedLanguage,
|
||||
onChanged: selectLanguage(),
|
||||
isDense: false, // Установите isDense в false
|
||||
selectedItemBuilder: getList(),
|
||||
items: ['Русский'].map((String language) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: language,
|
||||
child: Text(language),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
getList() {
|
||||
return (BuildContext context) {
|
||||
return ['Русский'].map<Widget>((String language) {
|
||||
return Align(
|
||||
alignment: Alignment.center, // Выравнивание текста по центру
|
||||
child: Text(
|
||||
language,
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
};
|
||||
}
|
||||
|
||||
selectLanguage() {
|
||||
return (newValue) {
|
||||
setState(() {
|
||||
selectedLanguage = newValue!;
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
45
lib/widgets/custom_notification_screen.dart
Normal file
45
lib/widgets/custom_notification_screen.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:eatvio_app/core/app_export.dart';
|
||||
|
||||
class NotificationSwitch extends StatefulWidget {
|
||||
final String title;
|
||||
|
||||
NotificationSwitch(this.title);
|
||||
|
||||
@override
|
||||
_NotificationSwitchState createState() => _NotificationSwitchState();
|
||||
}
|
||||
|
||||
class _NotificationSwitchState extends State<NotificationSwitch> {
|
||||
bool switchValue = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
widget.title,
|
||||
style: TextStyle(
|
||||
color: Colors.black, fontSize: 14, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Switch(
|
||||
value: switchValue,
|
||||
onChanged: toggleSwitch(),
|
||||
inactiveThumbColor: appTheme.blueA400,
|
||||
inactiveTrackColor: Colors.white,
|
||||
activeTrackColor: appTheme.blueA400,
|
||||
activeColor: Colors.white,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
toggleSwitch() {
|
||||
return (value) {
|
||||
setState(() {
|
||||
switchValue = value;
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
19
lib/widgets/custom_section_title.dart
Normal file
19
lib/widgets/custom_section_title.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SectionTitle extends StatelessWidget {
|
||||
final String title;
|
||||
|
||||
SectionTitle(this.title);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user