refactor(diary): Compiled version apk: profile, settings, diarym registration, auth, navigation bar

This commit is contained in:
2024-04-10 17:07:56 +03:00
parent f4ddb7285c
commit bbbc20a15a
11 changed files with 164 additions and 133 deletions

View File

@@ -86,6 +86,7 @@ class UserRegistrationSheet {
'favorite_foods': favoriteFoods,
'unfavorite_foods': unfavoriteFoods,
'additional_info': additionalInfo,
'activity_coefficient': '1.2',
};
}
}

View File

@@ -65,7 +65,7 @@ class AuthScreen extends StatelessWidget {
EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v),
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
onPressed: onTapNoAccount(context)),
NextStepButton(
/*NextStepButton(
text: "Тест дневника".toUpperCase(),
margin:
EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v),
@@ -76,14 +76,14 @@ class AuthScreen extends StatelessWidget {
margin:
EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v),
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
onPressed: onTapProfileTest(context)),
onPressed: onTapProfileTest(context)),*/
BlocBuilder<AuthBloc, AuthState>(builder: (context, state) {
return NextStepButton(
text: "authentificate".tr.toUpperCase(),
margin:
EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v),
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
onPressed: () => onTapAuth(state, context));
onPressed: onTapAuth(state, context));
}),
])));
}
@@ -102,6 +102,7 @@ class AuthScreen extends StatelessWidget {
headers: {'Content-Type': 'application/json'},
body: json.encode(credentials),
encoding: utf8);
print(response.statusCode);
if (response.statusCode == 200) {
var res = await jsonDecode(response.body);
final box = await Hive.openBox('token');

View File

@@ -89,9 +89,10 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
diaryEditModelObj: currentState.diaryEditModelObj));
} else {
// Если текущее состояние - начальное, создаем новое загруженное состояние
final List<SelectionPopupModel> meals =
fillMealList(diary['meals']);
emit(DiaryEditLoadedState(
currentMeal: SelectionPopupModel(
id: 1, title: "Прием пищи 1", isSelected: true),
currentMeal: meals[0],
portionController: SelectionPopupModel(
id: 0, title: "порций", isSelected: true),
wakeupExpanded: true,
@@ -120,8 +121,8 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
diaryId: diaryId,
diaryDate: diaryDate,
autocompleteList: [],
diaryEditModelObj: state.diaryEditModelObj?.copyWith(
mealList: fillMealList(), portionList: fillPortions())));
diaryEditModelObj: state.diaryEditModelObj
?.copyWith(mealList: meals, portionList: fillPortions())));
}
}
} catch (e) {
@@ -200,7 +201,18 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
}
reloadScreen(DiaryEditEvent event, Emitter<DiaryEditState> emit) async {
refreshScreen(
int mealID,
DiaryEditEvent event,
Emitter<DiaryEditState> emit,
) async {
await reloadScreen(event, emit);
}
reloadScreen(
DiaryEditEvent event,
Emitter<DiaryEditState> emit,
) async {
print("Reloading...");
try {
final token =
@@ -244,45 +256,46 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
responseChart.body)['dailyNutritionRecommendation'];
final consumedChartValues =
jsonDecode(responseChart.body)['dailyNutritionIntake'];
final List<SelectionPopupModel> meals =
fillMealList(diary['meals']);
try {
await Future(() => emit(DiaryEditLoadedState(
currentMeal: SelectionPopupModel(
id: 1, title: "Прием пищи 1", isSelected: true),
portionController: SelectionPopupModel(
id: 0, title: "порций", isSelected: true),
wakeupExpanded: true,
moodExpanded: true,
moderationExpanded: false,
token: token,
recommendedChartValues: recommendedChartValues.values
.map<int>((value) => value as int)
.toList(),
consumedChartValues: consumedChartValues.values
.map<int>((value) => value as int)
.toList(),
meals: diary['meals'],
portions: diary['meals'][0]['portions'],
photos: diary['meals'][0]['photos'],
wakeupController: toTime(diary['wakeup'] ?? "09:00"),
retireController: toTime(diary['retire'] ?? "23:00"),
mealTimeController:
toTime(diary['meals'][0]['time'] ?? "10:00"),
selectedSatiety: diary['meals'][0]['satiety'],
selectedMood: diary['meals'][0]['mood'],
commentController:
TextEditingController(text: diary['comment']),
productNameController: TextEditingController(),
productQuantityController: TextEditingController(),
caloriesController: TextEditingController(),
proteinsController: TextEditingController(),
fatsController: TextEditingController(),
carbsController: TextEditingController(),
diaryId: diaryId,
diaryDate: diaryDate,
autocompleteList: [],
diaryEditModelObj: state.diaryEditModelObj?.copyWith(
mealList: fillMealList(),
portionList: fillPortions()))));
diaryEditModelObj: state.diaryEditModelObj?.copyWith(
mealList: meals, portionList: fillPortions()),
currentMeal: meals[0],
portionController: SelectionPopupModel(
id: 0, title: "порций", isSelected: true),
wakeupExpanded: true,
moodExpanded: true,
moderationExpanded: false,
token: token,
recommendedChartValues: recommendedChartValues.values
.map<int>((value) => value as int)
.toList(),
consumedChartValues: consumedChartValues.values
.map<int>((value) => value as int)
.toList(),
meals: diary['meals'],
portions: diary['meals'][0]['portions'],
photos: diary['meals'][0]['photos'],
wakeupController: toTime(diary['wakeup'] ?? "09:00"),
retireController: toTime(diary['retire'] ?? "23:00"),
mealTimeController:
toTime(diary['meals'][0]['time'] ?? "10:00"),
selectedSatiety: diary['meals'][0]['satiety'],
selectedMood: diary['meals'][0]['mood'],
commentController:
TextEditingController(text: diary['comment']),
productNameController: TextEditingController(),
productQuantityController: TextEditingController(),
caloriesController: TextEditingController(),
proteinsController: TextEditingController(),
fatsController: TextEditingController(),
carbsController: TextEditingController(),
diaryId: diaryId,
diaryDate: diaryDate,
autocompleteList: [],
)));
print("Updated");
} catch (e) {
@@ -364,6 +377,8 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
currentState.diaryId);
if (response.statusCode == 200) {
print(
'Mood change success! meal_id: ${currentState.currentMeal?.id}, mood: ${event.selectedElement}');
updatedState.selectedMood = event.selectedElement;
emit(updatedState); // Передаем обновленное состояние в emit
}
@@ -511,11 +526,10 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
final meal = currentState.meals?.firstWhere(
(meal) => meal['type'] == event.value.id,
(meal) => meal['id'] == event.value.id,
orElse: () => null);
print(meal);
int? id = event.value.id;
print(meal['photos']);
DiaryEditLoadedState updatedState = currentState.copyWith(
currentMeal: event.value,
portions: meal['portions'],
@@ -523,6 +537,7 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
mealTimeController: toTime(meal['time'] ?? "1$id:00"),
selectedMood: meal['mood'],
selectedSatiety: meal['satiety']);
print(updatedState.photos);
emit(updatedState);
}
}
@@ -916,15 +931,16 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
return timeOfDay;
}
List<SelectionPopupModel> fillMealList() {
return [
SelectionPopupModel(id: 1, title: "Прием пищи 1", isSelected: true),
SelectionPopupModel(id: 2, title: "Прием пищи 2"),
SelectionPopupModel(id: 3, title: "Прием пищи 3"),
SelectionPopupModel(id: 4, title: "Прием пищи 4"),
SelectionPopupModel(id: 5, title: "Прием пищи 5"),
SelectionPopupModel(id: 6, title: "Прием пищи 6"),
];
List<SelectionPopupModel> fillMealList(List<dynamic> meals) {
meals.sort(compareTypes);
return meals.map((meal) {
String title = "Прием пищи ${meal['type']}";
return SelectionPopupModel(id: meal['id'], title: title);
}).toList();
}
int compareTypes(a, b) {
return a['type'].compareTo(b['type']);
}
List<SelectionPopupModel> fillPortions() {

View File

@@ -139,6 +139,7 @@ class DiaryEditLoadedState extends DiaryEditState {
diaryDate: diaryDate ?? this.diaryDate,
token: token ?? this.token,
meals: meals ?? this.meals,
photos: photos ?? this.photos,
autocompleteList: autocompleteList ?? this.autocompleteList,
portions: portions ?? this.portions,
recommendedChartValues:

View File

@@ -13,6 +13,7 @@ import 'package:eatvio_app/widgets/custom_edit_text_form_field.dart';
import 'package:eatvio_app/widgets/custom_edit_drop_down.dart';
import 'package:eatvio_app/widgets/custom_outlined_button.dart';
import 'package:eatvio_app/widgets/custom_scale_element.dart';
import 'package:eatvio_app/widgets/custom_bottom_bar.dart';
// ignore: must_be_immutable
class DiaryEditScreen extends StatelessWidget {
@@ -229,7 +230,6 @@ class DiaryEditScreen extends StatelessWidget {
state.autocompleteList!.map((dynamic item) => item as String).toList();
//print(_options);
FocusNode focusNodeName = FocusNode();
FocusNode focusNodeQuantity = FocusNode();
return Container(
margin: EdgeInsets.symmetric(horizontal: 16.h),
padding: EdgeInsets.symmetric(
@@ -318,10 +318,7 @@ class DiaryEditScreen extends StatelessWidget {
hintText: "Введите название продукта",
controller: productEditingController,
focusNode: focusNodeName,
onChanged: getAutocomplete(context, focusNodeQuantity),
/*onFieldSubmitted: (String value) {
onFieldSubmitted();
},*/
onChanged: getAutocomplete(context, focusNodeName),
);
},
optionsViewBuilder: (
@@ -341,7 +338,7 @@ class DiaryEditScreen extends StatelessWidget {
itemBuilder: (BuildContext context, int index) {
final String option = options.elementAt(index);
return GestureDetector(
onTap: selectProduct(onSelected, option),
onTap: selectProduct(onSelected, option, state),
child: ListTile(
title: Text(option),
),
@@ -374,7 +371,7 @@ class DiaryEditScreen extends StatelessWidget {
width: 150.h,
hintText: "Кол-во",
textInputAction: TextInputAction.done,
focusNode: focusNodeQuantity,
// focusNode: focusNodeQuantity,
controller: state.productQuantityController,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[digitsOnly],
@@ -405,10 +402,12 @@ class DiaryEditScreen extends StatelessWidget {
.toList(),
SizedBox(height: 30.v),
...state.photos != null
? state.photos!
.map((photo) => _buildPhoto(context, photo))
.toList()
: [],
? state.photos!.isEmpty
? [Text('Фото пока нет')]
: state.photos!
.map((photo) => _buildPhoto(context, photo))
.toList()
: [Text('Фото нет')],
SizedBox(height: 20.v),
_buildAddPhoto(context),
SizedBox(height: 30.v),
@@ -561,7 +560,9 @@ class DiaryEditScreen extends StatelessWidget {
};
}
selectProduct(AutocompleteOnSelected<String> onSelected, String option) {
selectProduct(AutocompleteOnSelected<String> onSelected, String option,
DiaryEditLoadedState state) {
state.productNameController?.text = option;
return () {
onSelected(option);
};
@@ -764,25 +765,37 @@ class DiaryEditScreen extends StatelessWidget {
BarChartGroupData(x: 0, barRods: [
BarChartRodData(
toY: consumedValues[0] / recommendedValues[0] * 100,
color: Colors.blue,
color: checkConsumedValues(
[recommendedValues[0]], [consumedValues[1]])
? Colors.red
: Colors.blue,
)
]),
BarChartGroupData(x: 1, barRods: [
BarChartRodData(
toY: consumedValues[1] / recommendedValues[1] * 100,
color: Colors.red,
color: checkConsumedValues(
[recommendedValues[1]], [consumedValues[1]])
? Colors.red
: Colors.blue,
)
]),
BarChartGroupData(x: 2, barRods: [
BarChartRodData(
toY: consumedValues[2] / recommendedValues[2] * 100,
color: Colors.green,
color: checkConsumedValues(
[recommendedValues[2]], [consumedValues[2]])
? Colors.red
: Colors.blue,
)
]),
BarChartGroupData(x: 3, barRods: [
BarChartRodData(
toY: consumedValues[3] / recommendedValues[3] * 100,
color: Colors.orange,
color: checkConsumedValues(
[recommendedValues[3]], [consumedValues[3]])
? Colors.red
: Colors.blue,
)
]),
],
@@ -889,7 +902,7 @@ class DiaryEditScreen extends StatelessWidget {
SizedBox(height: 19.v),
if (checkConsumedValues(recommendedValues, consumedValues))
Text(
"*Превышенная суточная норма углеводов",
"*Превышенная суточная норма",
style: theme.textTheme.labelLarge,
)
],
@@ -1042,7 +1055,6 @@ class DiaryEditScreen extends StatelessWidget {
Function() onFinishDayPressed(BuildContext context) {
return () {
print("sad");
showDialog(
context: context,
builder: (BuildContext dialogContext) {

View File

@@ -4,7 +4,7 @@ import '/core/app_export.dart';
import 'package:eatvio_app/presentation/profile/my_profile_screen/models/my_profile_model.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
//import 'package:hive/hive.dart';
import 'package:hive/hive.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
part 'my_profile_event.dart';
@@ -21,28 +21,24 @@ class MyProfileBloc extends Bloc<MyProfileEvent, MyProfileState> {
Emitter<MyProfileState> emit,
) async {
try {
/*final box = await Hive.openBox('token');
final token = box.get('token');*/
final token =
"9|laravel_sanctum_KFXbccDcWEvTPfJmV99EQv1neAggmpR2TidVGDPN34fa201a";
final box = await Hive.openBox('token');
final token = box.get('token');
//final token =
// "9|laravel_sanctum_KFXbccDcWEvTPfJmV99EQv1neAggmpR2TidVGDPN34fa201a";
final response = await http.get(
Uri.parse(dotenv.env['SERVER_ROOT']! + '/profile/index'),
headers: {
'Authorization': 'Bearer $token',
},
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
// Проверка наличия ключевых полей в JSON
if (data is Map<String, dynamic> &&
data.containsKey('user') &&
data.containsKey('userDetails') &&
data.containsKey('chartPoints') &&
data.containsKey('circumferences')) {
// Все ключевые поля присутствуют, продолжаем обработку
if (state is MyProfileLoadedState) {
// Если текущее состояние уже загружено, обновляем его
var currentState = state as MyProfileLoadedState;
var plans = []
..addAll(data["finishedPlans"])
@@ -51,9 +47,6 @@ class MyProfileBloc extends Bloc<MyProfileEvent, MyProfileState> {
..addAll(data["paidPlan"])
..addAll(data["requestedPlan"])
..addAll(data["initedPlan"]);
// Обновляем значения контроллеров только если они уже были созданы
emit((currentState).copyWith(
chartPoints: currentState.chartPoints,
chartDates: currentState.chartDates,
@@ -123,18 +116,6 @@ class MyProfileBloc extends Bloc<MyProfileEvent, MyProfileState> {
})
: data["chartPoints"];
/*List<double> weights = [0.0, 0.0, 0.0, 0.0];
List<String> dates = [
"0000-00-00 00:00:00",
"0000-00-00 00:00:00",
"0000-00-00 00:00:00",
"0000-00-00 00:00:00"
];
for (int i = 0; i < data["chartPoints"].length; i++) {
weights[i] = data["chartPoints"][i]["weight"].toDouble();
dates[i] = data["chartPoints"][i]["created_at"].toString();
}
print(data);*/
List<String> dates = [
"0000-00-00 00:00:00",
"0000-00-00 00:00:00",
@@ -169,14 +150,7 @@ class MyProfileBloc extends Bloc<MyProfileEvent, MyProfileState> {
};
}
}
print(data['userDetails']);
/*print(chartPoints);
print(circumferences);*/
/*print(weights);
print(weights.runtimeType);
print(circumferences);
print(circumferences.runtimeType);*/
// Если текущее состояние - начальное, создаем новое загруженное состояние
emit(MyProfileLoadedState(
chartPoints: chartPoints,
chartDates: dates,
@@ -231,7 +205,7 @@ class MyProfileBloc extends Bloc<MyProfileEvent, MyProfileState> {
selectedCity: data['userDetails']['city'],
selectedCountry: data['userDetails']['country'],
selectedActivity: determineActivityLevel(
double.parse(data['userDetails']['activity_coefficient'])),
data['userDetails']['activity_coefficient']),
));
}
} else {

View File

@@ -182,7 +182,7 @@ class MyProfileScreen extends StatelessWidget {
switch (chartType) {
case 1: // График веса
return GestureDetector(
onTap: _editWeight(context, state),
onTap: () => _editWeight(context, state),
child: Column(children: [
Text(
"weight_chart".tr,
@@ -225,7 +225,7 @@ class MyProfileScreen extends StatelessWidget {
]);
case 3: //График обхватов
return GestureDetector(
onTap: _editCircumference(context, state),
onTap: () => _editCircumference(context, state),
child: Column(children: [
Text(
"circumferences_chart".tr,
@@ -279,10 +279,8 @@ class MyProfileScreen extends StatelessWidget {
);
}
/// Section Widget
_buildChart(
BuildContext context, List<double> chartPoints, List<String>? dates) {
// Определение осей графика
List<FlSpot> spots = [];
for (int i = 0; i < 4; i++) {
spots.add(
@@ -428,7 +426,7 @@ class MyProfileScreen extends StatelessWidget {
};
}
mapSpots() {
List<LineTooltipItem?> Function(List<LineBarSpot>) mapSpots() {
return (touchedSpots) {
return touchedSpots.map((LineBarSpot touchedSpot) {
final textStyle = TextStyle(
@@ -635,7 +633,7 @@ class MyProfileScreen extends StatelessWidget {
);
}
mapTouchedSpots() {
List<LineTooltipItem?> Function(List<LineBarSpot>) mapTouchedSpots() {
return (touchedSpots) {
return touchedSpots.map((LineBarSpot touchedSpot) {
final textStyle = TextStyle(

View File

@@ -78,12 +78,12 @@ class AdditionalInformationScreen extends StatelessWidget {
sheet.additionalInfo = state.editTextController!.text;
//print(json.encode(sheet.toJson()));
final response = await http.post(
Uri.parse(dotenv.env['SERVER_ROOT']! + '/register'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(sheet.toJson()),
);
print(response.statusCode);
print(response.body);
Uri.parse(dotenv.env['SERVER_ROOT']! + '/register'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(sheet),
encoding: utf8);
print(jsonEncode(sheet.toJson()));
print(Uri.parse(dotenv.env['SERVER_ROOT']! + '/register'));
if (response.statusCode == 200) {
var res = await jsonDecode(response.body);
final box = await Hive.openBox('token');

View File

@@ -21,12 +21,12 @@ class CustomBottomBarState extends State<CustomBottomBar> {
title: "diary".tr,
type: BottomBarEnum.tf,
),
BottomMenuModel(
/*BottomMenuModel(
icon: ImageConstant.imgNavBlueGray400,
activeIcon: ImageConstant.imgNavBlueGray400,
title: "my_blog".tr,
type: BottomBarEnum.tf,
),
),*/
BottomMenuModel(
icon: ImageConstant.imgNavBlueGray40024x23,
activeIcon: ImageConstant.imgNavBlueGray40024x23,
@@ -34,9 +34,9 @@ class CustomBottomBarState extends State<CustomBottomBar> {
type: BottomBarEnum.tf,
),
BottomMenuModel(
icon: ImageConstant.imgNavPrimary,
activeIcon: ImageConstant.imgNavPrimary,
title: "admin".tr,
icon: ImageConstant.imgNavBlueGray40024x23,
activeIcon: ImageConstant.imgNavBlueGray40024x23,
title: "Настройки",
type: BottomBarEnum.tf,
),
BottomMenuModel(
@@ -72,12 +72,33 @@ class CustomBottomBarState extends State<CustomBottomBar> {
}
void changeMeny(index) {
selectedIndex = index;
widget.onChanged?.call(bottomMenuList[index].type);
setState(() {});
setState(() {
selectedIndex = index;
});
switch (index) {
case 0:
Navigator.pushNamed(context, AppRoutes.diaryEdit);
break;
/*case 1:
Navigator.pushNamed(context, '/my_blog');
break;*/
case 1:
Navigator.pushNamed(context, AppRoutes.myProfile);
break;
case 2:
Navigator.pushNamed(context, AppRoutes.mySettings);
break;
case 3:
Navigator.pushNamed(context, '/chat');
break;
default:
}
}
BottomNavigationBarItem bottomMenu(index) {
bool isSelected = selectedIndex == index;
return BottomNavigationBarItem(
icon: Column(
crossAxisAlignment: CrossAxisAlignment.center,
@@ -86,14 +107,17 @@ class CustomBottomBarState extends State<CustomBottomBar> {
imagePath: bottomMenuList[index].icon,
height: 24.v,
width: 19.h,
color: appTheme.blueGray400,
color:
isSelected ? theme.colorScheme.primary : appTheme.blueGray400,
),
Padding(
padding: EdgeInsets.only(top: 8.v),
child: Text(
bottomMenuList[index].title ?? "",
style: CustomTextStyles.bodySmallMulishBluegray80012.copyWith(
color: appTheme.blueGray800,
color: isSelected
? theme.colorScheme.primary
: appTheme.blueGray800,
),
),
),

View File

@@ -20,6 +20,7 @@ class CustomTextFormField extends StatelessWidget {
this.prefixConstraints,
this.suffix,
this.suffixConstraints,
this.onFieldSubmitted,
this.initialValue,
this.contentPadding,
this.inputFormatters,
@@ -66,6 +67,8 @@ class CustomTextFormField extends StatelessWidget {
final Widget? suffix;
final Function(String)? onFieldSubmitted;
final BoxConstraints? suffixConstraints;
final EdgeInsets? contentPadding;
@@ -112,6 +115,7 @@ class CustomTextFormField extends StatelessWidget {
keyboardType: keyboardType,
onSaved: onSaved,
onChanged: onChanged,
onFieldSubmitted: onFieldSubmitted,
inputFormatters: inputFormatters,
initialValue: initialValue,
),

View File

@@ -255,7 +255,7 @@ class _ExpandableListState extends State<ExpandableList> {
],
),
NextStepButton(
onPressed: sendData(state),
onPressed: () => sendProfileData(state),
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
text: "save".tr.toUpperCase(),
margin: EdgeInsets.only(top: 20.h, bottom: 20.h)),
@@ -326,6 +326,7 @@ class _ExpandableListState extends State<ExpandableList> {
}
Future<void> sendProfileData(MyProfileLoadedState? state) async {
print("asd");
try {
// Создаем JSON объект с данными профиля
Map<String, dynamic> profileData = {
@@ -350,8 +351,7 @@ class _ExpandableListState extends State<ExpandableList> {
'has_hypo': state?.hypoFormController,
'has_hyper': state?.hyperFormController,
'activity_coefficient':
determineActivityFactor(state?.selectedActivity ?? 'сидячий')
.toString,
determineActivityFactor(state?.selectedActivity ?? 'сидячий'),
};
final box = await Hive.openBox('token');
final token = box.get('token');