diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml
index 75372b09..fd291367 100644
--- a/.gitea/workflows/test.yml
+++ b/.gitea/workflows/test.yml
@@ -3,7 +3,7 @@ name: Eatvio App Android Test
on: [ pull_request ]
env:
- flutter_version: "3.32.5"
+ flutter_version: "3.32.8"
java_version: "21.x"
flutter_channel: "stable"
my_local_cache_dir: "/opt/hostedtoolcache/"
diff --git a/android/app/build.gradle b/android/app/build.gradle
index a5377cc6..c9fe6d27 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -19,17 +19,17 @@ android {
ndkVersion = "27.0.12077973"
compileOptions {
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
- jvmTarget = 21
+ jvmTarget = JavaVersion.VERSION_11.toString()
}
defaultConfig {
applicationId = "com.eatvioapp.app"
- minSdk = flutter.minSdkVersion
+ minSdk = 23
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
diff --git a/android/gradle.properties b/android/gradle.properties
index 25971708..f018a618 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,3 +1,3 @@
-org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
+org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index f587a472..ac3b4792 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
diff --git a/android/settings.gradle b/android/settings.gradle
index 833c476b..29eab0d3 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -22,7 +22,7 @@ plugins {
// START: FlutterFire Configuration
id "com.google.gms.google-services" version "4.4.2" apply false
// END: FlutterFire Configuration
- id "org.jetbrains.kotlin.android" version "2.0.21" apply false
+ id "org.jetbrains.kotlin.android" version "2.1.0" apply false
}
include ":app"
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 23adc916..9a27847e 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -396,7 +396,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 62;
+ CURRENT_PROJECT_VERSION = 64;
DEVELOPMENT_TEAM = VL68C36HYS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@@ -546,7 +546,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 62;
+ CURRENT_PROJECT_VERSION = 64;
DEVELOPMENT_TEAM = VL68C36HYS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@@ -584,7 +584,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 62;
+ CURRENT_PROJECT_VERSION = 64;
DEVELOPMENT_TEAM = VL68C36HYS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index f5570627..2341e63f 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -21,7 +21,7 @@
CFBundleSignature
????
CFBundleVersion
- 62
+ 64
ITSAppUsesNonExemptEncryption
LSRequiresIPhoneOS
diff --git a/lib/core/const.dart b/lib/core/const.dart
index 31c47e9c..f22f79aa 100644
--- a/lib/core/const.dart
+++ b/lib/core/const.dart
@@ -1,5 +1,5 @@
String baseUrl = 'https://eatvio.ru';
-// String baseUrl = 'https://dev2.eatvio.com';
+bool hidePlans = true;
const List durationValues = [7, 14, 21];
diff --git a/lib/features/create_recipe/reporitories/recipe_repository.dart b/lib/features/create_recipe/reporitories/recipe_repository.dart
index f0f860e9..289233a2 100644
--- a/lib/features/create_recipe/reporitories/recipe_repository.dart
+++ b/lib/features/create_recipe/reporitories/recipe_repository.dart
@@ -57,7 +57,7 @@ class RecipeRepository {
'type': recipe.type,
'state': 'active',
'title': recipe.title,
- 'tags': recipe.tags,
+ 'tags[]': recipe.tags ?? [],
'description_md': recipe.description,
'video_url': recipe.videoUrl,
'ingredients': ingredientsMap,
diff --git a/lib/features/diary/presentation/bloc/diary_cubit.dart b/lib/features/diary/presentation/bloc/diary_cubit.dart
index 9fd27c39..1bbfbbc7 100644
--- a/lib/features/diary/presentation/bloc/diary_cubit.dart
+++ b/lib/features/diary/presentation/bloc/diary_cubit.dart
@@ -243,6 +243,7 @@ class DiaryCubit extends Cubit {
required int quantity,
int? productNutritionalValueId,
}) async {
+ emit((state as DiaryStateLoaded).copyWith(isLoadingAddingProductInMeal: true));
await diaryRepository.addPortionToMeal(
diaryId: diaryId,
mealId: mealId,
diff --git a/lib/features/diary/presentation/bloc/diary_state.dart b/lib/features/diary/presentation/bloc/diary_state.dart
index d5e8e39d..4779e2ea 100644
--- a/lib/features/diary/presentation/bloc/diary_state.dart
+++ b/lib/features/diary/presentation/bloc/diary_state.dart
@@ -29,6 +29,7 @@ abstract class DiaryState with _$DiaryState {
@Default(false) bool isDiaryCommented,
@Default(false) bool isWakeUpAndRetireEnabled,
@Default(false) bool isMoodEnabled,
+ @Default(false) bool isLoadingAddingProductInMeal,
}) = DiaryStateLoaded;
const factory DiaryState.loadedTomorrowWithDiet({
diff --git a/lib/features/diary/presentation/widgets/product_loader_widget.dart b/lib/features/diary/presentation/widgets/product_loader_widget.dart
new file mode 100644
index 00000000..7b679354
--- /dev/null
+++ b/lib/features/diary/presentation/widgets/product_loader_widget.dart
@@ -0,0 +1,26 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+
+class ProductLoaderWidget extends StatefulWidget {
+ const ProductLoaderWidget({
+ super.key,
+ });
+
+ @override
+ State createState() => _ProductLoaderWidgetState();
+}
+
+class _ProductLoaderWidgetState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return ListTile(
+ horizontalTitleGap: 0,
+ contentPadding: const EdgeInsets.only(right: 24, left: 12),
+ title: const CupertinoActivityIndicator(),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(20),
+ ),
+ tileColor: const Color(0xFFF6FAFF),
+ );
+ }
+}
diff --git a/lib/features/diary/presentation/widgets/products_list_widget.dart b/lib/features/diary/presentation/widgets/products_list_widget.dart
index 13bbe7fc..6882af08 100644
--- a/lib/features/diary/presentation/widgets/products_list_widget.dart
+++ b/lib/features/diary/presentation/widgets/products_list_widget.dart
@@ -1,5 +1,6 @@
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
+import 'package:eatvio_app/features/diary/presentation/widgets/product_loader_widget.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/product_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -25,6 +26,11 @@ class _ProductsListWidgetState extends State {
ProductWidget(portion: state.diary.meals[mealIndex].portions[i]),
i < state.diary.meals[mealIndex].portions.length - 1 ? const SizedBox(height: 8) : const SizedBox.shrink(),
],
+ if (state.isLoadingAddingProductInMeal)
+ const Padding(
+ padding: EdgeInsets.only(top: 8),
+ child: ProductLoaderWidget(),
+ ),
],
);
}
diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart
index b6869040..ce29b884 100644
--- a/lib/features/feed/presentation/pages/feed_screen.dart
+++ b/lib/features/feed/presentation/pages/feed_screen.dart
@@ -1,4 +1,5 @@
import 'package:easy_debounce/easy_debounce.dart';
+import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/widgets/add_item_button.dart';
import 'package:eatvio_app/core/widgets/custom_search_bar.dart';
import 'package:eatvio_app/features/create_diet/presentation/create_diet_screen.dart';
@@ -32,24 +33,12 @@ class FeedScreen extends StatelessWidget {
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
- BlocProvider(
- create: (context) => sl()..loadRecipesList(),
- ),
- BlocProvider(
- create: (context) => sl()..getProfile(),
- ),
- BlocProvider(
- create: (context) => sl()..loadFeedBlogPostList(),
- ),
- BlocProvider(
- create: (context) => sl()..loadDiets(),
- ),
- BlocProvider(
- create: (context) => sl()..loadPlans(),
- ),
- BlocProvider(
- create: (context) => sl()..getConsultants(),
- ),
+ BlocProvider(create: (context) => sl()..loadRecipesList()),
+ BlocProvider(create: (context) => sl()..getProfile()),
+ BlocProvider(create: (context) => sl()..loadFeedBlogPostList()),
+ BlocProvider(create: (context) => sl()..loadDiets()),
+ if (!hidePlans) BlocProvider(create: (context) => sl()..loadPlans()),
+ BlocProvider(create: (context) => sl()..getConsultants()),
],
child: const FeedScreenContent(),
);
@@ -69,7 +58,8 @@ class _FeedScreenContentState extends State {
final dietsController = TextEditingController();
final plansController = TextEditingController();
final consultantsController = TextEditingController();
- final List chipsLabelList = ['Все', 'Рецепты', 'Диеты', 'Планы питания', 'Консультанты'];
+
+ late final List chipsLabelList;
int _selectedChipIndex = 0;
final blogPostsScrollController = ScrollController();
final recipesScrollController = ScrollController();
@@ -78,12 +68,13 @@ class _FeedScreenContentState extends State {
final consultantsScrollController = ScrollController();
@override
- void initState() {
+ void initState() {
+ // Initialize chipsLabelList based on hidePlans setting
+ chipsLabelList = hidePlans ? ['Все', 'Рецепты', 'Диеты', 'Консультанты'] : ['Все', 'Рецепты', 'Диеты', 'Планы питания', 'Консультанты'];
+
consultantsScrollController.addListener(_onScrollConsultants);
super.initState();
- }
-
-
+ }
void _onScrollConsultants() {
if (consultantsScrollController.offset >= consultantsScrollController.position.maxScrollExtent && !consultantsScrollController.position.outOfRange) {}
@@ -108,45 +99,36 @@ class _FeedScreenContentState extends State {
heroTag: 'recipesTagsFilter',
backgroundColor: appTheme.blueA400,
shape: const CircleBorder(),
- child: const Icon(
- Icons.filter_list_rounded,
- color: Colors.white,
- ),
+ child: const Icon(Icons.filter_list_rounded, color: Colors.white),
onPressed: () async {
final recipesCubit = context.read();
await showModalBottomSheet(
useRootNavigator: true,
context: context,
- builder: (context) => TagsModalWidget(
- recipesCubit: recipesCubit,
- ),
+ builder: (context) => TagsModalWidget(recipesCubit: recipesCubit),
);
recipesCubit.loadRecipesList();
},
)
: null,
- appBar: AppBar(
- backgroundColor: Colors.white,
- toolbarHeight: 0,
- ),
+ appBar: AppBar(backgroundColor: Colors.white, toolbarHeight: 0),
backgroundColor: Colors.grey.shade200,
body: NestedScrollView(
controller: switch (_selectedChipIndex) {
0 => blogPostsScrollController,
1 => recipesScrollController,
2 => dietsScrollController,
- 3 => plansScrollController,
- 4 => consultantsScrollController,
- _ => blogPostsScrollController
+ 3 when !hidePlans => plansScrollController,
+ 3 when hidePlans => consultantsScrollController,
+ 4 when !hidePlans => consultantsScrollController,
+ _ => blogPostsScrollController,
},
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
BlocBuilder(
builder: (context, state) {
return SliverAppBar(
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.vertical(bottom: Radius.circular(12)),
- ),
+ shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(bottom: Radius.circular(12))),
backgroundColor: Colors.white,
foregroundColor: Colors.white,
automaticallyImplyLeading: false,
@@ -172,78 +154,71 @@ class _FeedScreenContentState extends State {
searchController: switch (_selectedChipIndex) {
1 => recipesController,
2 => dietsController,
- 3 => plansController,
- 4 => consultantsController,
+ 3 when !hidePlans => plansController,
+ 3 when hidePlans => consultantsController,
+ 4 when !hidePlans => consultantsController,
_ => postsController,
},
onChanged: (query) {
if (query.length > 2) {
- EasyDebounce.debounce(
- 'searchFeed',
- const Duration(milliseconds: 500),
- () {
- switch (_selectedChipIndex) {
- case 0:
- context.read().loadFeedBlogPostList(query: query);
- break;
- case 1:
- context.read().loadRecipesList(query: query);
- break;
- case 2:
- context.read().loadDiets(query: query);
- break;
- case 3:
- context.read().loadPlans(query: query);
- break;
- case 4:
- context.read().getConsultants();
- break;
- }
- },
- );
+ EasyDebounce.debounce('searchFeed', const Duration(milliseconds: 500), () {
+ switch (_selectedChipIndex) {
+ case 0:
+ context.read().loadFeedBlogPostList(query: query);
+ break;
+ case 1:
+ context.read().loadRecipesList(query: query);
+ break;
+ case 2:
+ context.read().loadDiets(query: query);
+ break;
+ case 3 when !hidePlans:
+ context.read().loadPlans(query: query);
+ break;
+ case 3 when hidePlans:
+ case 4 when !hidePlans:
+ context.read().getConsultants();
+ break;
+ }
+ });
} else {
- EasyDebounce.debounce(
- 'searchFeed',
- const Duration(milliseconds: 500),
- () {
- switch (_selectedChipIndex) {
- case 0:
- context.read().loadFeedBlogPostList();
- break;
- case 1:
- context.read().loadRecipesList();
- break;
- case 2:
- context.read().loadDiets();
- break;
- case 3:
- context.read().loadPlans();
- break;
- case 4:
- context.read().getConsultants();
- break;
- }
- },
- );
+ EasyDebounce.debounce('searchFeed', const Duration(milliseconds: 500), () {
+ switch (_selectedChipIndex) {
+ case 0:
+ context.read().loadFeedBlogPostList();
+ break;
+ case 1:
+ context.read().loadRecipesList();
+ break;
+ case 2:
+ context.read().loadDiets();
+ break;
+ case 3 when !hidePlans:
+ context.read().loadPlans();
+ break;
+ case 3 when hidePlans:
+ case 4 when !hidePlans:
+ context.read().getConsultants();
+ break;
+ }
+ });
}
},
),
const SizedBox(width: 12),
switch (_selectedChipIndex) {
- 1 => AddItemButton(
- onTap: () => GoRouter.of(context).pushNamed(RecipeCreateScreen.name),
- ),
+ 1 => AddItemButton(onTap: () => GoRouter.of(context).pushNamed(RecipeCreateScreen.name)),
2 => AddItemButton(
- onTap: state.profile?.roles.contains('consultant') ?? false
- ? () async {
- await GoRouter.of(context).pushNamed(CreateDietScreen.name);
- }
- : null,
- ),
- 3 => AddItemButton(
- onTap: state.profile?.roles.contains('consultant') ?? false ? () => GoRouter.of(context).pushNamed(CreatePlanScreen.name) : null,
- ),
- _ => const AddItemButton()
+ onTap: state.profile?.roles.contains('consultant') ?? false
+ ? () async {
+ await GoRouter.of(context).pushNamed(CreateDietScreen.name);
+ }
+ : null,
+ ),
+ 3 when !hidePlans => AddItemButton(
+ onTap: state.profile?.roles.contains('consultant') ?? false ? () => GoRouter.of(context).pushNamed(CreatePlanScreen.name) : null,
+ ),
+ _ => const AddItemButton(),
},
],
),
@@ -256,8 +231,9 @@ class _FeedScreenContentState extends State {
0 => const BlogPosts(),
1 => const Recipes(),
2 => const Diets(),
- 3 => const Plans(),
- 4 => const Consultants(),
+ 3 when !hidePlans => const Plans(),
+ 3 when hidePlans => const Consultants(),
+ 4 when !hidePlans => const Consultants(),
_ => Center(child: Text(chipsLabelList[_selectedChipIndex])),
},
),
diff --git a/lib/features/feed/presentation/widgets/chip_group.dart b/lib/features/feed/presentation/widgets/chip_group.dart
index a8d88da1..183a5a76 100644
--- a/lib/features/feed/presentation/widgets/chip_group.dart
+++ b/lib/features/feed/presentation/widgets/chip_group.dart
@@ -2,12 +2,7 @@ import 'package:eatvio_app/features/feed/presentation/widgets/choice_chip_widget
import 'package:flutter/widgets.dart';
class ChipGroup extends StatelessWidget {
- const ChipGroup({
- super.key,
- required this.selectedChipIndex,
- required this.chipsLabelList,
- required this.setSelectedChipIndex,
- });
+ const ChipGroup({super.key, required this.selectedChipIndex, required this.chipsLabelList, required this.setSelectedChipIndex});
final int selectedChipIndex;
final List chipsLabelList;
final void Function(int) setSelectedChipIndex;
@@ -22,7 +17,7 @@ class ChipGroup extends StatelessWidget {
child: Row(
children: [
...List.generate(
- 5,
+ chipsLabelList.length,
(index) => Padding(
padding: const EdgeInsets.only(right: 8.0),
child: ChoiceChipWidget(
diff --git a/lib/features/profile/models/profile_model.dart b/lib/features/profile/models/profile_model.dart
index 72e91d0d..f798021f 100644
--- a/lib/features/profile/models/profile_model.dart
+++ b/lib/features/profile/models/profile_model.dart
@@ -14,6 +14,7 @@ abstract class ProfileModel with _$ProfileModel {
@JsonKey(name: "email") required String email,
@JsonKey(name: "rating_place") int? ratingPlace,
@JsonKey(name: "email_verified_at") DateTime? emailVerifiedAt,
+ @JsonKey(name: "phone_confirmation_state") required String phoneConfirmationState,
@JsonKey(name: "created_at") DateTime? createdAt,
@JsonKey(name: "updated_at") DateTime? updatedAt,
@JsonKey(name: "is_public_profile", fromJson: parseBool) required bool isPublicProfile,
diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart
index 07ab1bd2..211543a9 100644
--- a/lib/features/profile/presentation/pages/profile_screen.dart
+++ b/lib/features/profile/presentation/pages/profile_screen.dart
@@ -45,10 +45,7 @@ import 'package:url_launcher/url_launcher.dart';
class ProfileScreen extends StatefulWidget {
final Author? author;
- const ProfileScreen({
- super.key,
- this.author,
- });
+ const ProfileScreen({super.key, this.author});
@override
State createState() => _ProfileScreenState();
@@ -91,7 +88,7 @@ class _ProfileScreenState extends State {
}
if (isFirstFetch) {
canSub = !state.profile.isEntitySubscribedByMe;
- if (state.profile.roles.contains('consultant')) {
+ if (state.profile.roles.contains('consultant') && !hidePlans) {
plansCubit.getPlans(state.profile.slug);
}
isFirstFetch = false;
@@ -109,10 +106,7 @@ class _ProfileScreenState extends State {
),
);
} else {
- return Scaffold(
- appBar: AppBar(),
- body: const Loader(),
- );
+ return Scaffold(appBar: AppBar(), body: const Loader());
}
},
),
@@ -130,15 +124,13 @@ class _ProfileScreenState extends State {
Container(
decoration: const BoxDecoration(
color: Colors.white,
- borderRadius: BorderRadius.vertical(
- bottom: Radius.circular(16),
- ),
+ borderRadius: BorderRadius.vertical(bottom: Radius.circular(16)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_header(state),
- if (state.profile.roles.contains('consultant'))
+ if (state.profile.roles.contains('consultant') && state.consultantInfo != null)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -147,28 +139,15 @@ class _ProfileScreenState extends State {
const SizedBox(width: 16),
const Text(
'Консультант',
- style: TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w600,
- color: Color(
- 0xFF323F4B,
- ),
- ),
+ style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF323F4B)),
),
const SizedBox(width: 12),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
- decoration: BoxDecoration(
- color: const Color(0xFFF6FAFF),
- borderRadius: BorderRadius.circular(12),
- ),
+ decoration: BoxDecoration(color: const Color(0xFFF6FAFF), borderRadius: BorderRadius.circular(12)),
child: Text(
'${state.consultantInfo!.ratingPlace}-й в рейтинге',
- style: TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w600,
- color: appTheme.blueA400,
- ),
+ style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: appTheme.blueA400),
),
),
],
@@ -177,17 +156,10 @@ class _ProfileScreenState extends State {
const Row(
children: [
SizedBox(width: 16),
- Icon(
- Icons.done_rounded,
- color: Colors.green,
- ),
+ Icon(Icons.done_rounded, color: Colors.green),
Text(
'Медицинское образование',
- style: TextStyle(
- color: Color(0xFF323F4B),
- fontSize: 14,
- fontWeight: FontWeight.w600,
- ),
+ style: TextStyle(color: Color(0xFF323F4B), fontSize: 14, fontWeight: FontWeight.w600),
),
],
),
@@ -202,10 +174,10 @@ class _ProfileScreenState extends State {
),
_subscriptionsAndSubscribers(state),
if (state.profile.badges.isNotEmpty) Padding(padding: const EdgeInsets.only(bottom: 16), child: _badges(state)),
- if (state.profile.roles.contains('consultant')) _socialLinks(state),
- if (state.profile.roles.contains('consultant')) _education(state),
- if (state.profile.roles.contains('consultant')) _diplomasAndCertificates(state),
- if (state.profile.roles.contains('consultant')) _activePlans(state),
+ if (state.profile.roles.contains('consultant') && state.consultantInfo != null) _socialLinks(state),
+ if (state.profile.roles.contains('consultant') && state.consultantInfo != null) _education(state),
+ if (state.profile.roles.contains('consultant') && state.consultantInfo != null) _diplomasAndCertificates(state),
+ if (state.profile.roles.contains('consultant') && state.consultantInfo != null && !hidePlans) _activePlans(state),
_blogPosts(state),
],
),
@@ -216,7 +188,7 @@ class _ProfileScreenState extends State {
Scaffold _myProfileScreen(ProfileStateLoaded state) {
return Scaffold(
backgroundColor: Colors.grey.shade200,
- appBar: AppBar(),
+ appBar: AppBar(toolbarHeight: widget.author == null ? 0 : null),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -224,9 +196,7 @@ class _ProfileScreenState extends State {
Container(
decoration: const BoxDecoration(
color: Colors.white,
- borderRadius: BorderRadius.vertical(
- bottom: Radius.circular(16),
- ),
+ borderRadius: BorderRadius.vertical(bottom: Radius.circular(16)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
@@ -241,28 +211,15 @@ class _ProfileScreenState extends State {
const SizedBox(width: 16),
const Text(
'Консультант',
- style: TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w600,
- color: Color(
- 0xFF323F4B,
- ),
- ),
+ style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF323F4B)),
),
const SizedBox(width: 12),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
- decoration: BoxDecoration(
- color: const Color(0xFFF6FAFF),
- borderRadius: BorderRadius.circular(12),
- ),
+ decoration: BoxDecoration(color: const Color(0xFFF6FAFF), borderRadius: BorderRadius.circular(12)),
child: Text(
'${state.consultantInfo!.ratingPlace}-й в рейтинге',
- style: TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w600,
- color: appTheme.blueA400,
- ),
+ style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: appTheme.blueA400),
),
),
],
@@ -271,17 +228,10 @@ class _ProfileScreenState extends State {
const Row(
children: [
SizedBox(width: 16),
- Icon(
- Icons.done_rounded,
- color: Colors.green,
- ),
+ Icon(Icons.done_rounded, color: Colors.green),
Text(
'Медицинское образование',
- style: TextStyle(
- color: Color(0xFF323F4B),
- fontSize: 14,
- fontWeight: FontWeight.w600,
- ),
+ style: TextStyle(color: Color(0xFF323F4B), fontSize: 14, fontWeight: FontWeight.w600),
),
],
),
@@ -297,7 +247,7 @@ class _ProfileScreenState extends State {
if (state.profile.roles.contains('consultant')) _education(state),
if (state.profile.roles.contains('consultant')) _diplomasAndCertificates(state),
Padding(padding: const EdgeInsets.only(bottom: 16), child: _charts()),
- if (state.profile.roles.contains('consultant')) _activePlans(state),
+ if (state.profile.roles.contains('consultant') && !hidePlans) _activePlans(state),
_newBlogPostButton(),
_blogPosts(state),
],
@@ -307,7 +257,7 @@ class _ProfileScreenState extends State {
}
Widget _activePlans(ProfileStateLoaded state) {
- if (!state.profile.roles.contains('consultant')) {
+ if (!state.profile.roles.contains('consultant') || hidePlans) {
return const SizedBox.shrink();
}
return BlocBuilder(
@@ -326,12 +276,7 @@ class _ProfileScreenState extends State {
children: [
Text(
'Активные планы',
- style: TextStyle(
- color: Color(0xFF323F4B),
- fontSize: 24,
- height: 1,
- fontWeight: FontWeight.w600,
- ),
+ style: TextStyle(color: Color(0xFF323F4B), fontSize: 24, height: 1, fontWeight: FontWeight.w600),
),
],
),
@@ -341,10 +286,7 @@ class _ProfileScreenState extends State {
height: 781,
child: PageView.builder(
itemBuilder: (BuildContext context, int index) {
- return PlanWidget(
- plan: state.plansList[index],
- index: index,
- );
+ return PlanWidget(plan: state.plansList[index], index: index);
},
onPageChanged: (bullet) {
setState(() {
@@ -368,17 +310,11 @@ class _ProfileScreenState extends State {
Container _bullets(int currentBullet, int bulletCount) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(20),
- ),
+ decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20)),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
- for (int i = 0; i < bulletCount; i++) ...[
- _bullet(i == currentBullet),
- i < bulletCount - 1 ? const SizedBox(width: 4) : const SizedBox.shrink(),
- ],
+ for (int i = 0; i < bulletCount; i++) ...[_bullet(i == currentBullet), i < bulletCount - 1 ? const SizedBox(width: 4) : const SizedBox.shrink()],
],
),
);
@@ -389,10 +325,7 @@ class _ProfileScreenState extends State {
width: isActive ? 10 : 8,
height: isActive ? 10 : 8,
duration: const Duration(milliseconds: 150),
- decoration: BoxDecoration(
- color: isActive ? appTheme.blueA400 : const Color(0xFFD7D9DC),
- shape: BoxShape.circle,
- ),
+ decoration: BoxDecoration(color: isActive ? appTheme.blueA400 : const Color(0xFFD7D9DC), shape: BoxShape.circle),
);
}
@@ -409,25 +342,15 @@ class _ProfileScreenState extends State {
borderRadius: BorderRadius.circular(8),
child: Ink(
padding: const EdgeInsets.all(12),
- decoration: BoxDecoration(
- color: const Color(0xFFF6FAFF),
- borderRadius: BorderRadius.circular(8),
- ),
+ decoration: BoxDecoration(color: const Color(0xFFF6FAFF), borderRadius: BorderRadius.circular(8)),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
- Icon(
- Icons.add_circle_outline_rounded,
- color: Color(0xFF2F80ED),
- ),
+ Icon(Icons.add_circle_outline_rounded, color: Color(0xFF2F80ED)),
SizedBox(width: 12),
Text(
'Новая запись',
- style: TextStyle(
- fontSize: 18,
- fontWeight: FontWeight.w600,
- color: Color(0xFF2F80ED),
- ),
+ style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xFF2F80ED)),
),
],
),
@@ -452,12 +375,7 @@ class _ProfileScreenState extends State {
children: [
const Text(
'Дипломы\nи сертификаты',
- style: TextStyle(
- color: Color(0xFF323F4B),
- fontSize: 24,
- height: 1,
- fontWeight: FontWeight.w600,
- ),
+ style: TextStyle(color: Color(0xFF323F4B), fontSize: 24, height: 1, fontWeight: FontWeight.w600),
),
GestureDetector(
onTap: () {
@@ -465,11 +383,7 @@ class _ProfileScreenState extends State {
},
child: Text(
widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '',
- style: const TextStyle(
- color: Color(0xFF2F80ED),
- fontSize: 16,
- fontWeight: FontWeight.w500,
- ),
+ style: const TextStyle(color: Color(0xFF2F80ED), fontSize: 16, fontWeight: FontWeight.w500),
),
),
],
@@ -489,17 +403,14 @@ class _ProfileScreenState extends State {
child: Row(
children: [
if (state.consultantInfo!.photos.isNotEmpty)
- ...List.generate(
- state.consultantInfo!.photos.length * 2 - 1,
- (index) {
- if (index.isEven) {
- final photo = state.consultantInfo!.photos[index ~/ 2];
- return _diplomaImage(photo.url);
- } else {
- return const SizedBox(width: 8);
- }
- },
- ),
+ ...List.generate(state.consultantInfo!.photos.length * 2 - 1, (index) {
+ if (index.isEven) {
+ final photo = state.consultantInfo!.photos[index ~/ 2];
+ return _diplomaImage(photo.url);
+ } else {
+ return const SizedBox(width: 8);
+ }
+ }),
],
),
),
@@ -513,24 +424,13 @@ class _ProfileScreenState extends State {
GestureDetector _diplomaImage(String url) {
return GestureDetector(
onTap: () {
- context.pushTransparentRoute(
- rootNavigator: true,
- PhotoViewScreen(
- imageUrls: [url],
- index: 0,
- ),
- );
+ context.pushTransparentRoute(rootNavigator: true, PhotoViewScreen(imageUrls: [url], index: 0));
},
child: Hero(
tag: url,
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
- child: CachedNetworkImage(
- imageUrl: url,
- fit: BoxFit.fitHeight,
- width: MediaQuery.of(context).size.width / 3 - (60 / 3),
- height: 160,
- ),
+ child: CachedNetworkImage(imageUrl: url, fit: BoxFit.fitHeight, width: MediaQuery.of(context).size.width / 3 - (60 / 3), height: 160),
),
),
);
@@ -553,11 +453,7 @@ class _ProfileScreenState extends State {
children: [
const Text(
'Образование',
- style: TextStyle(
- color: Color(0xFF323F4B),
- fontSize: 24,
- fontWeight: FontWeight.w600,
- ),
+ style: TextStyle(color: Color(0xFF323F4B), fontSize: 24, fontWeight: FontWeight.w600),
),
GestureDetector(
onTap: () {
@@ -565,11 +461,7 @@ class _ProfileScreenState extends State {
},
child: Text(
widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '',
- style: const TextStyle(
- color: Color(0xFF2F80ED),
- fontSize: 16,
- fontWeight: FontWeight.w500,
- ),
+ style: const TextStyle(color: Color(0xFF2F80ED), fontSize: 16, fontWeight: FontWeight.w500),
),
),
],
@@ -588,8 +480,10 @@ class _ProfileScreenState extends State {
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
- itemBuilder: (context, index) => _educationBlock(state.consultantInfo!.educationModel.completedCourses![index].values.first.title,
- state.consultantInfo!.educationModel.completedCourses![index].values.first.date),
+ itemBuilder: (context, index) => _educationBlock(
+ state.consultantInfo!.educationModel.completedCourses![index].values.first.title,
+ state.consultantInfo!.educationModel.completedCourses![index].values.first.date,
+ ),
separatorBuilder: (context, index) => const SizedBox(height: 8),
itemCount: state.consultantInfo!.educationModel.completedCourses!.length,
),
@@ -619,22 +513,12 @@ class _ProfileScreenState extends State {
children: [
Text(
title,
- style: const TextStyle(
- height: 1,
- color: Color(0xFF323F4B),
- fontWeight: FontWeight.w500,
- fontSize: 16,
- ),
+ style: const TextStyle(height: 1, color: Color(0xFF323F4B), fontWeight: FontWeight.w500, fontSize: 16),
),
const SizedBox(height: 4),
Text(
formattedDate,
- style: const TextStyle(
- height: 1,
- color: Color(0xFF6D6F71),
- fontWeight: FontWeight.w500,
- fontSize: 14,
- ),
+ style: const TextStyle(height: 1, color: Color(0xFF6D6F71), fontWeight: FontWeight.w500, fontSize: 14),
),
],
),
@@ -644,7 +528,7 @@ class _ProfileScreenState extends State {
}
SingleChildRenderObjectWidget _socialLinks(ProfileStateLoaded state) {
- if (!state.profile.roles.contains('consultant')) {
+ if (!state.profile.roles.contains('consultant') && state.consultantInfo != null) {
return const SizedBox.shrink();
}
return Padding(
@@ -658,12 +542,7 @@ class _ProfileScreenState extends State {
children: [
_socialLinkButton(
() {
- launchUrl(
- Uri.parse(
- state.consultantInfo!.educationModel.vkLink ?? '',
- ),
- mode: LaunchMode.externalApplication,
- );
+ launchUrl(Uri.parse(state.consultantInfo!.educationModel.vkLink ?? ''), mode: LaunchMode.externalApplication);
},
'assets/icons/vk.svg',
state.consultantInfo!.educationModel.vkLink!.isEmpty ? true : false,
@@ -671,12 +550,7 @@ class _ProfileScreenState extends State {
const SizedBox(width: 12),
_socialLinkButton(
() {
- launchUrl(
- Uri.parse(
- state.consultantInfo!.educationModel.tgLink ?? '',
- ),
- mode: LaunchMode.externalApplication,
- );
+ launchUrl(Uri.parse(state.consultantInfo!.educationModel.tgLink ?? ''), mode: LaunchMode.externalApplication);
},
'assets/icons/telegram.svg',
state.consultantInfo!.educationModel.tgLink!.isEmpty ? true : false,
@@ -684,12 +558,7 @@ class _ProfileScreenState extends State {
const SizedBox(width: 12),
_socialLinkButton(
() {
- launchUrl(
- Uri.parse(
- state.consultantInfo!.educationModel.personalSiteLink ?? '',
- ),
- mode: LaunchMode.externalApplication,
- );
+ launchUrl(Uri.parse(state.consultantInfo!.educationModel.personalSiteLink ?? ''), mode: LaunchMode.externalApplication);
},
'assets/icons/web.svg',
state.consultantInfo!.educationModel.personalSiteLink!.isEmpty ? true : false,
@@ -707,10 +576,7 @@ class _ProfileScreenState extends State {
borderRadius: BorderRadius.circular(20),
child: Ink(
width: MediaQuery.of(context).size.width / 3 - (56 / 3),
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(20),
- color: const Color(0xFFF6F6F6),
- ),
+ decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: const Color(0xFFF6F6F6)),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 16),
child: SvgPicture.asset(
@@ -732,20 +598,13 @@ class _ProfileScreenState extends State {
child: Ink(
padding: const EdgeInsets.all(8),
width: MediaQuery.of(context).size.width,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(12),
- color: Colors.white,
- ),
+ decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Достижения',
- style: TextStyle(
- color: Color(0xFF6D6F71),
- fontSize: 14,
- fontWeight: FontWeight.w600,
- ),
+ style: TextStyle(color: Color(0xFF6D6F71), fontSize: 14, fontWeight: FontWeight.w600),
),
const SizedBox(height: 8),
SingleChildScrollView(
@@ -757,51 +616,25 @@ class _ProfileScreenState extends State {
? Tooltip(
message: state.profile.badges[i].description,
triggerMode: TooltipTriggerMode.tap,
- textStyle: const TextStyle(
- color: Colors.black,
- fontSize: 16,
- fontWeight: FontWeight.w500,
- ),
+ textStyle: const TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
- boxShadow: [
- BoxShadow(
- color: Colors.black.withAlpha((255 * 0.2).toInt()),
- blurRadius: 32,
- )
- ],
- ),
- child: SvgPicture.network(
- '$baseUrl/storage/${state.profile.badges[i].image}',
- width: 40,
- height: 40,
+ boxShadow: [BoxShadow(color: Colors.black.withAlpha((255 * 0.2).toInt()), blurRadius: 32)],
),
+ child: SvgPicture.network('$baseUrl/storage/${state.profile.badges[i].image}', width: 40, height: 40),
)
: Tooltip(
message: state.profile.badges[i].description,
margin: const EdgeInsets.symmetric(horizontal: 32),
triggerMode: TooltipTriggerMode.tap,
- textStyle: const TextStyle(
- color: Colors.black,
- fontSize: 16,
- fontWeight: FontWeight.w500,
- ),
+ textStyle: const TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
- boxShadow: [
- BoxShadow(
- color: Colors.black.withAlpha((255 * 0.2).toInt()),
- blurRadius: 32,
- )
- ],
- ),
- child: CachedNetworkImage(
- imageUrl: '$baseUrl/storage/${state.profile.badges[i].image}',
- width: 40,
- height: 40,
+ boxShadow: [BoxShadow(color: Colors.black.withAlpha((255 * 0.2).toInt()), blurRadius: 32)],
),
+ child: CachedNetworkImage(imageUrl: '$baseUrl/storage/${state.profile.badges[i].image}', width: 40, height: 40),
),
i < state.profile.badges.length - 1 ? const SizedBox(width: 8) : const SizedBox.shrink(),
],
@@ -821,21 +654,12 @@ class _ProfileScreenState extends State {
child: Row(
children: [
InkWell(
- onTap: () => GoRouter.of(context).pushNamed(
- 'subsScreen',
- extra: SubType.subscriptions,
- pathParameters: {
- 'slug': state.profile.slug,
- },
- ),
+ onTap: () => GoRouter.of(context).pushNamed('subsScreen', extra: SubType.subscriptions, pathParameters: {'slug': state.profile.slug}),
borderRadius: BorderRadius.circular(12),
child: Ink(
padding: const EdgeInsets.all(8),
width: MediaQuery.of(context).size.width / 2 - 6,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(12),
- color: Colors.white,
- ),
+ decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
@@ -845,47 +669,27 @@ class _ProfileScreenState extends State {
children: [
const Text(
'Подписки',
- style: TextStyle(
- color: Color(0xFF6D6F71),
- fontSize: 14,
- fontWeight: FontWeight.w600,
- ),
+ style: TextStyle(color: Color(0xFF6D6F71), fontSize: 14, fontWeight: FontWeight.w600),
),
Text(
'${state.profile.subscriptions.length}',
- style: const TextStyle(
- color: Color(0xFF323F4B),
- fontSize: 22,
- fontWeight: FontWeight.w700,
- ),
+ style: const TextStyle(color: Color(0xFF323F4B), fontSize: 22, fontWeight: FontWeight.w700),
),
],
),
- Padding(
- padding: const EdgeInsets.only(right: 8),
- child: _miniAvatars(state.profile.subscriptions),
- ),
+ Padding(padding: const EdgeInsets.only(right: 8), child: _miniAvatars(state.profile.subscriptions)),
],
),
),
),
const SizedBox(width: 4),
InkWell(
- onTap: () => GoRouter.of(context).pushNamed(
- 'subsScreen',
- extra: SubType.subscribers,
- pathParameters: {
- 'slug': state.profile.slug,
- },
- ),
+ onTap: () => GoRouter.of(context).pushNamed('subsScreen', extra: SubType.subscribers, pathParameters: {'slug': state.profile.slug}),
borderRadius: BorderRadius.circular(12),
child: Ink(
padding: const EdgeInsets.all(8),
width: MediaQuery.of(context).size.width / 2 - 6,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(12),
- color: Colors.white,
- ),
+ decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
@@ -895,26 +699,15 @@ class _ProfileScreenState extends State {
children: [
const Text(
'Подписчики',
- style: TextStyle(
- color: Color(0xFF6D6F71),
- fontSize: 14,
- fontWeight: FontWeight.w600,
- ),
+ style: TextStyle(color: Color(0xFF6D6F71), fontSize: 14, fontWeight: FontWeight.w600),
),
Text(
'${state.profile.subscribers.length}',
- style: const TextStyle(
- color: Color(0xFF323F4B),
- fontSize: 22,
- fontWeight: FontWeight.w700,
- ),
+ style: const TextStyle(color: Color(0xFF323F4B), fontSize: 22, fontWeight: FontWeight.w700),
),
],
),
- Padding(
- padding: const EdgeInsets.only(right: 8),
- child: _miniAvatars(state.profile.subscribers),
- ),
+ Padding(padding: const EdgeInsets.only(right: 8), child: _miniAvatars(state.profile.subscribers)),
],
),
),
@@ -932,13 +725,7 @@ class _ProfileScreenState extends State {
for (int i = 0; i < maxLength; i++)
Align(
widthFactor: 0.8,
- child: CircleAvatar(
- radius: 14,
- foregroundImage: NetworkImage(
- urls[i],
- ),
- backgroundImage: const AssetImage('assets/images/no_avatar.png'),
- ),
+ child: CircleAvatar(radius: 14, foregroundImage: NetworkImage(urls[i]), backgroundImage: const AssetImage('assets/images/no_avatar.png')),
),
],
);
@@ -949,10 +736,7 @@ class _ProfileScreenState extends State {
padding: const EdgeInsets.symmetric(vertical: 16),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
- itemBuilder: (context, index) => ProfileBlogPostWidget(
- index: index,
- profileCubit: profileCubit,
- ),
+ itemBuilder: (context, index) => ProfileBlogPostWidget(index: index, profileCubit: profileCubit),
separatorBuilder: (context, index) => const SizedBox(height: 8),
itemCount: state.blogPosts.length,
);
@@ -966,13 +750,7 @@ class _ProfileScreenState extends State {
return Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.all(16),
- child: Text(
- text,
- style: TextStyle(
- color: Colors.black.withValues(alpha: 0.4),
- height: 1,
- ),
- ),
+ child: Text(text, style: TextStyle(color: Colors.black.withValues(alpha: 0.4), height: 1)),
);
}
@@ -984,13 +762,7 @@ class _ProfileScreenState extends State {
PopupMenuButton(
onSelected: (value) async {
if (value == 'view') {
- context.pushTransparentRoute(
- rootNavigator: true,
- PhotoViewScreen(
- imageUrls: [baseUrl + state.profile.profilePhotoUrl],
- index: 0,
- ),
- );
+ context.pushTransparentRoute(rootNavigator: true, PhotoViewScreen(imageUrls: [baseUrl + state.profile.profilePhotoUrl], index: 0));
}
if (value == 'replace') {
showCupertinoModalPopup(
@@ -1017,13 +789,7 @@ class _ProfileScreenState extends State {
context: context,
);
},
- child: const Row(
- children: [
- Icon(Icons.photo_camera),
- SizedBox(width: 8),
- Text('Фото'),
- ],
- ),
+ child: const Row(children: [Icon(Icons.photo_camera), SizedBox(width: 8), Text('Фото')]),
),
CupertinoActionSheetAction(
onPressed: () async {
@@ -1043,13 +809,7 @@ class _ProfileScreenState extends State {
context: context,
);
},
- child: const Row(
- children: [
- Icon(Icons.photo),
- SizedBox(width: 8),
- Text('Галерея'),
- ],
- ),
+ child: const Row(children: [Icon(Icons.photo), SizedBox(width: 8), Text('Галерея')]),
),
],
cancelButton: CupertinoActionSheetAction(
@@ -1067,20 +827,9 @@ class _ProfileScreenState extends State {
}
},
itemBuilder: (context) => [
- const PopupMenuItem(
- value: 'view',
- child: Text('Посмотреть'),
- ),
- if (widget.author == null || widget.author!.authorIsMe)
- const PopupMenuItem(
- value: 'replace',
- child: Text('Заменить'),
- ),
- if (widget.author == null || widget.author!.authorIsMe)
- const PopupMenuItem(
- value: 'delete',
- child: Text('Удалить'),
- ),
+ const PopupMenuItem(value: 'view', child: Text('Посмотреть')),
+ if (widget.author == null || widget.author!.authorIsMe) const PopupMenuItem(value: 'replace', child: Text('Заменить')),
+ if (widget.author == null || widget.author!.authorIsMe) const PopupMenuItem(value: 'delete', child: Text('Удалить')),
],
child: Hero(
tag: state.profile.profilePhotoUrl,
@@ -1099,12 +848,7 @@ class _ProfileScreenState extends State {
children: [
Text(
'${state.profileDetails.firstName} ${state.profileDetails.lastName}',
- style: const TextStyle(
- color: Colors.black,
- fontWeight: FontWeight.w600,
- fontSize: 16,
- height: 1,
- ),
+ style: const TextStyle(color: Colors.black, fontWeight: FontWeight.w600, fontSize: 16, height: 1),
),
const SizedBox(height: 8),
GestureDetector(
@@ -1122,11 +866,7 @@ class _ProfileScreenState extends State {
children: [
const Text(
'Подробнее',
- style: TextStyle(
- fontSize: 20,
- fontWeight: FontWeight.w700,
- color: Color(0xFF323F4B),
- ),
+ style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700, color: Color(0xFF323F4B)),
),
const SizedBox(height: 16),
_additional('Дата рожденя: ', state.profileDetails.birthdate),
@@ -1146,19 +886,11 @@ class _ProfileScreenState extends State {
},
child: const Row(
children: [
- Icon(
- Icons.info_outline,
- size: 20,
- color: Color(0xFF6D6F71),
- ),
+ Icon(Icons.info_outline, size: 20, color: Color(0xFF6D6F71)),
SizedBox(width: 4),
Text(
'Дополнительно',
- style: TextStyle(
- color: Color(0xFF6D6F71),
- fontSize: 14,
- fontWeight: FontWeight.w500,
- ),
+ style: TextStyle(color: Color(0xFF6D6F71), fontSize: 14, fontWeight: FontWeight.w500),
),
],
),
@@ -1171,10 +903,7 @@ class _ProfileScreenState extends State {
if (value == 'share') {
final box = context.findRenderObject() as RenderBox?;
SharePlus.instance.share(
- ShareParams(
- uri: Uri.parse('$baseUrl/ru/profile/${state.profile.slug}'),
- sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
- ),
+ ShareParams(uri: Uri.parse('$baseUrl/ru/profile/${state.profile.slug}'), sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size),
);
} else if (value == 'block') {
isFirstFetch = true;
@@ -1196,33 +925,15 @@ class _ProfileScreenState extends State {
showModalBottomSheet(
context: context,
isScrollControlled: true,
- builder: (context) => ComplainingBottomSheet(
- complainedContentType: ComplainedContent.profile,
- slug: widget.author?.authorSlug,
- ),
+ builder: (context) => ComplainingBottomSheet(complainedContentType: ComplainedContent.profile, slug: widget.author?.authorSlug),
);
}
},
itemBuilder: (context) => [
- const PopupMenuItem(
- value: 'share',
- child: Text('Поделиться'),
- ),
- if (widget.author != null)
- const PopupMenuItem(
- value: 'complain',
- child: Text('Пожаловаться'),
- ),
- if (widget.author != null && !state.profile.isBlockedByMe)
- const PopupMenuItem(
- value: 'block',
- child: Text('Заблокировать'),
- ),
- if (widget.author != null && state.profile.isBlockedByMe)
- const PopupMenuItem(
- value: 'unblock',
- child: Text('Разблокировать'),
- ),
+ const PopupMenuItem(value: 'share', child: Text('Поделиться')),
+ if (widget.author != null) const PopupMenuItem(value: 'complain', child: Text('Пожаловаться')),
+ if (widget.author != null && !state.profile.isBlockedByMe) const PopupMenuItem(value: 'block', child: Text('Заблокировать')),
+ if (widget.author != null && state.profile.isBlockedByMe) const PopupMenuItem(value: 'unblock', child: Text('Разблокировать')),
],
child: const Icon(Icons.more_horiz_rounded),
),
@@ -1236,19 +947,11 @@ class _ProfileScreenState extends State {
children: [
Text(
title,
- style: const TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w500,
- color: Color(0xFF6D6F71),
- ),
+ style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Color(0xFF6D6F71)),
),
Text(
value,
- style: const TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w500,
- color: Color(0xFF323F4B),
- ),
+ style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Color(0xFF323F4B)),
),
],
);
@@ -1264,16 +967,8 @@ class _ProfileScreenState extends State {
alignment: Alignment.center,
padding: const EdgeInsets.all(8),
width: (MediaQuery.of(context).size.width - 40) / 2,
- decoration: BoxDecoration(
- color: appTheme.blueA400.withValues(alpha: 0.1),
- borderRadius: BorderRadius.circular(16),
- ),
- child: Text(
- 'Сообщение',
- style: TextStyle(
- color: appTheme.blueA400,
- ),
- ),
+ decoration: BoxDecoration(color: appTheme.blueA400.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(16)),
+ child: Text('Сообщение', style: TextStyle(color: appTheme.blueA400)),
),
),
const SizedBox(width: 8),
@@ -1288,16 +983,8 @@ class _ProfileScreenState extends State {
alignment: Alignment.center,
padding: const EdgeInsets.all(8),
width: (MediaQuery.of(context).size.width - 40) / 2,
- decoration: BoxDecoration(
- color: !canSub ? Colors.grey.shade200 : appTheme.blueA400,
- borderRadius: BorderRadius.circular(16),
- ),
- child: Text(
- !canSub ? 'Отписаться' : 'Подписаться',
- style: TextStyle(
- color: !canSub ? Colors.black : Colors.white,
- ),
- ),
+ decoration: BoxDecoration(color: !canSub ? Colors.grey.shade200 : appTheme.blueA400, borderRadius: BorderRadius.circular(16)),
+ child: Text(!canSub ? 'Отписаться' : 'Подписаться', style: TextStyle(color: !canSub ? Colors.black : Colors.white)),
),
),
const SizedBox(width: 16),
@@ -1316,33 +1003,17 @@ class _ProfileScreenState extends State {
SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16),
scrollDirection: Axis.horizontal,
- child: Row(
- children: [
- _choiceChipWidget(0),
- const SizedBox(width: 8),
- _choiceChipWidget(1),
- const SizedBox(width: 8),
- _choiceChipWidget(2),
- ],
- ),
+ child: Row(children: [_choiceChipWidget(0), const SizedBox(width: 8), _choiceChipWidget(1), const SizedBox(width: 8), _choiceChipWidget(2)]),
),
Builder(
builder: (context) {
switch (_selectedChipIndex) {
case 0:
- return WeightChartWidget(
- weightPoints: weightPoints,
- profileCubit: profileCubit,
- );
+ return WeightChartWidget(weightPoints: weightPoints, profileCubit: profileCubit);
case 1:
- return CircumferenceChartWidget(
- circumferencePoints: circumferencePoints,
- profileCubit: profileCubit,
- );
+ return CircumferenceChartWidget(circumferencePoints: circumferencePoints, profileCubit: profileCubit);
case 2:
- return ImtChartWidget(
- weightPoints: weightPoints,
- );
+ return ImtChartWidget(weightPoints: weightPoints);
default:
return const SizedBox.shrink();
}
@@ -1375,16 +1046,10 @@ class _ProfileScreenState extends State {
pressElevation: 0,
showCheckmark: false,
side: BorderSide.none,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(16),
- ),
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
label: Text(chipsIntervalLabelList[index]),
- labelStyle: TextStyle(
- color: appTheme.gray600,
- fontWeight: FontWeight.w500,
- fontSize: 12,
- ),
+ labelStyle: TextStyle(color: appTheme.gray600, fontWeight: FontWeight.w500, fontSize: 12),
selected: _selectedIntervalChipIndex == index,
onSelected: (bool selected) {
profileCubit.getMyProfile(period: chipsIntervalList[index]);
@@ -1401,16 +1066,10 @@ class _ProfileScreenState extends State {
pressElevation: 0,
showCheckmark: false,
side: BorderSide.none,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(16),
- ),
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
label: Text(chipsLabelList[index]),
- labelStyle: TextStyle(
- color: index == _selectedChipIndex ? Colors.white : appTheme.gray600,
- fontWeight: FontWeight.w500,
- fontSize: 12,
- ),
+ labelStyle: TextStyle(color: index == _selectedChipIndex ? Colors.white : appTheme.gray600, fontWeight: FontWeight.w500, fontSize: 12),
selected: _selectedChipIndex == index,
backgroundColor: appTheme.gray100,
onSelected: (bool selected) {
diff --git a/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart b/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart
index fa2948bc..c9426674 100644
--- a/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart
+++ b/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart
@@ -60,10 +60,11 @@ class RegistrationCubit extends Cubit {
),
);
await TokenStorage.saveTokenInStorage(token);
- AppRouter.navigatorKey.currentContext?.pushNamed('verifyEmailScreen');
await sl().registerPushToken();
+ AppRouter.navigatorKey.currentContext?.replaceNamed('verifyEmailScreen');
} catch (e, st) {
log(e.toString(), stackTrace: st);
+ emit(RegistrationState(sheet: state.sheet, error: e.toString()));
}
}
diff --git a/lib/features/registration/presentation/bloc/registration_cubit/registration_state.dart b/lib/features/registration/presentation/bloc/registration_cubit/registration_state.dart
index e4347d20..6a280864 100644
--- a/lib/features/registration/presentation/bloc/registration_cubit/registration_state.dart
+++ b/lib/features/registration/presentation/bloc/registration_cubit/registration_state.dart
@@ -7,5 +7,6 @@ part 'registration_state.freezed.dart';
abstract class RegistrationState with _$RegistrationState {
const factory RegistrationState({
required UserRegistrationSheet sheet,
+ String? error,
}) = _RegistrationState;
}
diff --git a/lib/features/registration/presentation/pages/registration_screen.dart b/lib/features/registration/presentation/pages/registration_screen.dart
index 69ae62d5..86514be8 100644
--- a/lib/features/registration/presentation/pages/registration_screen.dart
+++ b/lib/features/registration/presentation/pages/registration_screen.dart
@@ -43,142 +43,161 @@ class _RegistrationScreenState extends State {
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => registrationCubit,
- child: BlocBuilder(
- builder: (BuildContext context, RegistrationState state) {
- return Scaffold(
- floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
- floatingActionButton: Row(
- children: [
- Container(
- height: 48,
- width: MediaQuery.of(context).size.width * 0.2,
- padding: const EdgeInsets.only(left: 16, right: 4),
- child: FloatingActionButton.extended(
- heroTag: 'backButtonRegistration',
- highlightElevation: 0,
- focusElevation: 0,
- elevation: 0,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(20),
- ),
- backgroundColor: const Color(0xFFEAF2FD),
- onPressed: () async {
- setState(() {
- pageController.previousPage(
- duration: const Duration(milliseconds: 350),
- curve: Curves.easeInOut,
- );
- });
- },
- label: Icon(
- Icons.arrow_back_ios_new_rounded,
- color: appTheme.blueA400,
- ),
+ child: BlocListener(
+ listener: (context, state) {
+ if (state.error != null && state.error!.isNotEmpty) {
+ showDialog(
+ context: context,
+ builder: (context) => AlertDialog(
+ title: const Text('Ошибка при регистрации'),
+ content: Text(state.error!),
+ actions: [
+ TextButton(
+ onPressed: () => Navigator.pop(context),
+ child: const Text('OK'),
),
- ),
- Container(
- height: 48,
- width: MediaQuery.of(context).size.width * 0.8,
- padding: const EdgeInsets.only(left: 4, right: 16),
- child: FloatingActionButton.extended(
- heroTag: 'nextButtonRegistration',
- highlightElevation: 0,
- elevation: 0,
- focusElevation: 0,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(20),
- ),
- backgroundColor: appTheme.blueA400,
- onPressed: () async {
- if (await canGoNext(state, context)) {
+ ],
+ ),
+ );
+ }
+ },
+ child: BlocBuilder(
+ builder: (BuildContext context, RegistrationState state) {
+ return Scaffold(
+ floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
+ floatingActionButton: Row(
+ children: [
+ Container(
+ height: 48,
+ width: MediaQuery.of(context).size.width * 0.2,
+ padding: const EdgeInsets.only(left: 16, right: 4),
+ child: FloatingActionButton.extended(
+ heroTag: 'backButtonRegistration',
+ highlightElevation: 0,
+ focusElevation: 0,
+ elevation: 0,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(20),
+ ),
+ backgroundColor: const Color(0xFFEAF2FD),
+ onPressed: () async {
setState(() {
- pageController.nextPage(
+ pageController.previousPage(
duration: const Duration(milliseconds: 350),
curve: Curves.easeInOut,
);
});
- }
- },
- label: Text(
- 'Продолжить',
- style: theme.textTheme.titleSmall!.copyWith(color: Colors.white),
+ },
+ label: Icon(
+ Icons.arrow_back_ios_new_rounded,
+ color: appTheme.blueA400,
+ ),
),
),
- ),
- ],
- ),
- appBar: AppBar(
- automaticallyImplyLeading: false,
- leading: Builder(
- builder: (context) => IconButton(
- icon: const Icon(Icons.close_rounded),
- onPressed: () => GoRouter.of(context).pop(),
- ),
- ),
- centerTitle: true,
- title: SvgPicture.asset(
- ImageConstant.imgLogoEatvio,
- height: 48,
- fit: BoxFit.contain,
- ),
- actions: [
- Padding(
- padding: const EdgeInsets.only(right: 16),
- child: Text('шаг $step из 15'),
- ),
- ],
- bottom: PreferredSize(
- preferredSize: Size(MediaQuery.of(context).size.width, 32),
- child: Padding(
- padding: const EdgeInsets.all(16),
- child: TweenAnimationBuilder(
- duration: const Duration(milliseconds: 350),
- curve: Curves.easeInOut,
- tween: Tween(
- begin: 1 / 15,
- end: progressValue,
+ Container(
+ height: 48,
+ width: MediaQuery.of(context).size.width * 0.8,
+ padding: const EdgeInsets.only(left: 4, right: 16),
+ child: FloatingActionButton.extended(
+ heroTag: 'nextButtonRegistration',
+ highlightElevation: 0,
+ elevation: 0,
+ focusElevation: 0,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(20),
+ ),
+ backgroundColor: appTheme.blueA400,
+ onPressed: () async {
+ if (await canGoNext(state, context)) {
+ setState(() {
+ pageController.nextPage(
+ duration: const Duration(milliseconds: 350),
+ curve: Curves.easeInOut,
+ );
+ });
+ }
+ },
+ label: Text(
+ 'Продолжить',
+ style: theme.textTheme.titleSmall!.copyWith(color: Colors.white),
+ ),
),
- builder: (context, value, _) => LinearProgressIndicator(
- value: value,
- borderRadius: BorderRadius.circular(16),
- minHeight: 8,
- backgroundColor: Colors.grey.shade100,
- valueColor: AlwaysStoppedAnimation(appTheme.blueA400),
+ ),
+ ],
+ ),
+ appBar: AppBar(
+ automaticallyImplyLeading: false,
+ leading: Builder(
+ builder: (context) => IconButton(
+ icon: const Icon(Icons.close_rounded),
+ onPressed: () => GoRouter.of(context).pop(),
+ ),
+ ),
+ centerTitle: true,
+ title: SvgPicture.asset(
+ ImageConstant.imgLogoEatvio,
+ height: 48,
+ fit: BoxFit.contain,
+ ),
+ actions: [
+ Padding(
+ padding: const EdgeInsets.only(right: 16),
+ child: Text('шаг $step из 15'),
+ ),
+ ],
+ bottom: PreferredSize(
+ preferredSize: Size(MediaQuery.of(context).size.width, 32),
+ child: Padding(
+ padding: const EdgeInsets.all(16),
+ child: TweenAnimationBuilder(
+ duration: const Duration(milliseconds: 350),
+ curve: Curves.easeInOut,
+ tween: Tween(
+ begin: 1 / 15,
+ end: progressValue,
+ ),
+ builder: (context, value, _) => LinearProgressIndicator(
+ value: value,
+ borderRadius: BorderRadius.circular(16),
+ minHeight: 8,
+ backgroundColor: Colors.grey.shade100,
+ valueColor: AlwaysStoppedAnimation(appTheme.blueA400),
+ ),
),
),
),
),
- ),
- body: PageView(
- physics: const NeverScrollableScrollPhysics(),
- controller: pageController,
- onPageChanged: (index) {
- setState(() {
- step = index + 1;
- progressValue = step / 15;
- });
- },
- children: [
- // LanguageSelectScreen(sheet: state.sheet),
- PhoneScreen(sheet: state.sheet),
- CredentialsScreen(sheet: state.sheet),
- NameScreen(sheet: state.sheet),
- GenderScreen(sheet: state.sheet),
- DateOfBirthScreen(sheet: state.sheet),
- CityOfLivingScreen(sheet: state.sheet),
- BodyCircumferencesScreen(sheet: state.sheet),
- WeightScreen(sheet: state.sheet),
- HeightScreen(sheet: state.sheet),
- BloodPressureScreen(sheet: state.sheet),
- AllergiesScreen(sheet: state.sheet),
- MedicineIntakeScreen(sheet: state.sheet),
- FavoriteSportsScreen(sheet: state.sheet),
- FavoriteFoodsScreen(sheet: state.sheet),
- AdditionalInformationScreen(sheet: state.sheet),
- ],
- ),
- );
- },
+ body: PageView(
+ physics: const NeverScrollableScrollPhysics(),
+ controller: pageController,
+ onPageChanged: (index) {
+ setState(() {
+ step = index + 1;
+ progressValue = step / 15;
+ });
+ },
+ children: [
+ // LanguageSelectScreen(sheet: state.sheet),
+ PhoneScreen(sheet: state.sheet),
+ CredentialsScreen(sheet: state.sheet),
+ NameScreen(sheet: state.sheet),
+ GenderScreen(sheet: state.sheet),
+ DateOfBirthScreen(sheet: state.sheet),
+ CityOfLivingScreen(sheet: state.sheet),
+ BodyCircumferencesScreen(sheet: state.sheet),
+ WeightScreen(sheet: state.sheet),
+ HeightScreen(sheet: state.sheet),
+ BloodPressureScreen(sheet: state.sheet),
+ AllergiesScreen(sheet: state.sheet),
+ MedicineIntakeScreen(sheet: state.sheet),
+ FavoriteSportsScreen(sheet: state.sheet),
+ FavoriteFoodsScreen(sheet: state.sheet),
+ AdditionalInformationScreen(sheet: state.sheet),
+ ],
+ ),
+ );
+ },
+ ),
),
);
}
diff --git a/lib/features/registration/presentation/pages/verify_screen.dart b/lib/features/registration/presentation/pages/verify_screen.dart
index 7f8aede5..637dba5b 100644
--- a/lib/features/registration/presentation/pages/verify_screen.dart
+++ b/lib/features/registration/presentation/pages/verify_screen.dart
@@ -1,5 +1,6 @@
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
+import 'package:eatvio_app/core/widgets/loader.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:lottie/lottie.dart';
@@ -19,6 +20,7 @@ class VerifyScreen extends StatefulWidget {
class _VerifyScreenState extends State {
late final WebViewController _controller;
+ bool _isLoading = true;
@override
void initState() {
@@ -27,6 +29,11 @@ class _VerifyScreenState extends State {
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
+ onPageFinished: (url) {
+ setState(() {
+ _isLoading = false;
+ });
+ },
onNavigationRequest: (NavigationRequest request) async {
if (request.url.contains('user_detailz') && !request.url.contains('change-phone-verify') || request.url.contains('email/verify')) {
GoRouter.of(context).pop();
@@ -105,11 +112,17 @@ class _VerifyScreenState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
- appBar: AppBar(
- toolbarHeight: 0,
- ),
+ appBar: AppBar(toolbarHeight: 0),
body: SafeArea(
- child: WebViewWidget(controller: _controller),
+ child: Stack(
+ children: [
+ WebViewWidget(controller: _controller),
+ if (_isLoading)
+ const Center(
+ child: Loader(),
+ ),
+ ],
+ ),
),
);
}
diff --git a/lib/features/registration/repositories/registration_repository.dart b/lib/features/registration/repositories/registration_repository.dart
index 0c3008e0..a34bf1b0 100644
--- a/lib/features/registration/repositories/registration_repository.dart
+++ b/lib/features/registration/repositories/registration_repository.dart
@@ -1,7 +1,5 @@
-
import 'package:dio/dio.dart';
import 'package:eatvio_app/core/locator_service.dart';
-import 'package:eatvio_app/core/utils/toasts.dart';
import 'package:eatvio_app/features/registration/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/models/location_model.dart';
import 'package:eatvio_app/features/registration/services/registration_service.dart';
@@ -14,13 +12,55 @@ class RegistrationRepository {
Future tryRegister(UserRegistrationSheet sheet) async {
try {
final response = await registrationService.register(sheet: sheet.toJson());
- try {
- return (response['token']!);
- } catch (e) {
- showErrorToast(response.toString());
- rethrow;
+ if (response.containsKey('token')) {
+ return response['token']!;
+ } else {
+ // Если нет токена, но есть message или errors
+ String errorMsg = '';
+ if (response.containsKey('message')) {
+ errorMsg += '${response['message']!}\n';
+ }
+ if (response.containsKey('errors')) {
+ final errors = response['errors'];
+ if (errors != null && errors is Map) {
+ (errors as Map).forEach((key, value) {
+ if (value is List && value.isNotEmpty) {
+ errorMsg += '${value.join('\n')}\n';
+ }
+ });
+ }
+ }
+ if (errorMsg.isNotEmpty) {
+ throw errorMsg.trim();
+ } else {
+ throw 'Ошибка регистрации: $response';
+ }
+ }
+ } on DioException catch (e) {
+ if (e.response != null && e.response?.statusCode == 422) {
+ final data = e.response?.data;
+ String errorMsg = '';
+ if (data is Map) {
+ if (data.containsKey('message')) {
+ errorMsg += data['message'] + '\n';
+ }
+ if (data.containsKey('errors')) {
+ final errors = data['errors'];
+ if (errors != null && errors is Map) {
+ (errors).forEach((key, value) {
+ if (value is List && value.isNotEmpty) {
+ errorMsg += '${value.join('\n')}\n';
+ }
+ });
+ }
+ }
+ }
+ if (errorMsg.isNotEmpty) {
+ throw errorMsg.trim();
+ } else {
+ throw 'Ошибка регистрации: $data';
+ }
}
- } catch (e) {
rethrow;
}
}
diff --git a/lib/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart b/lib/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart
index 3cb047f6..ae498824 100644
--- a/lib/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart
+++ b/lib/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart
@@ -22,7 +22,11 @@ class SettingsCubit extends Cubit {
final profile = await profileRepository.getMyProfile();
late final ConsultationRequestModel? consultantInfo;
try {
- consultantInfo = await consultantRepository.getMyRequestStatus(profile.slug);
+ if (profile.phoneConfirmationState.contains('confirmed')) {
+ consultantInfo = await consultantRepository.getMyRequestStatus(profile.slug);
+ } else {
+ consultantInfo = null;
+ }
} catch (e) {
consultantInfo = null;
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 4223ded7..057a2d2d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,10 +1,10 @@
name: eatvio_app
description: A new Flutter project.
-version: 1.2.4+54
+version: 1.2.6+64
publish_to: 'none'
environment:
- sdk: '>=3.3.4 <4.0.0'
+ sdk: '>=3.8.0 <4.0.0'
dependencies:
flutter:
@@ -18,28 +18,28 @@ dependencies:
cached_network_image: ^3.4.1
flutter_svg: ^2.2.0
equatable: ^2.0.7
- freezed_annotation: ^3.0.0
+ freezed_annotation: ^3.1.0
json_annotation: ^4.9.0
validators: ^3.0.0
path_provider: ^2.1.5
carousel_slider_plus: ^7.1.1
- flutter_form_builder: ^10.0.1
+ flutter_form_builder: ^10.1.0
image_picker: ^1.1.2
flutter_typeahead: ^5.2.0
go_router: ^16.0.0
keyboard_dismisser: ^3.0.0
- retrofit: ^4.5.0
- get_it: ^8.0.3
+ retrofit: ^4.7.0
+ get_it: ^8.1.0
dio: ^5.8.0+1
dart_pusher_channels: ^1.2.3
photo_view: ^0.15.0
dismissible_page: ^1.0.2
- url_launcher: ^6.3.1
+ url_launcher: ^6.3.2
easy_debounce: ^2.0.3
badges: ^3.1.2
google_fonts: ^6.2.1
- syncfusion_flutter_charts: ^30.1.38
- syncfusion_flutter_gauges: ^30.1.38
+ syncfusion_flutter_charts: ^30.1.42
+ syncfusion_flutter_gauges: ^30.1.42
table_calendar: ^3.2.0
flutter_keyboard_visibility: ^6.0.0
share_plus: ^11.0.0
@@ -58,11 +58,11 @@ dependencies:
http: ^1.4.0
flutter_native_splash: ^2.4.6
webview_flutter: ^4.13.0
- sentry_flutter: ^8.14.2
+ sentry_flutter: ^9.5.0
connectivity_plus: ^6.1.4
visibility_detector: ^0.4.0+2
- firebase_core: ^3.15.0
- firebase_messaging: ^15.2.8
+ firebase_core: ^4.0.0
+ firebase_messaging: ^16.0.0
http_parser: ^4.1.2
path: ^1.9.1
collection: ^1.19.1
@@ -70,15 +70,15 @@ dependencies:
version: ^3.0.2
package_info_plus: ^8.3.0
device_info_plus: ^11.5.0
- permission_handler: ^12.0.0+1
+ permission_handler: ^12.0.1
qr_code_scanner_plus: ^2.0.10+1
dev_dependencies:
- build_runner: ^2.5.4
- freezed: ^3.0.6
- json_serializable: ^6.9.5
- retrofit_generator: ^9.2.0
- mockito: ^5.4.6
+ build_runner: ^2.6.0
+ freezed: ^3.2.0
+ json_serializable: ^6.10.0
+ retrofit_generator: ^10.0.1
+ mockito: ^5.5.0
flutter_test:
sdk: flutter
diff --git a/test/features/profile/services/profile_service_test.dart b/test/features/profile/services/profile_service_test.dart
index b2c51b01..106da096 100644
--- a/test/features/profile/services/profile_service_test.dart
+++ b/test/features/profile/services/profile_service_test.dart
@@ -19,6 +19,7 @@ void main() {
id: 0,
name: 'Alexander Avanesyan',
email: 'mso7nueh@mail.ru',
+ phoneConfirmationState: '',
isPublicProfile: true,
isEntitySubscribedByMe: false,
isBlockedByMe: false,