diff --git a/.gitignore b/.gitignore index 5bb96d46..bb936737 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ /node_modules/ /android/app/release/app-release.aab /android/app/upload-keystore.jks +/android/app/.cxx diff --git a/android/app/build.gradle b/android/app/build.gradle index 2869498c..4df5da7f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,5 +1,8 @@ plugins { id "com.android.application" + // START: FlutterFire Configuration + id 'com.google.gms.google-services' + // END: FlutterFire Configuration id "kotlin-android" id "dev.flutter.flutter-gradle-plugin" } @@ -13,7 +16,7 @@ if (keystorePropertiesFile.exists()) { android { namespace = "com.eatvioapp.app" compileSdk = flutter.compileSdkVersion - ndkVersion = flutter.ndkVersion + ndkVersion = "27.0.12077973" compileOptions { sourceCompatibility = JavaVersion.VERSION_21 diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 00000000..8b0acfc2 --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,30 @@ +{ + "project_info": { + "project_number": "613980912922", + "firebase_url": "https://eatvio-3467b-default-rtdb.europe-west1.firebasedatabase.app", + "project_id": "eatvio-3467b", + "storage_bucket": "eatvio-3467b.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:613980912922:android:4de95e5f2d50ba69ecc0a3", + "android_client_info": { + "package_name": "com.eatvioapp.app" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyBUe1UqAAMfgMcd4hWdRoLF1Os-yn-HE9k" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index a9f0eb13..849ba91f 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -19,6 +19,9 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "com.android.application" version "8.7.3" apply false + // START: FlutterFire Configuration + id "com.google.gms.google-services" version "4.3.15" apply false + // END: FlutterFire Configuration id "org.jetbrains.kotlin.android" version "2.0.21" apply false } diff --git a/firebase.json b/firebase.json new file mode 100644 index 00000000..9ebb3fe8 --- /dev/null +++ b/firebase.json @@ -0,0 +1,30 @@ +{ + "flutter": { + "platforms": { + "android": { + "default": { + "projectId": "eatvio-3467b", + "appId": "1:613980912922:android:4de95e5f2d50ba69ecc0a3", + "fileOutput": "android/app/google-services.json" + } + }, + "ios": { + "default": { + "projectId": "eatvio-3467b", + "appId": "1:613980912922:ios:c557d140a1212e63ecc0a3", + "uploadDebugSymbols": false, + "fileOutput": "ios/Runner/GoogleService-Info.plist" + } + }, + "dart": { + "lib/firebase_options.dart": { + "projectId": "eatvio-3467b", + "configurations": { + "android": "1:613980912922:android:4de95e5f2d50ba69ecc0a3", + "ios": "1:613980912922:ios:c557d140a1212e63ecc0a3" + } + } + } + } + } +} \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8e714119..38d0543a 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + ACF3142BB74D6F5F3C98AD82 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = EB9FE5381C3F532BD9A9456D /* GoogleService-Info.plist */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -47,6 +48,7 @@ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9D8D6181877DE17809AFF936 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; DF0C4038A57E19D3ABA03C15 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + EB9FE5381C3F532BD9A9456D /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; FEE92A0E2D772EA300E6E989 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; /* End PBXFileReference section */ @@ -91,6 +93,7 @@ 97C146EF1CF9000F007C117D /* Products */, 6F201E010624CF963CC3A17B /* Pods */, AEE6B7943D197783DD1CB2EE /* Frameworks */, + EB9FE5381C3F532BD9A9456D /* GoogleService-Info.plist */, ); sourceTree = ""; }; @@ -141,6 +144,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 1D324C14EB43C988423BC1AD /* [CP] Embed Pods Frameworks */, + DEAA66E178B81C074317BF9A /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -194,6 +198,7 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ACF3142BB74D6F5F3C98AD82 /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -270,6 +275,23 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + DEAA66E178B81C074317BF9A /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -363,9 +385,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 48; + CURRENT_PROJECT_VERSION = 51; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -383,7 +406,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 1.0.48; + MARKETING_VERSION = 1.0.49; PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -512,9 +535,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 48; + CURRENT_PROJECT_VERSION = 51; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -532,7 +556,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 1.0.48; + MARKETING_VERSION = 1.0.49; PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -549,9 +573,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 48; + CURRENT_PROJECT_VERSION = 51; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -569,7 +594,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 1.0.48; + MARKETING_VERSION = 1.0.49; PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist new file mode 100644 index 00000000..3f42d802 --- /dev/null +++ b/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,32 @@ + + + + + API_KEY + AIzaSyBnE8tQjL9_1HuXrTnqNy6qbXpoenO36yQ + GCM_SENDER_ID + 613980912922 + PLIST_VERSION + 1 + BUNDLE_ID + com.eatvioapp.app + PROJECT_ID + eatvio-3467b + STORAGE_BUCKET + eatvio-3467b.firebasestorage.app + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:613980912922:ios:c557d140a1212e63ecc0a3 + DATABASE_URL + https://eatvio-3467b-default-rtdb.europe-west1.firebasedatabase.app + + \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index cab95de7..b6470ce4 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,8 +2,6 @@ - ITSAppUsesNonExemptEncryption - CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion @@ -24,6 +22,8 @@ ???? CFBundleVersion $(FLUTTER_BUILD_NUMBER) + ITSAppUsesNonExemptEncryption + LSRequiresIPhoneOS NSAppTransportSecurity @@ -42,6 +42,7 @@ UIBackgroundModes fetch + remote-notification UILaunchStoryboardName LaunchScreen diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements index a9bc4abe..903def2a 100644 --- a/ios/Runner/Runner.entitlements +++ b/ios/Runner/Runner.entitlements @@ -3,6 +3,6 @@ aps-environment - disabled + development diff --git a/lib/core/firebase_api.dart b/lib/core/firebase_api.dart new file mode 100644 index 00000000..f83d47d6 --- /dev/null +++ b/lib/core/firebase_api.dart @@ -0,0 +1,11 @@ +import 'package:firebase_messaging/firebase_messaging.dart'; + +class FirebaseApi { + + final _firebaseMessaging = FirebaseMessaging.instance; + + Future getToken() async{ + await _firebaseMessaging.requestPermission(); + return await _firebaseMessaging.getToken(); + } +} \ No newline at end of file diff --git a/lib/core/locator_service.dart b/lib/core/locator_service.dart index 3a3f5342..4320423a 100644 --- a/lib/core/locator_service.dart +++ b/lib/core/locator_service.dart @@ -94,13 +94,13 @@ Future init() async { // Cubit factories sl.registerFactory(() => RegistrationCubit(registrationRepository: sl())); - sl.registerFactory(() => ChatRoomCubit(chatRepository: sl(), wsManager: sl())); + sl.registerFactory(() => ChatRoomCubit(cardsRepository: sl(), chatRepository: sl(), wsManager: sl())); sl.registerFactory(() => RecipesCubit(feedRepository: sl(), recipeRepository: sl(), aboutRecipeRepository: sl())); sl.registerFactory(() => CalendarCubit(calendarRepository: sl())); sl.registerFactory(() => ProfileCubit(profileRepository: sl(), chatRepository: sl())); sl.registerFactory(() => profilePlans.PlansCubit(plansRepository: sl())); sl.registerFactory(() => DietsCubit(feedRepository: sl(), dietsRepository: sl())); - sl.registerFactory(() => CommentsCubit(feedRepository: sl())); + sl.registerFactory(() => CommentsCubit(feedRepository: sl())); sl.registerFactory(() => PlansCubit(feedRepository: sl(), planRepository: sl())); sl.registerFactory(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl())); sl.registerFactory(() => RegisterConsultantCubit(consultantRepository: sl())); @@ -171,15 +171,7 @@ Future init() async { // External sl.registerLazySingleton( - () => Dio( - BaseOptions( - baseUrl: baseUrl, - headers: { - 'accept': 'application/json', - 'content-type': 'application/json', - }, - ), - )..interceptors.add(TokenInterceptor()), + () => Dio(BaseOptions(baseUrl: baseUrl, headers: {'accept': 'application/json', 'content-type': 'application/json'}))..interceptors.add(TokenInterceptor()), ); sl.registerLazySingleton(() async => await FlutterSecureStorage()); } diff --git a/lib/core/widgets/data_error_widget.dart b/lib/core/widgets/data_error_widget.dart index 1ce1c110..e7330506 100644 --- a/lib/core/widgets/data_error_widget.dart +++ b/lib/core/widgets/data_error_widget.dart @@ -25,43 +25,33 @@ class _DataErrorWidgetState extends State { children: [ SvgPicture.asset('assets/icons/cloud.svg'), SizedBox(height: 30), - Text( - s.something_went_wrong, - style: TextStyles.textLSemibold.copyWith(color: appTheme.black), - ), + Text(s.something_went_wrong, style: TextStyles.textLSemibold.copyWith(color: appTheme.black)), SizedBox(height: 12), Padding( padding: const EdgeInsets.symmetric(horizontal: 32), - child: Text( - s.can_not_load_data_please_try_again, - style: TextStyles.textSMedium.copyWith(color: appTheme.black), - textAlign: TextAlign.center, - ), + child: Text(s.can_not_load_data_please_try_again, style: TextStyles.textSMedium.copyWith(color: appTheme.black), textAlign: TextAlign.center), ), SizedBox(height: 20), isLoading ? Loader() : Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: CustomOutlinedButton( - text: s.try_again, - height: 52, - buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), - buttonStyle: ButtonStyle( - side: WidgetStatePropertyAll(BorderSide.none), - backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), - ), - onPressed: () async { - setState(() { - isLoading = true; - }); - await widget.onReload(); - setState(() { - isLoading = false; - }); - }, - ), + padding: const EdgeInsets.symmetric(horizontal: 16), + child: CustomOutlinedButton( + text: s.try_again, + height: 52, + buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), + buttonStyle: ButtonStyle(side: WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)), + onPressed: () async { + setState(() { + isLoading = true; + }); + await widget.onReload(); + setState(() { + isLoading = false; + }); + }, ), + ), ], ); } diff --git a/lib/features/blog_post_create/repositories/blog_post_repository.dart b/lib/features/blog_post_create/repositories/blog_post_repository.dart index 7ec77089..0b9b0ecd 100644 --- a/lib/features/blog_post_create/repositories/blog_post_repository.dart +++ b/lib/features/blog_post_create/repositories/blog_post_repository.dart @@ -68,8 +68,7 @@ class BlogPostRepository { ) async { FormData formData = FormData.fromMap({ 'title': title, - 'description': description, - 'state': 'active', + 'description_md': description, 'video_url': videoUrl, 'image': image != null ? await MultipartFile.fromFile((await ImageCompressUtility.compressFile(File(image.path))).path, filename: image.name) diff --git a/lib/features/blog_post_create/services/blog_post_service.dart b/lib/features/blog_post_create/services/blog_post_service.dart index 645b621d..56fc5461 100644 --- a/lib/features/blog_post_create/services/blog_post_service.dart +++ b/lib/features/blog_post_create/services/blog_post_service.dart @@ -13,7 +13,7 @@ abstract class BlogPostService { @Body() required FormData formData, }); - @POST('/api/blogPosts/update/{id}') + @POST('/api/blogPosts/update/published/{id}') @MultiPart() Future updateBlogPost({ @Path('id') required int id, diff --git a/lib/features/blog_post_create/services/blog_post_service.g.dart b/lib/features/blog_post_create/services/blog_post_service.g.dart index aa430049..ba5e1482 100644 --- a/lib/features/blog_post_create/services/blog_post_service.g.dart +++ b/lib/features/blog_post_create/services/blog_post_service.g.dart @@ -59,7 +59,7 @@ class _BlogPostService implements BlogPostService { ) .compose( _dio.options, - '/api/blogPosts/update/${id}', + '/api/blogPosts/update/published/${id}', queryParameters: queryParameters, data: _data, ) diff --git a/lib/features/blog_post_create/services/blog_service.dart b/lib/features/blog_post_create/services/blog_service.dart deleted file mode 100644 index 4b110622..00000000 --- a/lib/features/blog_post_create/services/blog_service.dart +++ /dev/null @@ -1,16 +0,0 @@ -/* -import 'package:eatvio_app/features/blog_post_create/models/blog_post_create_credentials_model.dart'; -import 'package:dio/dio.dart'; -import 'package:retrofit/retrofit.dart'; - -part 'blog_service.g.dart'; - -@RestApi() -abstract class BlogService { - factory BlogService(Dio dio, {String baseUrl}) = _BlogService; - - @POST('/blog_post/create') - Future createBlogPost( - BlogPostCreateCredentialsModel model); -} -*/ diff --git a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart index 1e456fc6..c6e44f76 100644 --- a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart +++ b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart @@ -11,10 +11,13 @@ import 'package:eatvio_app/core/websockets/ws_manager.dart'; import 'package:eatvio_app/features/chat/models/chat_message_model.dart'; import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart'; import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; +import 'package:eatvio_app/features/my_finance/models/card_model.dart'; +import 'package:eatvio_app/features/my_finance/repositories/cards_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class ChatRoomCubit extends Cubit { final ChatRepository chatRepository; + final CardsRepository cardsRepository; final WsManager wsManager; StreamSubscription? typingSubscription; @@ -23,34 +26,22 @@ class ChatRoomCubit extends Cubit { late final int lastPage; bool isLoading = false; - ChatRoomCubit({ - required this.chatRepository, - required this.wsManager, - }) : super(ChatRoomState.loading()); + ChatRoomCubit({required this.chatRepository, required this.wsManager, required this.cardsRepository}) : super(ChatRoomState.loading()); loadNextPage(String chatId) async { if (currentPage < lastPage && !isLoading) { isLoading = true; - emit( - ChatRoomState.loaded( - chatRoom: (state as ChatRoomStateLoaded).chatRoom, - chatMessages: (state as ChatRoomStateLoaded).chatMessages, - isTyping: (state as ChatRoomStateLoaded).isTyping, - isLoading: isLoading, - ), - ); + emit((state as ChatRoomStateLoaded).copyWith(isLoading: isLoading)); try { final chatMessages = await chatRepository.getChatMessages(chatId, currentPage + 1); isLoading = false; emit( - ChatRoomState.loaded( - chatRoom: (state as ChatRoomStateLoaded).chatRoom, - chatMessages: [...(state as ChatRoomStateLoaded).chatMessages, ...chatMessages.messagesList], - isTyping: (state as ChatRoomStateLoaded).isTyping, + (state as ChatRoomStateLoaded).copyWith( isLoading: isLoading, + chatMessages: [...(state as ChatRoomStateLoaded).chatMessages, ...chatMessages.messagesList], ), ); @@ -61,6 +52,24 @@ class ChatRoomCubit extends Cubit { } } + Future checkCards() async { + try { + final cards = await cardsRepository.getCards(); + setCard(cards: cards); + } catch (e) { + emit(ChatRoomState.error(errorMessage: 'Ошибка получеия данных')); + } + } + + void setCard({required List cards}) { + final currentState = state; + if (currentState is ChatRoomStateLoaded) { + if (cards.where((card) => card.isDefault).isNotEmpty) { + emit(currentState.copyWith(hasCard: true)); + } + } + } + initChat(String chatId) async { try { final chatRoom = await chatRepository.getChatRoom(chatId); @@ -70,14 +79,9 @@ class ChatRoomCubit extends Cubit { await _subscribeToChatChannel(chatId: chatId); - emit( - ChatRoomState.loaded( - chatRoom: chatRoom, - chatMessages: chatMessages.messagesList, - isTyping: false, - isLoading: isLoading, - ), - ); + emit(ChatRoomState.loaded(chatRoom: chatRoom, chatMessages: chatMessages.messagesList, isTyping: false, isLoading: isLoading, hasCard: false)); + final cards = await cardsRepository.getCards(); + setCard(cards: cards); } catch (e) { typingSubscription?.cancel(); messagesSubscription?.cancel(); @@ -90,17 +94,13 @@ class ChatRoomCubit extends Cubit { try { await chatRepository.cancelChosenPlan(id: planId); final chatRoom = await chatRepository.getChatRoom(chatId); - emit( - (state as ChatRoomStateLoaded).copyWith(chatRoom: chatRoom), - ); + emit((state as ChatRoomStateLoaded).copyWith(chatRoom: chatRoom)); } catch (e) { emit(ChatRoomState.error(errorMessage: 'Ошибка получеия данных')); } } - Future _subscribeToChatChannel({ - required String chatId, - }) async { + Future _subscribeToChatChannel({required String chatId}) async { final client = wsManager.client; if (client == null) return; await wsManager.initPrivateDirectChatChannel(chatId); @@ -108,56 +108,20 @@ class ChatRoomCubit extends Cubit { messagesSubscription = wsManager.directChatStream?.listen((event) { AudioPlayer().play((AssetSource('audio/recive_message.wav'))); final message = ChatMessageModel.fromJson(jsonDecode(event.data)['message']); - List messagesList = [ - message, - ...(state as ChatRoomStateLoaded).chatMessages, - ]; + List messagesList = [message, ...(state as ChatRoomStateLoaded).chatMessages]; chatRepository.emitNewMessageToChats(message); - emit( - ChatRoomState.loaded( - chatRoom: (state as ChatRoomStateLoaded).chatRoom, - chatMessages: messagesList, - isTyping: (state as ChatRoomStateLoaded).isTyping, - isLoading: isLoading, - ), - ); + emit((state as ChatRoomStateLoaded).copyWith(chatMessages: messagesList, isLoading: isLoading)); }); typingSubscription = wsManager.clientTypingStream?.listen((event) { - emit( - ChatRoomState.loaded( - chatRoom: (state as ChatRoomStateLoaded).chatRoom, - chatMessages: (state as ChatRoomStateLoaded).chatMessages, - isTyping: true, - isLoading: isLoading, - ), - ); - EasyDebounce.debounce( - 'client-typing', - Duration(seconds: 3), - () => emit( - ChatRoomState.loaded( - chatRoom: (state as ChatRoomStateLoaded).chatRoom, - chatMessages: (state as ChatRoomStateLoaded).chatMessages, - isTyping: false, - isLoading: isLoading, - ), - ), - ); + emit((state as ChatRoomStateLoaded).copyWith(isTyping: true, isLoading: isLoading)); + EasyDebounce.debounce('client-typing', Duration(seconds: 3), () => emit((state as ChatRoomStateLoaded).copyWith(isTyping: false, isLoading: isLoading))); }); } - Future sendMessage({ - required String chatId, - String? data, - List? files, - }) async { + Future sendMessage({required String chatId, String? data, List? files}) async { try { - await chatRepository.sendMessage( - chatId: chatId, - data: data, - files: files != null ? await ImageCompressUtility.compressFilesList(files) : null, - ); + await chatRepository.sendMessage(chatId: chatId, data: data, files: files != null ? await ImageCompressUtility.compressFilesList(files) : null); AudioPlayer().play((AssetSource('audio/send_message.wav'))); return true; } catch (e, st) { @@ -176,9 +140,7 @@ class ChatRoomCubit extends Cubit { currentMessages[elem.index] = currentMessages[elem.index].copyWith(isRead: true); }); if (!isClosed) { - emit( - (state as ChatRoomStateLoaded).copyWith(chatMessages: currentMessages), - ); + emit((state as ChatRoomStateLoaded).copyWith(chatMessages: currentMessages)); } return true; } diff --git a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart index 24113e62..36ca4f35 100644 --- a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart +++ b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart @@ -13,6 +13,7 @@ abstract class ChatRoomState with _$ChatRoomState { const factory ChatRoomState.loaded({ required ChatRoomModel chatRoom, required List chatMessages, + required bool hasCard, required bool isTyping, required bool isLoading, }) = ChatRoomStateLoaded; diff --git a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.freezed.dart b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.freezed.dart index 52b11c34..eb7ab711 100644 --- a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.freezed.dart +++ b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.freezed.dart @@ -24,6 +24,7 @@ mixin _$ChatRoomState { required TResult Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, ) @@ -37,6 +38,7 @@ mixin _$ChatRoomState { TResult? Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, )? @@ -50,6 +52,7 @@ mixin _$ChatRoomState { TResult Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, )? @@ -151,6 +154,7 @@ class _$ChatRoomStateImpl implements _ChatRoomState { required TResult Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, ) @@ -168,6 +172,7 @@ class _$ChatRoomStateImpl implements _ChatRoomState { TResult? Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, )? @@ -185,6 +190,7 @@ class _$ChatRoomStateImpl implements _ChatRoomState { TResult Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, )? @@ -289,6 +295,7 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading { required TResult Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, ) @@ -306,6 +313,7 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading { TResult? Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, )? @@ -323,6 +331,7 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading { TResult Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, )? @@ -388,6 +397,7 @@ abstract class _$$ChatRoomStateLoadedImplCopyWith<$Res> { $Res call({ ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, }); @@ -411,6 +421,7 @@ class __$$ChatRoomStateLoadedImplCopyWithImpl<$Res> $Res call({ Object? chatRoom = null, Object? chatMessages = null, + Object? hasCard = null, Object? isTyping = null, Object? isLoading = null, }) { @@ -426,6 +437,11 @@ class __$$ChatRoomStateLoadedImplCopyWithImpl<$Res> ? _value._chatMessages : chatMessages // ignore: cast_nullable_to_non_nullable as List, + hasCard: + null == hasCard + ? _value.hasCard + : hasCard // ignore: cast_nullable_to_non_nullable + as bool, isTyping: null == isTyping ? _value.isTyping @@ -457,6 +473,7 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { const _$ChatRoomStateLoadedImpl({ required this.chatRoom, required final List chatMessages, + required this.hasCard, required this.isTyping, required this.isLoading, }) : _chatMessages = chatMessages; @@ -471,6 +488,8 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { return EqualUnmodifiableListView(_chatMessages); } + @override + final bool hasCard; @override final bool isTyping; @override @@ -478,7 +497,7 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { @override String toString() { - return 'ChatRoomState.loaded(chatRoom: $chatRoom, chatMessages: $chatMessages, isTyping: $isTyping, isLoading: $isLoading)'; + return 'ChatRoomState.loaded(chatRoom: $chatRoom, chatMessages: $chatMessages, hasCard: $hasCard, isTyping: $isTyping, isLoading: $isLoading)'; } @override @@ -492,6 +511,7 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { other._chatMessages, _chatMessages, ) && + (identical(other.hasCard, hasCard) || other.hasCard == hasCard) && (identical(other.isTyping, isTyping) || other.isTyping == isTyping) && (identical(other.isLoading, isLoading) || @@ -503,6 +523,7 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { runtimeType, chatRoom, const DeepCollectionEquality().hash(_chatMessages), + hasCard, isTyping, isLoading, ); @@ -526,13 +547,14 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { required TResult Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, ) loaded, required TResult Function(String errorMessage) error, }) { - return loaded(chatRoom, chatMessages, isTyping, isLoading); + return loaded(chatRoom, chatMessages, hasCard, isTyping, isLoading); } @override @@ -543,13 +565,14 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { TResult? Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, )? loaded, TResult? Function(String errorMessage)? error, }) { - return loaded?.call(chatRoom, chatMessages, isTyping, isLoading); + return loaded?.call(chatRoom, chatMessages, hasCard, isTyping, isLoading); } @override @@ -560,6 +583,7 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { TResult Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, )? @@ -568,7 +592,7 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { required TResult orElse(), }) { if (loaded != null) { - return loaded(chatRoom, chatMessages, isTyping, isLoading); + return loaded(chatRoom, chatMessages, hasCard, isTyping, isLoading); } return orElse(); } @@ -615,12 +639,14 @@ abstract class ChatRoomStateLoaded implements ChatRoomState { const factory ChatRoomStateLoaded({ required final ChatRoomModel chatRoom, required final List chatMessages, + required final bool hasCard, required final bool isTyping, required final bool isLoading, }) = _$ChatRoomStateLoadedImpl; ChatRoomModel get chatRoom; List get chatMessages; + bool get hasCard; bool get isTyping; bool get isLoading; @@ -711,6 +737,7 @@ class _$ChatRoomStateErrorImpl implements ChatRoomStateError { required TResult Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, ) @@ -728,6 +755,7 @@ class _$ChatRoomStateErrorImpl implements ChatRoomStateError { TResult? Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, )? @@ -745,6 +773,7 @@ class _$ChatRoomStateErrorImpl implements ChatRoomStateError { TResult Function( ChatRoomModel chatRoom, List chatMessages, + bool hasCard, bool isTyping, bool isLoading, )? diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart index 014068e4..5fafe2c8 100644 --- a/lib/features/chat/presentation/pages/chat_screen.dart +++ b/lib/features/chat/presentation/pages/chat_screen.dart @@ -13,6 +13,7 @@ import 'package:eatvio_app/features/chat/presentation/widgets/chat_bubble_widget import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/theme/custom_text_style.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/features/chat/presentation/widgets/notification_banner.dart'; import 'package:eatvio_app/features/chat/presentation/widgets/order_card.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart'; @@ -27,10 +28,7 @@ import 'package:visibility_detector/visibility_detector.dart'; class ChatScreen extends StatefulWidget { final String chatId; - const ChatScreen({ - required this.chatId, - super.key, - }); + const ChatScreen({required this.chatId, super.key}); @override State createState() => _ChatScreenState(); @@ -73,14 +71,9 @@ class _ChatScreenState extends State { if (state is ChatRoomStateLoaded) { return _buildChat(context, state); } else if (state is ChatRoomStateError) { - return Scaffold( - appBar: AppBar(), - body: DataErrorWidget(onReload: () => chatRoomCubit.initChat(widget.chatId)), - ); + return Scaffold(appBar: AppBar(), body: DataErrorWidget(onReload: () => chatRoomCubit.initChat(widget.chatId))); } else { - return Scaffold( - body: const Loader(), - ); + return Scaffold(body: const Loader()); } }, ), @@ -91,6 +84,14 @@ class _ChatScreenState extends State { final chosenPlan = state.chatRoom.chosenPlan; final amIConsultant = chosenPlan?.consultantId == state.chatRoom.users.sender.id; final showAboutOrderButton = showableChatBadgeStates.contains(chosenPlan?.chosenPlanState); + BannerType? bannerType; + if (amIConsultant && !state.hasCard) { + bannerType = BannerType.card; + } else if (amIConsultant && chosenPlan?.chosenPlanState == ChosenPlanStateEnum.stateInCoordination) { + bannerType = BannerType.date; + } else if (!amIConsultant && chosenPlan?.chosenPlanState == ChosenPlanStateEnum.stateStartDateHasBeenSet) { + bannerType = BannerType.payment; + } return Scaffold( resizeToAvoidBottomInset: true, appBar: AppBar( @@ -184,10 +185,7 @@ class _ChatScreenState extends State { shrinkWrap: true, itemBuilder: (context, index) { if (index == state.chatMessages.length) { - return Padding( - padding: const EdgeInsets.all(8), - child: const Loader(), - ); + return Padding(padding: const EdgeInsets.all(8), child: const Loader()); } if ((index + 1 != state.chatMessages.length && @@ -202,18 +200,15 @@ class _ChatScreenState extends State { onVisibilityChanged: (VisibilityInfo info) { if (!state.chatMessages[index].isRead && !isCurrentUserAuthor && info.visibleFraction > 0) { unreadMessagesIdsCopy.add((id: state.chatMessages[index].id, index: index)); - EasyDebounce.debounce( - 'mark_as_read', - Duration(milliseconds: 500), - () async { - final result = await context.read().markMessagesAsRead(state.chatRoom.id, unreadMessagesIdsCopy); - if (!result) return; - context - .read() - .reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIdsCopy.length); - unreadMessagesIdsCopy.clear(); - }, - ); + EasyDebounce.debounce('mark_as_read', Duration(milliseconds: 500), () async { + final result = await context.read().markMessagesAsRead(state.chatRoom.id, unreadMessagesIdsCopy); + if (!result) return; + context.read().reduceUnreadMessagesCount( + chatId: state.chatRoom.id, + count: unreadMessagesIdsCopy.length, + ); + unreadMessagesIdsCopy.clear(); + }); } }, child: ChatBubbleWidget( @@ -233,16 +228,12 @@ class _ChatScreenState extends State { onVisibilityChanged: (VisibilityInfo info) { if (!state.chatMessages[index].isRead && !isCurrentUserAuthor && info.visibleFraction > 0) { unreadMessagesIds.add((id: state.chatMessages[index].id, index: index)); - EasyDebounce.debounce( - 'mark_as_read', - Duration(milliseconds: 500), - () async { - final result = await context.read().markMessagesAsRead(state.chatRoom.id, unreadMessagesIds); - if (!result) return; - context.read().reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIds.length); - unreadMessagesIds.clear(); - }, - ); + EasyDebounce.debounce('mark_as_read', Duration(milliseconds: 500), () async { + final result = await context.read().markMessagesAsRead(state.chatRoom.id, unreadMessagesIds); + if (!result) return; + context.read().reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIds.length); + unreadMessagesIds.clear(); + }); } }, child: ChatBubbleWidget( @@ -282,6 +273,8 @@ class _ChatScreenState extends State { }, ), ), + if (bannerType != null) + Padding(padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), child: NotificationBanner(bannerType: bannerType)), ], ], ], @@ -324,24 +317,14 @@ class _ChatScreenState extends State { if (result != null) { List files = result.paths.map((path) => File(path!)).toList(); - await chatRoomCubit.sendMessage( - chatId: widget.chatId, - files: files, - ); + await chatRoomCubit.sendMessage(chatId: widget.chatId, files: files); } }, customBorder: CircleBorder(), child: Ink( height: 40, width: 40, - child: Transform.rotate( - angle: pi / 4, - child: Icon( - Icons.attach_file_rounded, - size: 30, - color: Color(0xFF858E99), - ), - ), + child: Transform.rotate(angle: pi / 4, child: Icon(Icons.attach_file_rounded, size: 30, color: Color(0xFF858E99))), ), ), SizedBox(width: 8), @@ -360,33 +343,16 @@ class _ChatScreenState extends State { isDense: true, contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 10), hintText: 'Сообщение', - hintStyle: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - height: 1, - color: Color(0xFFAEAEB2), - ), + hintStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, height: 1, color: Color(0xFFAEAEB2)), filled: true, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(100), - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, - ), - ), + border: OutlineInputBorder(borderRadius: BorderRadius.circular(100), borderSide: BorderSide(color: Color(0xFFD1D1D6), width: 1)), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(100), - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, - ), + borderSide: BorderSide(color: Color(0xFFD1D1D6), width: 1), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(100), - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, - ), + borderSide: BorderSide(color: Color(0xFFD1D1D6), width: 1), ), ), ), @@ -397,27 +363,17 @@ class _ChatScreenState extends State { customBorder: CircleBorder(), onTap: () { if (textEditingController.text.isNotEmpty) { - chatRoomCubit.sendMessage( - chatId: widget.chatId, - data: textEditingController.text.trim(), - ); + chatRoomCubit.sendMessage(chatId: widget.chatId, data: textEditingController.text.trim()); setState(() { textEditingController.clear(); }); } }, child: Ink( - decoration: BoxDecoration( - color: appTheme.blueA400, - shape: BoxShape.circle, - ), + decoration: BoxDecoration(color: appTheme.blueA400, shape: BoxShape.circle), height: 40, width: 40, - child: Icon( - Icons.arrow_upward_rounded, - size: 24, - color: Colors.white, - ), + child: Icon(Icons.arrow_upward_rounded, size: 24, color: Colors.white), ), ), SizedBox(width: 8), @@ -426,13 +382,7 @@ class _ChatScreenState extends State { ), ], ), - if (showAboutOrderButton) - Positioned( - top: 8, - right: 15, - left: 16, - child: AboutOrderButton(), - ), + if (showAboutOrderButton) Positioned(top: 8, right: 15, left: 16, child: AboutOrderButton()), ], ), ), @@ -443,16 +393,7 @@ class _ChatScreenState extends State { return Center( child: Padding( padding: const EdgeInsets.only(top: 32), - child: Text( - DateFormat.yMMMMd('RU').format( - date, - ), - style: const TextStyle( - height: 1, - color: Color(0xFF8393A1), - fontWeight: FontWeight.w500, - ), - ), + child: Text(DateFormat.yMMMMd('RU').format(date), style: const TextStyle(height: 1, color: Color(0xFF8393A1), fontWeight: FontWeight.w500)), ), ); } diff --git a/lib/features/create_diet/repositories/create_diet_repository.dart b/lib/features/create_diet/repositories/create_diet_repository.dart index 3661dfd9..e72f159b 100644 --- a/lib/features/create_diet/repositories/create_diet_repository.dart +++ b/lib/features/create_diet/repositories/create_diet_repository.dart @@ -36,7 +36,7 @@ class CreateDietRepository { dietMap.addAll({ 'name': name, - 'details': details, + 'description_md': details, 'duration': duration, 'type[meat]': meatType, 'type[carb]': carbType, @@ -115,7 +115,7 @@ class CreateDietRepository { dietMap.addAll({'name': name}); } if (details != null) { - dietMap.addAll({'details': details}); + dietMap.addAll({'description_md': details}); } if (duration != null) { dietMap.addAll({'duration': duration}); diff --git a/lib/features/create_plan/models/create_plan_model.dart b/lib/features/create_plan/models/create_plan_model.dart index 37e4b883..75187284 100644 --- a/lib/features/create_plan/models/create_plan_model.dart +++ b/lib/features/create_plan/models/create_plan_model.dart @@ -27,7 +27,7 @@ class CreatePlanModel with _$CreatePlanModel { 'duration': duration, 'state': state, 'type': type, - 'details': details, + 'description_md': details, 'image': image != null ? await MultipartFile.fromFile((await ImageCompressUtility.compressFile(File(image!.path))).path, filename: image!.name) : null, }; diff --git a/lib/features/create_recipe/models/recipe_create_model.dart b/lib/features/create_recipe/models/recipe_create_model.dart index 747e165f..a38398d9 100644 --- a/lib/features/create_recipe/models/recipe_create_model.dart +++ b/lib/features/create_recipe/models/recipe_create_model.dart @@ -21,7 +21,7 @@ class RecipeCreateModel with _$RecipeCreateModel { const factory RecipeCreateModel({ required String title, required String state, - required String description, + @JsonKey(name: 'description_md') required String description, required RecipeType type, @JsonKey(name: 'video_url') String? videoUrl, @JsonKey(name: 'cooking_time') String? cookingTime, diff --git a/lib/features/create_recipe/models/recipe_create_model.freezed.dart b/lib/features/create_recipe/models/recipe_create_model.freezed.dart index b64ed74e..5e4efb8d 100644 --- a/lib/features/create_recipe/models/recipe_create_model.freezed.dart +++ b/lib/features/create_recipe/models/recipe_create_model.freezed.dart @@ -23,6 +23,7 @@ RecipeCreateModel _$RecipeCreateModelFromJson(Map json) { mixin _$RecipeCreateModel { String get title => throw _privateConstructorUsedError; String get state => throw _privateConstructorUsedError; + @JsonKey(name: 'description_md') String get description => throw _privateConstructorUsedError; RecipeType get type => throw _privateConstructorUsedError; @JsonKey(name: 'video_url') @@ -58,7 +59,7 @@ abstract class $RecipeCreateModelCopyWith<$Res> { $Res call({ String title, String state, - String description, + @JsonKey(name: 'description_md') String description, RecipeType type, @JsonKey(name: 'video_url') String? videoUrl, @JsonKey(name: 'cooking_time') String? cookingTime, @@ -179,7 +180,7 @@ abstract class _$$RecipeCreateModelImplCopyWith<$Res> $Res call({ String title, String state, - String description, + @JsonKey(name: 'description_md') String description, RecipeType type, @JsonKey(name: 'video_url') String? videoUrl, @JsonKey(name: 'cooking_time') String? cookingTime, @@ -292,7 +293,7 @@ class _$RecipeCreateModelImpl implements _RecipeCreateModel { const _$RecipeCreateModelImpl({ required this.title, required this.state, - required this.description, + @JsonKey(name: 'description_md') required this.description, required this.type, @JsonKey(name: 'video_url') this.videoUrl, @JsonKey(name: 'cooking_time') this.cookingTime, @@ -314,6 +315,7 @@ class _$RecipeCreateModelImpl implements _RecipeCreateModel { @override final String state; @override + @JsonKey(name: 'description_md') final String description; @override final RecipeType type; @@ -427,7 +429,7 @@ abstract class _RecipeCreateModel implements RecipeCreateModel { const factory _RecipeCreateModel({ required final String title, required final String state, - required final String description, + @JsonKey(name: 'description_md') required final String description, required final RecipeType type, @JsonKey(name: 'video_url') final String? videoUrl, @JsonKey(name: 'cooking_time') final String? cookingTime, @@ -447,6 +449,7 @@ abstract class _RecipeCreateModel implements RecipeCreateModel { @override String get state; @override + @JsonKey(name: 'description_md') String get description; @override RecipeType get type; diff --git a/lib/features/create_recipe/models/recipe_create_model.g.dart b/lib/features/create_recipe/models/recipe_create_model.g.dart index 4926d92f..6f3efc13 100644 --- a/lib/features/create_recipe/models/recipe_create_model.g.dart +++ b/lib/features/create_recipe/models/recipe_create_model.g.dart @@ -11,7 +11,7 @@ _$RecipeCreateModelImpl _$$RecipeCreateModelImplFromJson( ) => _$RecipeCreateModelImpl( title: json['title'] as String, state: json['state'] as String, - description: json['description'] as String, + description: json['description_md'] as String, type: $enumDecode(_$RecipeTypeEnumMap, json['type']), videoUrl: json['video_url'] as String?, cookingTime: json['cooking_time'] as String?, @@ -34,7 +34,7 @@ Map _$$RecipeCreateModelImplToJson( ) => { 'title': instance.title, 'state': instance.state, - 'description': instance.description, + 'description_md': instance.description, 'type': _$RecipeTypeEnumMap[instance.type]!, 'video_url': instance.videoUrl, 'cooking_time': instance.cookingTime, diff --git a/lib/features/create_recipe/reporitories/recipe_repository.dart b/lib/features/create_recipe/reporitories/recipe_repository.dart index f1284fd6..233c2c88 100644 --- a/lib/features/create_recipe/reporitories/recipe_repository.dart +++ b/lib/features/create_recipe/reporitories/recipe_repository.dart @@ -43,13 +43,13 @@ class RecipeRepository { if (step != null) { if ((step.image == null || (step.image?.isEmpty ?? true)) && step.description != null) { stepsMap.add({ - 'description': step.description ?? "", + 'description_md': step.description ?? "", }); } else if (step.image != null && (step.image?.isNotEmpty ?? false)) { final image = await ImageCompressUtility.compressFile(File(step.image ?? '')); final multipartFile = await MultipartFile.fromFile(image.path); stepsMap.add({ - 'description': step.description ?? "", + 'description_md': step.description ?? "", 'image': multipartFile, }); } @@ -60,7 +60,7 @@ class RecipeRepository { 'state': 'active', 'title': recipe.title, 'tags': recipe.tags, - 'description': recipe.description, + 'description_md': recipe.description, 'video_url': recipe.video_url, 'ingredients': ingredientsMap, 'steps': stepsMap, diff --git a/lib/features/dev_tools/presentation/dev_tools_screen.dart b/lib/features/dev_tools/presentation/dev_tools_screen.dart index 3b1067f7..32de0606 100644 --- a/lib/features/dev_tools/presentation/dev_tools_screen.dart +++ b/lib/features/dev_tools/presentation/dev_tools_screen.dart @@ -1,9 +1,15 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; import 'package:eatvio_app/core/const.dart'; +import 'package:eatvio_app/core/firebase_api.dart'; +import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/utils/toasts.dart'; import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; import 'package:eatvio_app/core/widgets/custom_text_form_field.dart'; import 'package:eatvio_app/features/dev_tools/test_cases.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; class DevToolsScreen extends StatelessWidget { const DevToolsScreen({super.key}); @@ -61,9 +67,7 @@ class _DevToolsScreenContentState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text('Для разработчиков'), - ), + appBar: AppBar(title: Text('Для разработчиков')), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 10), @@ -99,6 +103,7 @@ class _DevToolsScreenContentState extends State { ListView.builder( shrinkWrap: true, itemCount: testCases.length, + physics: NeverScrollableScrollPhysics(), itemBuilder: (context, index) => Padding( padding: const EdgeInsets.only(bottom: 10.0), @@ -151,6 +156,80 @@ class _DevToolsScreenContentState extends State { ), ), ), + const SizedBox(height: 10), + CustomOutlinedButton( + text: 'add token to server', + buttonStyle: ButtonStyle(), + onPressed: () async { + try { + final dio = sl(); + final String platform; + if (Platform.isAndroid) { + platform = 'android'; + } else { + platform = 'ios'; + } + await dio.post('/api/profile/notification/token/register', data: {'token': await FirebaseApi().getToken(), 'platform': platform}); + showInfoToast('Токен добавлен'); + } catch (e) { + showInfoToast('Не удалось добавть токен'); + } + }, + ), + const SizedBox(height: 10), + CustomOutlinedButton( + text: 'copy token', + buttonStyle: ButtonStyle(), + onPressed: () async { + try { + final token = await FirebaseApi().getToken(); + if (token != null) { + Clipboard.setData(ClipboardData(text: token)); + showInfoToast('Токен скопирован'); + } else { + showInfoToast('Token is null'); + } + } catch (e) { + showInfoToast('Не получилось скопировать токен'); + } + }, + ), + const SizedBox(height: 10), + CustomOutlinedButton( + text: 'remove token from server', + buttonStyle: ButtonStyle(), + onPressed: () async { + try { + final dio = sl(); + final String platform; + if (Platform.isAndroid) { + platform = 'android'; + } else { + platform = 'ios'; + } + await dio.post('/api/profile/notification/token/unregister', data: {'token': await FirebaseApi().getToken(), 'platform': platform}); + showInfoToast('Токен удалён'); + } catch (e) { + showInfoToast('Не удалось удалить токен'); + } + }, + ), + const SizedBox(height: 10), + CustomOutlinedButton( + text: 'send notification', + buttonStyle: ButtonStyle(), + onPressed: () async { + try { + final dio = sl(); + Future.delayed(Duration(seconds: 3), () async { + await dio.post('/api/profile/notification/token/test'); + }); + } catch (e) { + showInfoToast('Не удалось добавть токен'); + } + }, + ), + const SizedBox(height: 300), ], ), ), diff --git a/lib/features/diets/presentation/widgets/expandable_text.dart b/lib/features/diets/presentation/widgets/expandable_text.dart index 37285909..72f7467b 100644 --- a/lib/features/diets/presentation/widgets/expandable_text.dart +++ b/lib/features/diets/presentation/widgets/expandable_text.dart @@ -4,7 +4,6 @@ import 'package:eatvio_app/generated/l10n.dart'; import 'package:eatvio_app/core/theme/custom_text_style.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_svg/svg.dart'; class ExpandableText extends StatefulWidget { @@ -36,16 +35,17 @@ class _ExpandableTextState extends State { padding: const EdgeInsets.symmetric(horizontal: 16), child: Stack( children: [ - Html( - data: widget.text, - style: { - "*": Style( - margin: Margins.all(0), - color: Colors.black87, - maxLines: isExpanded ? null : widget.maxLines, - textOverflow: TextOverflow.clip, - ), - }, + Text( + widget.text, + style: TextStyles.textMMediumAuto.copyWith(color: appTheme.black), + // style: { + // "*": Style( + // margin: Margins.all(0), + // color: Colors.black87, + // maxLines: isExpanded ? null : widget.maxLines, + // textOverflow: TextOverflow.clip, + // ), + // }, ), if (!isExpanded) Positioned.fill( @@ -57,11 +57,7 @@ class _ExpandableTextState extends State { gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, - colors: [ - Colors.white.withValues(alpha: 0.0), - Colors.white.withValues(alpha: 0.6), - Colors.white, - ], + colors: [Colors.white.withValues(alpha: 0.0), Colors.white.withValues(alpha: 0.6), Colors.white], ), ), ), @@ -77,10 +73,7 @@ class _ExpandableTextState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - isExpanded ? s.hide : s.expand, - style: TextStyles.textMMedium.copyWith(color: appTheme.blueA400), - ), + Text(isExpanded ? s.hide : s.expand, style: TextStyles.textMMedium.copyWith(color: appTheme.blueA400)), Transform.rotate(angle: isExpanded ? math.pi : 0, child: SvgPicture.asset('assets/icons/arrow_down.svg', width: 12, height: 12)), ], ), diff --git a/lib/features/feed/models/diets_pagination_model.dart b/lib/features/feed/models/diets_pagination_model.dart index 3907fe8a..00f8e520 100644 --- a/lib/features/feed/models/diets_pagination_model.dart +++ b/lib/features/feed/models/diets_pagination_model.dart @@ -25,7 +25,7 @@ class Diet with _$Diet { @JsonKey(name: "duration") required int duration, @JsonKey(name: "state") required DietState state, @JsonKey(name: "type") required DietType type, - @JsonKey(name: "details") required String details, + @JsonKey(name: "description_md") required String details, @JsonKey(name: "daily_schedule") required Map>> dailySchedule, @JsonKey(name: "author") required Author author, @JsonKey(name: "total_likes") required int totalLikes, diff --git a/lib/features/feed/models/diets_pagination_model.freezed.dart b/lib/features/feed/models/diets_pagination_model.freezed.dart index 398cb653..ad7a4b07 100644 --- a/lib/features/feed/models/diets_pagination_model.freezed.dart +++ b/lib/features/feed/models/diets_pagination_model.freezed.dart @@ -285,7 +285,7 @@ mixin _$Diet { DietState get state => throw _privateConstructorUsedError; @JsonKey(name: "type") DietType get type => throw _privateConstructorUsedError; - @JsonKey(name: "details") + @JsonKey(name: "description_md") String get details => throw _privateConstructorUsedError; @JsonKey(name: "daily_schedule") Map>> get dailySchedule => @@ -326,7 +326,7 @@ abstract class $DietCopyWith<$Res> { @JsonKey(name: "duration") int duration, @JsonKey(name: "state") DietState state, @JsonKey(name: "type") DietType type, - @JsonKey(name: "details") String details, + @JsonKey(name: "description_md") String details, @JsonKey(name: "daily_schedule") Map>> dailySchedule, @JsonKey(name: "author") Author author, @@ -491,7 +491,7 @@ abstract class _$$DietImplCopyWith<$Res> implements $DietCopyWith<$Res> { @JsonKey(name: "duration") int duration, @JsonKey(name: "state") DietState state, @JsonKey(name: "type") DietType type, - @JsonKey(name: "details") String details, + @JsonKey(name: "description_md") String details, @JsonKey(name: "daily_schedule") Map>> dailySchedule, @JsonKey(name: "author") Author author, @@ -629,7 +629,7 @@ class _$DietImpl implements _Diet { @JsonKey(name: "duration") required this.duration, @JsonKey(name: "state") required this.state, @JsonKey(name: "type") required this.type, - @JsonKey(name: "details") required this.details, + @JsonKey(name: "description_md") required this.details, @JsonKey(name: "daily_schedule") required final Map>> dailySchedule, @JsonKey(name: "author") required this.author, @@ -665,7 +665,7 @@ class _$DietImpl implements _Diet { @JsonKey(name: "type") final DietType type; @override - @JsonKey(name: "details") + @JsonKey(name: "description_md") final String details; final Map>> _dailySchedule; @override @@ -785,7 +785,7 @@ abstract class _Diet implements Diet { @JsonKey(name: "duration") required final int duration, @JsonKey(name: "state") required final DietState state, @JsonKey(name: "type") required final DietType type, - @JsonKey(name: "details") required final String details, + @JsonKey(name: "description_md") required final String details, @JsonKey(name: "daily_schedule") required final Map>> dailySchedule, @JsonKey(name: "author") required final Author author, @@ -819,7 +819,7 @@ abstract class _Diet implements Diet { @JsonKey(name: "type") DietType get type; @override - @JsonKey(name: "details") + @JsonKey(name: "description_md") String get details; @override @JsonKey(name: "daily_schedule") diff --git a/lib/features/feed/models/diets_pagination_model.g.dart b/lib/features/feed/models/diets_pagination_model.g.dart index f8e66d9f..93258944 100644 --- a/lib/features/feed/models/diets_pagination_model.g.dart +++ b/lib/features/feed/models/diets_pagination_model.g.dart @@ -32,7 +32,7 @@ _$DietImpl _$$DietImplFromJson(Map json) => _$DietImpl( duration: (json['duration'] as num).toInt(), state: $enumDecode(_$DietStateEnumMap, json['state']), type: DietType.fromJson(json['type'] as Map), - details: json['details'] as String, + details: json['description_md'] as String, dailySchedule: (json['daily_schedule'] as Map).map( (k, e) => MapEntry( int.parse(k), @@ -70,7 +70,7 @@ Map _$$DietImplToJson( 'duration': instance.duration, 'state': _$DietStateEnumMap[instance.state]!, 'type': instance.type, - 'details': instance.details, + 'description_md': instance.details, 'daily_schedule': instance.dailySchedule.map( (k, e) => MapEntry( k.toString(), diff --git a/lib/features/feed/models/plan_pagination_model.dart b/lib/features/feed/models/plan_pagination_model.dart index 5af99db7..c4eeb71b 100644 --- a/lib/features/feed/models/plan_pagination_model.dart +++ b/lib/features/feed/models/plan_pagination_model.dart @@ -58,7 +58,7 @@ class PacketOptions with _$PacketOptions { @JsonKey(name: "items") required List items, @JsonKey(name: "price") required dynamic price, @JsonKey(name: "short") required String short, - @JsonKey(name: "description") required String description, + @JsonKey(name: "description_md") required String description, }) = _PacketOptions; factory PacketOptions.fromJson(Map json) => _$PacketOptionsFromJson(json); diff --git a/lib/features/feed/models/plan_pagination_model.freezed.dart b/lib/features/feed/models/plan_pagination_model.freezed.dart index bcf2a193..0ed900bb 100644 --- a/lib/features/feed/models/plan_pagination_model.freezed.dart +++ b/lib/features/feed/models/plan_pagination_model.freezed.dart @@ -1036,7 +1036,7 @@ mixin _$PacketOptions { dynamic get price => throw _privateConstructorUsedError; @JsonKey(name: "short") String get short => throw _privateConstructorUsedError; - @JsonKey(name: "description") + @JsonKey(name: "description_md") String get description => throw _privateConstructorUsedError; /// Serializes this PacketOptions to a JSON map. @@ -1060,7 +1060,7 @@ abstract class $PacketOptionsCopyWith<$Res> { @JsonKey(name: "items") List items, @JsonKey(name: "price") dynamic price, @JsonKey(name: "short") String short, - @JsonKey(name: "description") String description, + @JsonKey(name: "description_md") String description, }); } @@ -1125,7 +1125,7 @@ abstract class _$$PacketOptionsImplCopyWith<$Res> @JsonKey(name: "items") List items, @JsonKey(name: "price") dynamic price, @JsonKey(name: "short") String short, - @JsonKey(name: "description") String description, + @JsonKey(name: "description_md") String description, }); } @@ -1182,7 +1182,7 @@ class _$PacketOptionsImpl implements _PacketOptions { @JsonKey(name: "items") required final List items, @JsonKey(name: "price") required this.price, @JsonKey(name: "short") required this.short, - @JsonKey(name: "description") required this.description, + @JsonKey(name: "description_md") required this.description, }) : _items = items; factory _$PacketOptionsImpl.fromJson(Map json) => @@ -1204,7 +1204,7 @@ class _$PacketOptionsImpl implements _PacketOptions { @JsonKey(name: "short") final String short; @override - @JsonKey(name: "description") + @JsonKey(name: "description_md") final String description; @override @@ -1253,7 +1253,7 @@ abstract class _PacketOptions implements PacketOptions { @JsonKey(name: "items") required final List items, @JsonKey(name: "price") required final dynamic price, @JsonKey(name: "short") required final String short, - @JsonKey(name: "description") required final String description, + @JsonKey(name: "description_md") required final String description, }) = _$PacketOptionsImpl; factory _PacketOptions.fromJson(Map json) = @@ -1269,7 +1269,7 @@ abstract class _PacketOptions implements PacketOptions { @JsonKey(name: "short") String get short; @override - @JsonKey(name: "description") + @JsonKey(name: "description_md") String get description; /// Create a copy of PacketOptions diff --git a/lib/features/feed/models/plan_pagination_model.g.dart b/lib/features/feed/models/plan_pagination_model.g.dart index f9a2ccee..08771efc 100644 --- a/lib/features/feed/models/plan_pagination_model.g.dart +++ b/lib/features/feed/models/plan_pagination_model.g.dart @@ -93,7 +93,7 @@ _$PacketOptionsImpl _$$PacketOptionsImplFromJson(Map json) => items: (json['items'] as List).map((e) => e as String).toList(), price: json['price'], short: json['short'] as String, - description: json['description'] as String, + description: json['description_md'] as String, ); Map _$$PacketOptionsImplToJson(_$PacketOptionsImpl instance) => @@ -101,7 +101,7 @@ Map _$$PacketOptionsImplToJson(_$PacketOptionsImpl instance) => 'items': instance.items, 'price': instance.price, 'short': instance.short, - 'description': instance.description, + 'description_md': instance.description, }; _$PlanTypeImpl _$$PlanTypeImplFromJson(Map json) => diff --git a/lib/features/feed/models/recipes_model.dart b/lib/features/feed/models/recipes_model.dart index 3a5b56ff..6a5668bd 100644 --- a/lib/features/feed/models/recipes_model.dart +++ b/lib/features/feed/models/recipes_model.dart @@ -35,21 +35,14 @@ class Recipe with _$Recipe { @freezed class Ingredient with _$Ingredient { - const factory Ingredient({ - required String name, - String? unit, - required String portion, - }) = _Ingredient; + const factory Ingredient({required String name, String? unit, required String portion}) = _Ingredient; factory Ingredient.fromJson(Map json) => _$IngredientFromJson(json); } @freezed class Step with _$Step { - const factory Step({ - required String image, - required String description, - }) = _Step; + const factory Step({required String image, @JsonKey(name: 'description_md') required String description}) = _Step; factory Step.fromJson(Map json) => _$StepFromJson(json); } diff --git a/lib/features/feed/models/recipes_model.freezed.dart b/lib/features/feed/models/recipes_model.freezed.dart index 3e062bab..ed3d6d3e 100644 --- a/lib/features/feed/models/recipes_model.freezed.dart +++ b/lib/features/feed/models/recipes_model.freezed.dart @@ -929,6 +929,7 @@ Step _$StepFromJson(Map json) { /// @nodoc mixin _$Step { String get image => throw _privateConstructorUsedError; + @JsonKey(name: 'description_md') String get description => throw _privateConstructorUsedError; /// Serializes this Step to a JSON map. @@ -945,7 +946,10 @@ abstract class $StepCopyWith<$Res> { factory $StepCopyWith(Step value, $Res Function(Step) then) = _$StepCopyWithImpl<$Res, Step>; @useResult - $Res call({String image, String description}); + $Res call({ + String image, + @JsonKey(name: 'description_md') String description, + }); } /// @nodoc @@ -989,7 +993,10 @@ abstract class _$$StepImplCopyWith<$Res> implements $StepCopyWith<$Res> { ) = __$$StepImplCopyWithImpl<$Res>; @override @useResult - $Res call({String image, String description}); + $Res call({ + String image, + @JsonKey(name: 'description_md') String description, + }); } /// @nodoc @@ -1024,7 +1031,10 @@ class __$$StepImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() class _$StepImpl implements _Step { - const _$StepImpl({required this.image, required this.description}); + const _$StepImpl({ + required this.image, + @JsonKey(name: 'description_md') required this.description, + }); factory _$StepImpl.fromJson(Map json) => _$$StepImplFromJson(json); @@ -1032,6 +1042,7 @@ class _$StepImpl implements _Step { @override final String image; @override + @JsonKey(name: 'description_md') final String description; @override @@ -1070,7 +1081,7 @@ class _$StepImpl implements _Step { abstract class _Step implements Step { const factory _Step({ required final String image, - required final String description, + @JsonKey(name: 'description_md') required final String description, }) = _$StepImpl; factory _Step.fromJson(Map json) = _$StepImpl.fromJson; @@ -1078,6 +1089,7 @@ abstract class _Step implements Step { @override String get image; @override + @JsonKey(name: 'description_md') String get description; /// Create a copy of Step diff --git a/lib/features/feed/models/recipes_model.g.dart b/lib/features/feed/models/recipes_model.g.dart index 43a99cb9..ff44c0e2 100644 --- a/lib/features/feed/models/recipes_model.g.dart +++ b/lib/features/feed/models/recipes_model.g.dart @@ -78,11 +78,11 @@ Map _$$IngredientImplToJson(_$IngredientImpl instance) => _$StepImpl _$$StepImplFromJson(Map json) => _$StepImpl( image: json['image'] as String, - description: json['description'] as String, + description: json['description_md'] as String, ); Map _$$StepImplToJson(_$StepImpl instance) => { 'image': instance.image, - 'description': instance.description, + 'description_md': instance.description, }; diff --git a/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_cubit.dart b/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_cubit.dart index a2c22389..c35b8ed1 100644 --- a/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_cubit.dart +++ b/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_cubit.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'package:easy_debounce/easy_debounce.dart'; +import 'package:eatvio_app/core/enums/base_state.dart'; import 'package:eatvio_app/features/my_finance/models/payment_url_model.dart'; import 'package:eatvio_app/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_state.dart'; import 'package:eatvio_app/features/my_finance/repositories/cards_repository.dart'; @@ -22,10 +23,12 @@ class UserCardsCubit extends Cubit { Future getCards() async { try { if (isClosed) return; + emit(state.copyWith(state: BaseState.loading)); final cards = await cardsRepository.getCards(); - emit(state.copyWith(cards: cards)); + emit(state.copyWith(cards: cards, state: BaseState.success)); } catch (e, st) { log(e.toString(), stackTrace: st); + emit(state.copyWith(state: BaseState.error, error: e.toString())); } } @@ -59,7 +62,7 @@ class UserCardsCubit extends Cubit { emit(state.copyWith(cards: cards)); await cardsRepository.deleteCard(id: id); } catch (e, st) { - emit(state.copyWith(cards: oldCards)); + emit(state.copyWith(cards: oldCards, error: e.toString(), state: BaseState.error)); log(e.toString(), stackTrace: st); } } diff --git a/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_state.dart b/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_state.dart index d9fcd376..93e57dd7 100644 --- a/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_state.dart +++ b/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_state.dart @@ -1,3 +1,4 @@ +import 'package:eatvio_app/core/enums/base_state.dart'; import 'package:eatvio_app/features/my_finance/models/card_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -7,8 +8,9 @@ part 'user_cards_state.freezed.dart'; class UserCardsState with _$UserCardsState { factory UserCardsState({ - @Default([]) List cards, - @Default(false) bool isLoading, + @Default([]) List cards, + @Default(null) String? error, + @Default(BaseState.initial) BaseState state, }) = _UserCardsState; } \ No newline at end of file diff --git a/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_state.freezed.dart b/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_state.freezed.dart index 6af8348f..b8b630e9 100644 --- a/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_state.freezed.dart +++ b/lib/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_state.freezed.dart @@ -18,7 +18,8 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$UserCardsState { List get cards => throw _privateConstructorUsedError; - bool get isLoading => throw _privateConstructorUsedError; + String? get error => throw _privateConstructorUsedError; + BaseState get state => throw _privateConstructorUsedError; /// Create a copy of UserCardsState /// with the given fields replaced by the non-null parameter values. @@ -34,7 +35,7 @@ abstract class $UserCardsStateCopyWith<$Res> { $Res Function(UserCardsState) then, ) = _$UserCardsStateCopyWithImpl<$Res, UserCardsState>; @useResult - $Res call({List cards, bool isLoading}); + $Res call({List cards, String? error, BaseState state}); } /// @nodoc @@ -51,7 +52,11 @@ class _$UserCardsStateCopyWithImpl<$Res, $Val extends UserCardsState> /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({Object? cards = null, Object? isLoading = null}) { + $Res call({ + Object? cards = null, + Object? error = freezed, + Object? state = null, + }) { return _then( _value.copyWith( cards: @@ -59,11 +64,16 @@ class _$UserCardsStateCopyWithImpl<$Res, $Val extends UserCardsState> ? _value.cards : cards // ignore: cast_nullable_to_non_nullable as List, - isLoading: - null == isLoading - ? _value.isLoading - : isLoading // ignore: cast_nullable_to_non_nullable - as bool, + error: + freezed == error + ? _value.error + : error // ignore: cast_nullable_to_non_nullable + as String?, + state: + null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as BaseState, ) as $Val, ); @@ -79,7 +89,7 @@ abstract class _$$UserCardsStateImplCopyWith<$Res> ) = __$$UserCardsStateImplCopyWithImpl<$Res>; @override @useResult - $Res call({List cards, bool isLoading}); + $Res call({List cards, String? error, BaseState state}); } /// @nodoc @@ -95,7 +105,11 @@ class __$$UserCardsStateImplCopyWithImpl<$Res> /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({Object? cards = null, Object? isLoading = null}) { + $Res call({ + Object? cards = null, + Object? error = freezed, + Object? state = null, + }) { return _then( _$UserCardsStateImpl( cards: @@ -103,11 +117,16 @@ class __$$UserCardsStateImplCopyWithImpl<$Res> ? _value._cards : cards // ignore: cast_nullable_to_non_nullable as List, - isLoading: - null == isLoading - ? _value.isLoading - : isLoading // ignore: cast_nullable_to_non_nullable - as bool, + error: + freezed == error + ? _value.error + : error // ignore: cast_nullable_to_non_nullable + as String?, + state: + null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as BaseState, ), ); } @@ -118,7 +137,8 @@ class __$$UserCardsStateImplCopyWithImpl<$Res> class _$UserCardsStateImpl implements _UserCardsState { _$UserCardsStateImpl({ final List cards = const [], - this.isLoading = false, + this.error = null, + this.state = BaseState.initial, }) : _cards = cards; final List _cards; @@ -132,11 +152,14 @@ class _$UserCardsStateImpl implements _UserCardsState { @override @JsonKey() - final bool isLoading; + final String? error; + @override + @JsonKey() + final BaseState state; @override String toString() { - return 'UserCardsState(cards: $cards, isLoading: $isLoading)'; + return 'UserCardsState(cards: $cards, error: $error, state: $state)'; } @override @@ -145,15 +168,16 @@ class _$UserCardsStateImpl implements _UserCardsState { (other.runtimeType == runtimeType && other is _$UserCardsStateImpl && const DeepCollectionEquality().equals(other._cards, _cards) && - (identical(other.isLoading, isLoading) || - other.isLoading == isLoading)); + (identical(other.error, error) || other.error == error) && + (identical(other.state, state) || other.state == state)); } @override int get hashCode => Object.hash( runtimeType, const DeepCollectionEquality().hash(_cards), - isLoading, + error, + state, ); /// Create a copy of UserCardsState @@ -169,13 +193,18 @@ class _$UserCardsStateImpl implements _UserCardsState { } abstract class _UserCardsState implements UserCardsState { - factory _UserCardsState({final List cards, final bool isLoading}) = - _$UserCardsStateImpl; + factory _UserCardsState({ + final List cards, + final String? error, + final BaseState state, + }) = _$UserCardsStateImpl; @override List get cards; @override - bool get isLoading; + String? get error; + @override + BaseState get state; /// Create a copy of UserCardsState /// with the given fields replaced by the non-null parameter values. diff --git a/lib/features/my_finance/presentation/pages/card_settings.dart b/lib/features/my_finance/presentation/pages/card_settings.dart index caa6a6e0..36ef45e9 100644 --- a/lib/features/my_finance/presentation/pages/card_settings.dart +++ b/lib/features/my_finance/presentation/pages/card_settings.dart @@ -1,6 +1,9 @@ +import 'package:eatvio_app/core/enums/base_state.dart'; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/theme/custom_text_style.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/widgets/data_error_widget.dart'; +import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_cubit.dart'; import 'package:eatvio_app/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_state.dart'; import 'package:eatvio_app/features/my_finance/presentation/widgets/card_widget.dart'; @@ -35,9 +38,9 @@ class CardsSettingsContent extends StatelessWidget { body: Column( children: [ const SizedBox(height: 16), - Material( - borderRadius: BorderRadius.circular(12), - color: Colors.white, + Container( + decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white), + width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -64,21 +67,39 @@ class CardsSettingsContent extends StatelessWidget { ), const SizedBox(height: 16), SingleChildScrollView( - padding: EdgeInsets.symmetric(horizontal: 16), scrollDirection: Axis.horizontal, child: BlocBuilder( builder: (context, state) { - if (state.isLoading) {} - return Row( - spacing: 12, - children: List.generate(state.cards.length + 1, (index) { - if (index < state.cards.length) { - final cardsNumber = state.cards[index].cardNumber.substring(state.cards[index].cardNumber.length - 7); - return CardWidget(isSelected: state.cards[index].isDefault, cardId: state.cards[index].id, cardNumber: cardsNumber); - } - return CardWidget(enabledAddCard: true); - }), - ); + switch (state.state) { + case BaseState.error: + return SizedBox( + width: MediaQuery.sizeOf(context).width, + child: Center( + child: DataErrorWidget( + onReload: () async { + context.read().getCards(); + }, + ), + ), + ); + case BaseState.success: + return Padding( + padding: EdgeInsets.only(left: 12), + child: Row( + spacing: 12, + children: List.generate(state.cards.length + 1, (index) { + if (index < state.cards.length) { + final cardsNumber = state.cards[index].cardNumber.substring(state.cards[index].cardNumber.length - 7); + return CardWidget(isSelected: state.cards[index].isDefault, cardId: state.cards[index].id, cardNumber: cardsNumber); + } + return CardWidget(enabledAddCard: true); + }), + ), + ); + + default: + return SizedBox(width: MediaQuery.sizeOf(context).width, height: 200, child: Center(child: Loader())); + } }, ), ), diff --git a/lib/features/my_finance/presentation/widgets/card_widget.dart b/lib/features/my_finance/presentation/widgets/card_widget.dart index 22789c21..7d26342f 100644 --- a/lib/features/my_finance/presentation/widgets/card_widget.dart +++ b/lib/features/my_finance/presentation/widgets/card_widget.dart @@ -16,53 +16,68 @@ class CardWidget extends StatelessWidget { @override Widget build(BuildContext context) { final s = S.of(context); - return GestureDetector( - onTap: enabledAddCard - ? () async { - final addCardUrl = await context.read().addCard(); + return Stack( + children: [ + GestureDetector( + onTap: + enabledAddCard + ? () async { + final addCardUrl = await context.read().addCard(); - if (addCardUrl != null) { - final uri = Uri.parse(addCardUrl.paymentUrl); - if (await canLaunchUrl(uri)) { - await launchUrl(uri, mode: LaunchMode.externalApplication); - } - } - } - : () { - context.read().markAsDefault(id: cardId); - }, - child: Container( - padding: EdgeInsets.all(4), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all(color: isSelected ? appTheme.blueA400 : Color(0xFFF1F2F6), width: 2), + if (addCardUrl != null) { + final uri = Uri.parse(addCardUrl.paymentUrl); + if (await canLaunchUrl(uri)) { + await launchUrl(uri, mode: LaunchMode.externalApplication); + } + } + } + : () { + context.read().markAsDefault(id: cardId); + }, + child: Container( + padding: EdgeInsets.all(4), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all(color: isSelected ? appTheme.blueA400 : Color(0xFFF1F2F6), width: 2), + ), + child: + enabledAddCard + ? Container( + width: 148, + padding: EdgeInsets.all(10), + decoration: BoxDecoration(color: Color(0xFFF1F2F6), borderRadius: BorderRadius.circular(4)), + child: Column( + children: [ + SvgPicture.asset('assets/icons/add_card.svg'), + const SizedBox(height: 24), + Text(s.new_card, style: TextStyles.textSSemibold.copyWith(color: appTheme.black)), + ], + ), + ) + : Container( + width: 148, + padding: EdgeInsets.all(10), + decoration: BoxDecoration(color: Color(0xFFF1F2F6), borderRadius: BorderRadius.circular(4)), + child: Column( + children: [ + SvgPicture.asset('assets/icons/card.svg'), + const SizedBox(height: 24), + Text(cardNumber, style: TextStyles.textSSemibold.copyWith(color: appTheme.black)), + ], + ), + ), + ), ), - child: enabledAddCard - ? Container( - width: 148, - padding: EdgeInsets.all(10), - decoration: BoxDecoration(color: Color(0xFFF1F2F6), borderRadius: BorderRadius.circular(4)), - child: Column( - children: [ - SvgPicture.asset('assets/icons/add_card.svg'), - const SizedBox(height: 24), - Text(s.new_card, style: TextStyles.textSSemibold.copyWith(color: appTheme.black)), - ], - ), - ) - : Container( - width: 148, - padding: EdgeInsets.all(10), - decoration: BoxDecoration(color: Color(0xFFF1F2F6), borderRadius: BorderRadius.circular(4)), - child: Column( - children: [ - SvgPicture.asset('assets/icons/card.svg'), - const SizedBox(height: 24), - Text(cardNumber, style: TextStyles.textSSemibold.copyWith(color: appTheme.black)), - ], - ), - ), - ), + if (!enabledAddCard) + Positioned( + top: 12, + right: 12, + child: GestureDetector( + child: SvgPicture.asset('assets/images/img_close_blue_gray_900.svg'), + onTap: () => context.read().deleteCard(id: cardId), + ), + ), + ], ); } } diff --git a/lib/features/recipe/presentation/about_recipe_screen.dart b/lib/features/recipe/presentation/about_recipe_screen.dart index f2a15edd..5f1f6d7f 100644 --- a/lib/features/recipe/presentation/about_recipe_screen.dart +++ b/lib/features/recipe/presentation/about_recipe_screen.dart @@ -67,9 +67,7 @@ class _AboutRecipeScreenState extends State { void _scrollToBottom() { _jumped = true; - scrollController.jumpTo( - scrollController.position.maxScrollExtent, - ); + scrollController.jumpTo(scrollController.position.maxScrollExtent); } @override @@ -78,12 +76,7 @@ class _AboutRecipeScreenState extends State { return BlocProvider( create: (context) => recipeCubit..getRecipe(widget.recipe.slug), child: BlocProvider( - create: (BuildContext context) => commentsCubit - ..getComments( - widget.recipe.slug.toString(), - CommentSourceType.recipe, - true, - ), + create: (BuildContext context) => commentsCubit..getComments(widget.recipe.slug.toString(), CommentSourceType.recipe, true), child: BlocConsumer( listener: (BuildContext context, CommentsState commentsState) { if (commentsState is CommentsStateLoaded) { @@ -106,14 +99,7 @@ class _AboutRecipeScreenState extends State { resizeToAvoidBottomInset: true, bottomSheet: Container( padding: EdgeInsets.symmetric(vertical: 12) + (Platform.isIOS ? const EdgeInsets.only(bottom: 16) : EdgeInsets.zero), - decoration: BoxDecoration( - color: Colors.white, - border: Border( - top: BorderSide( - color: Colors.black.withValues(alpha: 0.1), - ), - ), - ), + decoration: BoxDecoration(color: Colors.white, border: Border(top: BorderSide(color: Colors.black.withValues(alpha: 0.1)))), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( @@ -133,17 +119,10 @@ class _AboutRecipeScreenState extends State { FocusManager.instance.primaryFocus?.unfocus(); }, child: Container( - decoration: BoxDecoration( - color: appTheme.blueA400, - shape: BoxShape.circle, - ), + decoration: BoxDecoration(color: appTheme.blueA400, shape: BoxShape.circle), height: 32, width: 32, - child: Icon( - Icons.close_rounded, - size: 18, - color: Colors.white, - ), + child: Icon(Icons.close_rounded, size: 18, color: Colors.white), ), ), if (replyId != null) SizedBox(width: 8), @@ -159,22 +138,12 @@ class _AboutRecipeScreenState extends State { maxLines: 5, minLines: 1, keyboardType: TextInputType.multiline, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - color: Colors.black, - height: 1.2, - ), + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w400, color: Colors.black, height: 1.2), decoration: InputDecoration( isDense: false, // убираем true, чтобы padding учитывался корректно contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 16), // вертикальный паддинг увеличен hintText: 'Комментарий', - hintStyle: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - height: 1.2, - color: Color(0xFFAEAEB2), - ), + hintStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.w400, height: 1.2, color: Color(0xFFAEAEB2)), filled: true, border: OutlineInputBorder( borderRadius: BorderRadius.circular(16), @@ -214,7 +183,10 @@ class _AboutRecipeScreenState extends State { } }, child: Container( - decoration: BoxDecoration(color: textEditingController.text.length > 2 ? appTheme.blueA400 : Colors.grey, shape: BoxShape.circle), + decoration: BoxDecoration( + color: textEditingController.text.length > 2 ? appTheme.blueA400 : Colors.grey, + shape: BoxShape.circle, + ), height: 32, width: 32, child: Icon(Icons.send_rounded, size: 18, color: Colors.white), @@ -244,22 +216,14 @@ class _AboutRecipeScreenState extends State { path: 'recipe/${widget.recipe.slug}', slug: widget.recipe.slug, ), - anchor: Aligned( - shiftToWithinBound: AxisFlag(x: true, y: true), - follower: Alignment.topRight, - target: Alignment.bottomRight, - ), + anchor: Aligned(shiftToWithinBound: AxisFlag(x: true, y: true), follower: Alignment.topRight, target: Alignment.bottomRight), child: IconButton( onPressed: () { setState(() { isMoreOptionsVisible = !isMoreOptionsVisible; }); }, - icon: SvgPicture.asset( - 'assets/icons/more_button.svg', - width: 20, - height: 20, - ), + icon: SvgPicture.asset('assets/icons/more_button.svg', width: 20, height: 20), ), ), ], @@ -294,10 +258,7 @@ class _AboutRecipeScreenState extends State { children: [ SvgPicture.asset('assets/icons/eye.svg', width: 18, height: 12), SizedBox(width: 8), - Text( - widget.recipe.viewsCount.toString(), - style: TextStyles.textXSSemibold.copyWith(color: appTheme.black), - ), + Text(widget.recipe.viewsCount.toString(), style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)), ], backgroundColor: appTheme.whiteA700, ), @@ -361,17 +322,11 @@ class _AboutRecipeScreenState extends State { SizedBox(height: 16), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), - child: Text( - s.about_recipe, - style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), - ), + child: Text(s.about_recipe, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)), ), SizedBox(height: 12), - InfoRow( - recipe: widget.recipe, - type: ProductType.recipe, - ), - if (widget.recipe.videoUrl != null) + InfoRow(recipe: widget.recipe, type: ProductType.recipe), + if (widget.recipe.videoUrl != null && widget.recipe.videoUrl!.isNotEmpty) Padding( padding: const EdgeInsets.only(left: 16, bottom: 12, top: 12), child: GestureDetector( @@ -389,44 +344,26 @@ class _AboutRecipeScreenState extends State { child: Row( mainAxisSize: MainAxisSize.min, children: [ - Text( - s.check_out_video_recipe, - style: TextStyles.textMSemibold.copyWith( - color: appTheme.black, - ), - ), + Text(s.check_out_video_recipe, style: TextStyles.textMSemibold.copyWith(color: appTheme.black)), SizedBox(width: 12), SvgPicture.asset('assets/icons/play_icon.svg', width: 16, height: 16), ], ), ), ), - ExpandableText( - text: widget.recipe.description, - ), + ExpandableText(text: widget.recipe.description), SizedBox(height: 20), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), - child: AuthorCard( - author: widget.recipe.author, - title: s.recipe_author, - ), + child: AuthorCard(author: widget.recipe.author, title: s.recipe_author), ), SizedBox(height: 16), ], ), ), SizedBox(height: 12), - if (widget.recipe.ingredients?.isNotEmpty == true) - IngredientsWidget( - recipe: widget.recipe, - ), - if (widget.recipe.steps?.isNotEmpty == true) ...[ - SizedBox(height: 12), - StepsWidget( - recipe: widget.recipe, - ), - ], + if (widget.recipe.ingredients?.isNotEmpty == true) IngredientsWidget(recipe: widget.recipe), + if (widget.recipe.steps?.isNotEmpty == true) ...[SizedBox(height: 12), StepsWidget(recipe: widget.recipe)], SizedBox(height: 8), MainBackgroundBouble( padding: EdgeInsets.symmetric(vertical: 16), @@ -437,20 +374,13 @@ class _AboutRecipeScreenState extends State { alignment: Alignment.centerLeft, child: Text( recipeState.recipe.commentsCount.toString() + ' ' + getCommentForm(widget.recipe.commentsCount, s), - style: TextStyles.textMMedium.copyWith( - color: appTheme.gray500, - ), + style: TextStyles.textMMedium.copyWith(color: appTheme.gray500), ), ), SizedBox(height: 16), if (state is CommentsStateLoading) const Loader(), if (state is CommentsStateLoaded) - CommentsWidget( - id: widget.recipe.slug, - commentSourceType: CommentSourceType.recipe, - comment: state.comment, - replyId: replyId, - ), + CommentsWidget(id: widget.recipe.slug, commentSourceType: CommentSourceType.recipe, comment: state.comment, replyId: replyId), ], ), ), @@ -479,29 +409,19 @@ class _AboutRecipeScreenState extends State { path: 'recipe/${widget.recipe.slug}', slug: widget.recipe.slug, ), - anchor: Aligned( - shiftToWithinBound: AxisFlag(x: true, y: true), - follower: Alignment.topRight, - target: Alignment.bottomRight, - ), + anchor: Aligned(shiftToWithinBound: AxisFlag(x: true, y: true), follower: Alignment.topRight, target: Alignment.bottomRight), child: IconButton( onPressed: () { setState(() { isMoreOptionsVisible = !isMoreOptionsVisible; }); }, - icon: SvgPicture.asset( - 'assets/icons/more_button.svg', - width: 20, - height: 20, - ), + icon: SvgPicture.asset('assets/icons/more_button.svg', width: 20, height: 20), ), ), ], ), - body: DataErrorWidget( - onReload: () => context.read().getRecipe(widget.recipe.slug, index: widget.index), - ), + body: DataErrorWidget(onReload: () => context.read().getRecipe(widget.recipe.slug, index: widget.index)), ); } return Scaffold( @@ -523,22 +443,14 @@ class _AboutRecipeScreenState extends State { path: 'recipe/${widget.recipe.slug}', slug: widget.recipe.slug, ), - anchor: Aligned( - shiftToWithinBound: AxisFlag(x: true, y: true), - follower: Alignment.topRight, - target: Alignment.bottomRight, - ), + anchor: Aligned(shiftToWithinBound: AxisFlag(x: true, y: true), follower: Alignment.topRight, target: Alignment.bottomRight), child: IconButton( onPressed: () { setState(() { isMoreOptionsVisible = !isMoreOptionsVisible; }); }, - icon: SvgPicture.asset( - 'assets/icons/more_button.svg', - width: 20, - height: 20, - ), + icon: SvgPicture.asset('assets/icons/more_button.svg', width: 20, height: 20), ), ), ], diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart new file mode 100644 index 00000000..dcf61a5d --- /dev/null +++ b/lib/firebase_options.dart @@ -0,0 +1,70 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: type=lint +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for web - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyBUe1UqAAMfgMcd4hWdRoLF1Os-yn-HE9k', + appId: '1:613980912922:android:4de95e5f2d50ba69ecc0a3', + messagingSenderId: '613980912922', + projectId: 'eatvio-3467b', + databaseURL: 'https://eatvio-3467b-default-rtdb.europe-west1.firebasedatabase.app', + storageBucket: 'eatvio-3467b.firebasestorage.app', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyBnE8tQjL9_1HuXrTnqNy6qbXpoenO36yQ', + appId: '1:613980912922:ios:c557d140a1212e63ecc0a3', + messagingSenderId: '613980912922', + projectId: 'eatvio-3467b', + databaseURL: 'https://eatvio-3467b-default-rtdb.europe-west1.firebasedatabase.app', + storageBucket: 'eatvio-3467b.firebasestorage.app', + iosBundleId: 'com.eatvioapp.app', + ); +} diff --git a/lib/main.dart b/lib/main.dart index 7cdeb5fa..65691c42 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,7 +8,9 @@ import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/prof import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; import 'package:eatvio_app/features/internet_connection_checker/internet_connection_checker_screen.dart'; +import 'package:eatvio_app/firebase_options.dart'; import 'package:eatvio_app/generated/l10n.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; @@ -20,14 +22,12 @@ import 'package:sentry_flutter/sentry_flutter.dart'; Future main() async { WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); + await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); await di.init(); - await SentryFlutter.init( - (options) { - options.dsn = 'http://ba7f2653067776f3034e6e89850e85a1@sentry.md-desk.ru:9000/2'; - options.tracesSampleRate = 1.0; - }, - appRunner: () => runApp(MyApp()), - ); + await SentryFlutter.init((options) { + options.dsn = 'http://ba7f2653067776f3034e6e89850e85a1@sentry.md-desk.ru:9000/2'; + options.tracesSampleRate = 1.0; + }, appRunner: () => runApp(MyApp())); FlutterNativeSplash.remove(); } @@ -55,9 +55,7 @@ class MyApp extends StatelessWidget { GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], - supportedLocales: [ - Locale.fromSubtags(languageCode: 'ru'), - ], + supportedLocales: [Locale.fromSubtags(languageCode: 'ru')], ), ), ), diff --git a/pubspec.yaml b/pubspec.yaml index a6ab85d4..59a1033d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: eatvio_app description: A new Flutter project. -version: 1.0.48+48 +version: 1.0.50+3 publish_to: 'none' environment: @@ -62,6 +62,8 @@ dependencies: sentry_flutter: ^8.13.0 connectivity_plus: ^6.1.3 visibility_detector: ^0.4.0+2 + firebase_core: ^3.12.1 + firebase_messaging: ^15.2.4 dependency_overrides: intl: ^0.19.0