forked from eatvio/eatvio_app
Error state added. Error display added for profile. Carousel in a separate function
This commit is contained in:
@@ -17,9 +17,10 @@ class MyProfileBloc extends Bloc<MyProfileEvent, MyProfileState> {
|
||||
}
|
||||
|
||||
Future<void> _onInitialize(
|
||||
MyProfileInitialEvent event,
|
||||
Emitter<MyProfileState> emit,
|
||||
) async {
|
||||
MyProfileInitialEvent event,
|
||||
Emitter<MyProfileState> emit,
|
||||
) async {
|
||||
try {
|
||||
final box = await Hive.openBox('token');
|
||||
final token = box.get('token');
|
||||
final response = await http.get(
|
||||
@@ -28,36 +29,58 @@ class MyProfileBloc extends Bloc<MyProfileEvent, MyProfileState> {
|
||||
'Authorization': 'Bearer $token',
|
||||
},
|
||||
);
|
||||
final data = jsonDecode(response.body);
|
||||
|
||||
if (state is MyProfileLoadedState) {
|
||||
// Если текущее состояние уже загружено, обновляем его
|
||||
emit((state as MyProfileLoadedState).copyWith(
|
||||
user: data['user'],
|
||||
userDetails: data['userDetails'],
|
||||
token: token,
|
||||
chartPoints: data['chartPoints'],
|
||||
plans: data['plans'],
|
||||
chestCircumferenceController: TextEditingController(),
|
||||
waistCircumferenceController: TextEditingController(),
|
||||
hipCircumferenceController: TextEditingController(),
|
||||
weightController: TextEditingController(),
|
||||
circumferences: data['circumferences'],
|
||||
));
|
||||
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('plans') &&
|
||||
data.containsKey('circumferences')) {
|
||||
// Все ключевые поля присутствуют, продолжаем обработку
|
||||
if (state is MyProfileLoadedState) {
|
||||
// Если текущее состояние уже загружено, обновляем его
|
||||
emit((state as MyProfileLoadedState).copyWith(
|
||||
user: data['user'],
|
||||
userDetails: data['userDetails'],
|
||||
token: token,
|
||||
chartPoints: data['chartPoints'],
|
||||
plans: data['plans'],
|
||||
chestCircumferenceController: TextEditingController(),
|
||||
waistCircumferenceController: TextEditingController(),
|
||||
hipCircumferenceController: TextEditingController(),
|
||||
weightController: TextEditingController(),
|
||||
circumferences: data['circumferences'],
|
||||
));
|
||||
} else {
|
||||
// Если текущее состояние - начальное, создаем новое загруженное состояние
|
||||
emit(MyProfileLoadedState(
|
||||
user: data['user'],
|
||||
userDetails: data['userDetails'],
|
||||
token: token,
|
||||
chartPoints: data['chartPoints'],
|
||||
plans: data['plans'],
|
||||
chestCircumferenceController: TextEditingController(),
|
||||
waistCircumferenceController: TextEditingController(),
|
||||
hipCircumferenceController: TextEditingController(),
|
||||
weightController: TextEditingController(),
|
||||
circumferences: data['circumferences'],
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// Один или несколько ключевых полей отсутствуют, обрабатываем ошибку
|
||||
emit(MyProfileErrorState('Некоторые необходимые данные отсутствуют.'));
|
||||
}
|
||||
} else {
|
||||
// Если текущее состояние - начальное, создаем новое загруженное состояние
|
||||
emit(MyProfileLoadedState(
|
||||
user: data['user'],
|
||||
userDetails: data['userDetails'],
|
||||
token: token,
|
||||
chartPoints: data['chartPoints'],
|
||||
plans: data['plans'],
|
||||
chestCircumferenceController: TextEditingController(),
|
||||
waistCircumferenceController: TextEditingController(),
|
||||
hipCircumferenceController: TextEditingController(),
|
||||
weightController: TextEditingController(),
|
||||
circumferences: data['circumferences'],
|
||||
));
|
||||
// Статус ответа не равен 200, обрабатываем ошибку
|
||||
emit(MyProfileErrorState('Ошибка сервера: ${response.statusCode}'));
|
||||
}
|
||||
} catch (e) {
|
||||
// Ошибка при декодировании JSON или другая ошибка выполнения
|
||||
emit(MyProfileErrorState('Ошибка при получении данных профиля: $e'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,3 +85,11 @@ class MyProfileLoadedState extends MyProfileState {
|
||||
}
|
||||
}
|
||||
|
||||
class MyProfileErrorState extends MyProfileState {
|
||||
final String errorMessage;
|
||||
|
||||
const MyProfileErrorState(this.errorMessage);
|
||||
|
||||
@override
|
||||
List<Object> get props => [errorMessage];
|
||||
}
|
||||
@@ -38,6 +38,10 @@ class MyProfileScreen extends StatelessWidget {
|
||||
} else if (state is MyProfileLoadedState) {
|
||||
// Данные загружены, можно строить экран.
|
||||
return _buildMyProfileScreen(context, state);
|
||||
}
|
||||
else if (state is MyProfileErrorState) {
|
||||
// Произошла ошибка при загрузке данных.
|
||||
return Center(child: Text(state.errorMessage));
|
||||
} else {
|
||||
// Другие состояния, если они есть.
|
||||
return Container(); // Пустой контейнер для необработанных состояний.
|
||||
@@ -65,7 +69,85 @@ class MyProfileScreen extends StatelessWidget {
|
||||
SizedBox(height: 15.v),
|
||||
_buildSettings(context),
|
||||
SizedBox(height: 30.v),
|
||||
CarouselSlider(
|
||||
_buildCarousel(context, state),
|
||||
SizedBox(height: 15.v),
|
||||
_buildPlans(
|
||||
context,
|
||||
state.plans?.map((plan) => plan['name']).toList(),
|
||||
state.plans?.map((plan) => plan['image']).toList(),
|
||||
state.plans?.map((plan) => plan['state']).toList(),
|
||||
),
|
||||
SizedBox(height: 5.v),
|
||||
])),
|
||||
bottomNavigationBar: _buildBottomBar(context)));
|
||||
}
|
||||
|
||||
/// Section Widget
|
||||
PreferredSizeWidget _buildAppBar(BuildContext context, String username) {
|
||||
return CustomAppBar(
|
||||
height: 54.v,
|
||||
leadingWidth: 28.h,
|
||||
title: Padding(
|
||||
padding: EdgeInsets.only(left: 20.h),
|
||||
child: Row(children: [
|
||||
AppbarTitleCircleimage(imagePath: ImageConstant.imgEllipse1),
|
||||
AppbarSubtitle(
|
||||
text: username,
|
||||
margin: EdgeInsets.only(left: 35.h, top: 12.v, bottom: 9.v))
|
||||
])),
|
||||
actions: [
|
||||
ExitButton(
|
||||
text: "exit".tr,
|
||||
margin: EdgeInsets.symmetric(horizontal: 16.h, vertical: 17.v),
|
||||
onTap: () {},
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
/// Section Widget
|
||||
Widget _buildMyBlog(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 7.h),
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
CustomImageView(
|
||||
imagePath: ImageConstant.imgGrid,
|
||||
height: 24.adaptSize,
|
||||
width: 24.adaptSize,
|
||||
margin: EdgeInsets.symmetric(vertical: 3.v)),
|
||||
Expanded(
|
||||
child: NextStepButton(
|
||||
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
|
||||
text: "my_blog".tr.toUpperCase(),
|
||||
margin: EdgeInsets.only(left: 10.h)))
|
||||
]));
|
||||
}
|
||||
|
||||
/// Section Widget
|
||||
Widget _buildSettings(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 7.h),
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
CustomImageView(
|
||||
imagePath: ImageConstant.imgSearch,
|
||||
height: 24.adaptSize,
|
||||
width: 24.adaptSize,
|
||||
margin: EdgeInsets.symmetric(vertical: 3.v)),
|
||||
Expanded(
|
||||
child: NextStepButton(
|
||||
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, AppRoutes.mySettings);
|
||||
},
|
||||
text: "my_settings".tr.toUpperCase(),
|
||||
margin: EdgeInsets.only(left: 10.h))),
|
||||
]));
|
||||
}
|
||||
|
||||
Widget _buildBottomBar(BuildContext context) {
|
||||
return CustomBottomBar(onChanged: (BottomBarEnum type) {});
|
||||
}
|
||||
Widget _buildCarousel(BuildContext contex, MyProfileLoadedState state){
|
||||
return CarouselSlider(
|
||||
options: CarouselOptions(height: 375.0),
|
||||
items: [1, 2, 3].map((chartType) {
|
||||
return Builder(
|
||||
@@ -154,84 +236,8 @@ class MyProfileScreen extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
SizedBox(height: 15.v),
|
||||
_buildPlans(
|
||||
context,
|
||||
state.plans?.map((plan) => plan['name']).toList(),
|
||||
state.plans?.map((plan) => plan['image']).toList(),
|
||||
state.plans?.map((plan) => plan['state']).toList(),
|
||||
),
|
||||
SizedBox(height: 5.v),
|
||||
])),
|
||||
bottomNavigationBar: _buildBottomBar(context)));
|
||||
);
|
||||
}
|
||||
|
||||
/// Section Widget
|
||||
PreferredSizeWidget _buildAppBar(BuildContext context, String username) {
|
||||
return CustomAppBar(
|
||||
height: 54.v,
|
||||
leadingWidth: 28.h,
|
||||
title: Padding(
|
||||
padding: EdgeInsets.only(left: 20.h),
|
||||
child: Row(children: [
|
||||
AppbarTitleCircleimage(imagePath: ImageConstant.imgEllipse1),
|
||||
AppbarSubtitle(
|
||||
text: username,
|
||||
margin: EdgeInsets.only(left: 35.h, top: 12.v, bottom: 9.v))
|
||||
])),
|
||||
actions: [
|
||||
ExitButton(
|
||||
text: "exit".tr,
|
||||
margin: EdgeInsets.symmetric(horizontal: 16.h, vertical: 17.v),
|
||||
onTap: () {},
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
/// Section Widget
|
||||
Widget _buildMyBlog(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 7.h),
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
CustomImageView(
|
||||
imagePath: ImageConstant.imgGrid,
|
||||
height: 24.adaptSize,
|
||||
width: 24.adaptSize,
|
||||
margin: EdgeInsets.symmetric(vertical: 3.v)),
|
||||
Expanded(
|
||||
child: NextStepButton(
|
||||
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
|
||||
text: "my_blog".tr.toUpperCase(),
|
||||
margin: EdgeInsets.only(left: 10.h)))
|
||||
]));
|
||||
}
|
||||
|
||||
/// Section Widget
|
||||
Widget _buildSettings(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 7.h),
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
CustomImageView(
|
||||
imagePath: ImageConstant.imgSearch,
|
||||
height: 24.adaptSize,
|
||||
width: 24.adaptSize,
|
||||
margin: EdgeInsets.symmetric(vertical: 3.v)),
|
||||
Expanded(
|
||||
child: NextStepButton(
|
||||
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, AppRoutes.mySettings);
|
||||
},
|
||||
text: "my_settings".tr.toUpperCase(),
|
||||
margin: EdgeInsets.only(left: 10.h))),
|
||||
]));
|
||||
}
|
||||
|
||||
Widget _buildBottomBar(BuildContext context) {
|
||||
return CustomBottomBar(onChanged: (BottomBarEnum type) {});
|
||||
}
|
||||
|
||||
Widget _buildChartLegend() {
|
||||
final colors = [Colors.pink, Colors.green, Colors.purple];
|
||||
final titles = ["chest".tr, "waist".tr, "hips".tr];
|
||||
@@ -666,13 +672,13 @@ class MyProfileScreen extends StatelessWidget {
|
||||
case 'active':
|
||||
boxColor = appTheme.greenA700;
|
||||
break;
|
||||
case 'archived':
|
||||
case 'archived': // График ИМТ
|
||||
boxColor = appTheme.gray400;
|
||||
break;
|
||||
case 'draft':
|
||||
boxColor = appTheme.deepOrange900;
|
||||
break;
|
||||
case 'in_progress':
|
||||
case 'in_progress': //График обхватов
|
||||
boxColor = appTheme.lightGreen300;
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user