diff --git a/lib/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart b/lib/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart index b64269ca..8c3db0f2 100644 --- a/lib/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart +++ b/lib/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart @@ -17,9 +17,10 @@ class MyProfileBloc extends Bloc { } Future _onInitialize( - MyProfileInitialEvent event, - Emitter emit, - ) async { + MyProfileInitialEvent event, + Emitter 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 { '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 && + 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')); } +} } \ No newline at end of file diff --git a/lib/presentation/profile/my_profile_screen/bloc/my_profile_state.dart b/lib/presentation/profile/my_profile_screen/bloc/my_profile_state.dart index 8f46f094..080deb63 100644 --- a/lib/presentation/profile/my_profile_screen/bloc/my_profile_state.dart +++ b/lib/presentation/profile/my_profile_screen/bloc/my_profile_state.dart @@ -85,3 +85,11 @@ class MyProfileLoadedState extends MyProfileState { } } +class MyProfileErrorState extends MyProfileState { + final String errorMessage; + + const MyProfileErrorState(this.errorMessage); + + @override + List get props => [errorMessage]; +} \ No newline at end of file diff --git a/lib/presentation/profile/my_profile_screen/my_profile_screen.dart b/lib/presentation/profile/my_profile_screen/my_profile_screen.dart index 44c6b86f..969c5ab9 100644 --- a/lib/presentation/profile/my_profile_screen/my_profile_screen.dart +++ b/lib/presentation/profile/my_profile_screen/my_profile_screen.dart @@ -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; }