forked from eatvio/eatvio_app
Merge pull request 'main' (#24) from eatvio/eatvio_app:main into main
Reviewed-on: mso7nueh/eatvio_app#24
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,3 +9,4 @@
|
||||
/node_modules/
|
||||
/android/app/release/app-release.aab
|
||||
/android/app/upload-keystore.jks
|
||||
/android/app/.cxx
|
||||
|
||||
@@ -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
|
||||
|
||||
30
android/app/google-services.json
Normal file
30
android/app/google-services.json
Normal file
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
30
firebase.json
Normal file
30
firebase.json
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
EB9FE5381C3F532BD9A9456D /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
FEE92A0E2D772EA300E6E989 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -91,6 +93,7 @@
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
6F201E010624CF963CC3A17B /* Pods */,
|
||||
AEE6B7943D197783DD1CB2EE /* Frameworks */,
|
||||
EB9FE5381C3F532BD9A9456D /* GoogleService-Info.plist */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -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 = "";
|
||||
|
||||
32
ios/Runner/GoogleService-Info.plist
Normal file
32
ios/Runner/GoogleService-Info.plist
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>API_KEY</key>
|
||||
<string>AIzaSyBnE8tQjL9_1HuXrTnqNy6qbXpoenO36yQ</string>
|
||||
<key>GCM_SENDER_ID</key>
|
||||
<string>613980912922</string>
|
||||
<key>PLIST_VERSION</key>
|
||||
<string>1</string>
|
||||
<key>BUNDLE_ID</key>
|
||||
<string>com.eatvioapp.app</string>
|
||||
<key>PROJECT_ID</key>
|
||||
<string>eatvio-3467b</string>
|
||||
<key>STORAGE_BUCKET</key>
|
||||
<string>eatvio-3467b.firebasestorage.app</string>
|
||||
<key>IS_ADS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_ANALYTICS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_APPINVITE_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_GCM_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_SIGNIN_ENABLED</key>
|
||||
<true></true>
|
||||
<key>GOOGLE_APP_ID</key>
|
||||
<string>1:613980912922:ios:c557d140a1212e63ecc0a3</string>
|
||||
<key>DATABASE_URL</key>
|
||||
<string>https://eatvio-3467b-default-rtdb.europe-west1.firebasedatabase.app</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -2,8 +2,6 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
@@ -24,6 +22,8 @@
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
@@ -42,6 +42,7 @@
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>remote-notification</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>disabled</string>
|
||||
<string>development</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
11
lib/core/firebase_api.dart
Normal file
11
lib/core/firebase_api.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
|
||||
class FirebaseApi {
|
||||
|
||||
final _firebaseMessaging = FirebaseMessaging.instance;
|
||||
|
||||
Future<String?> getToken() async{
|
||||
await _firebaseMessaging.requestPermission();
|
||||
return await _firebaseMessaging.getToken();
|
||||
}
|
||||
}
|
||||
@@ -94,13 +94,13 @@ Future<void> init() async {
|
||||
|
||||
// Cubit factories
|
||||
sl.registerFactory<RegistrationCubit>(() => RegistrationCubit(registrationRepository: sl()));
|
||||
sl.registerFactory<ChatRoomCubit>(() => ChatRoomCubit(chatRepository: sl(), wsManager: sl()));
|
||||
sl.registerFactory<ChatRoomCubit>(() => ChatRoomCubit(cardsRepository: sl(), chatRepository: sl(), wsManager: sl()));
|
||||
sl.registerFactory<RecipesCubit>(() => RecipesCubit(feedRepository: sl(), recipeRepository: sl(), aboutRecipeRepository: sl()));
|
||||
sl.registerFactory<CalendarCubit>(() => CalendarCubit(calendarRepository: sl()));
|
||||
sl.registerFactory<ProfileCubit>(() => ProfileCubit(profileRepository: sl(), chatRepository: sl()));
|
||||
sl.registerFactory<profilePlans.PlansCubit>(() => profilePlans.PlansCubit(plansRepository: sl()));
|
||||
sl.registerFactory<DietsCubit>(() => DietsCubit(feedRepository: sl(), dietsRepository: sl()));
|
||||
sl.registerFactory<CommentsCubit>(() => CommentsCubit(feedRepository: sl()));
|
||||
sl.registerFactory<CommentsCubit>(() => CommentsCubit(feedRepository: sl()));
|
||||
sl.registerFactory<PlansCubit>(() => PlansCubit(feedRepository: sl(), planRepository: sl()));
|
||||
sl.registerFactory<SettingsCubit>(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl()));
|
||||
sl.registerFactory<RegisterConsultantCubit>(() => RegisterConsultantCubit(consultantRepository: sl()));
|
||||
@@ -171,15 +171,7 @@ Future<void> 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());
|
||||
}
|
||||
|
||||
@@ -25,43 +25,33 @@ class _DataErrorWidgetState extends State<DataErrorWidget> {
|
||||
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;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -13,7 +13,7 @@ abstract class BlogPostService {
|
||||
@Body() required FormData formData,
|
||||
});
|
||||
|
||||
@POST('/api/blogPosts/update/{id}')
|
||||
@POST('/api/blogPosts/update/published/{id}')
|
||||
@MultiPart()
|
||||
Future<void> updateBlogPost({
|
||||
@Path('id') required int id,
|
||||
|
||||
@@ -59,7 +59,7 @@ class _BlogPostService implements BlogPostService {
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/api/blogPosts/update/${id}',
|
||||
'/api/blogPosts/update/published/${id}',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
|
||||
@@ -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<BlogPostCreateCredentialsModel> createBlogPost(
|
||||
BlogPostCreateCredentialsModel model);
|
||||
}
|
||||
*/
|
||||
@@ -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<ChatRoomState> {
|
||||
final ChatRepository chatRepository;
|
||||
final CardsRepository cardsRepository;
|
||||
final WsManager wsManager;
|
||||
|
||||
StreamSubscription<ChannelReadEvent>? typingSubscription;
|
||||
@@ -23,34 +26,22 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
|
||||
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<ChatRoomState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> checkCards() async {
|
||||
try {
|
||||
final cards = await cardsRepository.getCards();
|
||||
setCard(cards: cards);
|
||||
} catch (e) {
|
||||
emit(ChatRoomState.error(errorMessage: 'Ошибка получеия данных'));
|
||||
}
|
||||
}
|
||||
|
||||
void setCard({required List<CardModel> 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<ChatRoomState> {
|
||||
|
||||
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<ChatRoomState> {
|
||||
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<void> _subscribeToChatChannel({
|
||||
required String chatId,
|
||||
}) async {
|
||||
Future<void> _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<ChatRoomState> {
|
||||
messagesSubscription = wsManager.directChatStream?.listen((event) {
|
||||
AudioPlayer().play((AssetSource('audio/recive_message.wav')));
|
||||
final message = ChatMessageModel.fromJson(jsonDecode(event.data)['message']);
|
||||
List<ChatMessageModel> messagesList = [
|
||||
message,
|
||||
...(state as ChatRoomStateLoaded).chatMessages,
|
||||
];
|
||||
List<ChatMessageModel> 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<bool> sendMessage({
|
||||
required String chatId,
|
||||
String? data,
|
||||
List<File>? files,
|
||||
}) async {
|
||||
Future<bool> sendMessage({required String chatId, String? data, List<File>? 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<ChatRoomState> {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ abstract class ChatRoomState with _$ChatRoomState {
|
||||
const factory ChatRoomState.loaded({
|
||||
required ChatRoomModel chatRoom,
|
||||
required List<ChatMessageModel> chatMessages,
|
||||
required bool hasCard,
|
||||
required bool isTyping,
|
||||
required bool isLoading,
|
||||
}) = ChatRoomStateLoaded;
|
||||
|
||||
@@ -24,6 +24,7 @@ mixin _$ChatRoomState {
|
||||
required TResult Function(
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)
|
||||
@@ -37,6 +38,7 @@ mixin _$ChatRoomState {
|
||||
TResult? Function(
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)?
|
||||
@@ -50,6 +52,7 @@ mixin _$ChatRoomState {
|
||||
TResult Function(
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)?
|
||||
@@ -151,6 +154,7 @@ class _$ChatRoomStateImpl implements _ChatRoomState {
|
||||
required TResult Function(
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)
|
||||
@@ -168,6 +172,7 @@ class _$ChatRoomStateImpl implements _ChatRoomState {
|
||||
TResult? Function(
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)?
|
||||
@@ -185,6 +190,7 @@ class _$ChatRoomStateImpl implements _ChatRoomState {
|
||||
TResult Function(
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)?
|
||||
@@ -289,6 +295,7 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading {
|
||||
required TResult Function(
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)
|
||||
@@ -306,6 +313,7 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading {
|
||||
TResult? Function(
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)?
|
||||
@@ -323,6 +331,7 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading {
|
||||
TResult Function(
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)?
|
||||
@@ -388,6 +397,7 @@ abstract class _$$ChatRoomStateLoadedImplCopyWith<$Res> {
|
||||
$Res call({
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> 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<ChatMessageModel>,
|
||||
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<ChatMessageModel> 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<ChatMessageModel> 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<ChatMessageModel> 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<ChatMessageModel> 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<ChatMessageModel> chatMessages,
|
||||
required final bool hasCard,
|
||||
required final bool isTyping,
|
||||
required final bool isLoading,
|
||||
}) = _$ChatRoomStateLoadedImpl;
|
||||
|
||||
ChatRoomModel get chatRoom;
|
||||
List<ChatMessageModel> 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<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)
|
||||
@@ -728,6 +755,7 @@ class _$ChatRoomStateErrorImpl implements ChatRoomStateError {
|
||||
TResult? Function(
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)?
|
||||
@@ -745,6 +773,7 @@ class _$ChatRoomStateErrorImpl implements ChatRoomStateError {
|
||||
TResult Function(
|
||||
ChatRoomModel chatRoom,
|
||||
List<ChatMessageModel> chatMessages,
|
||||
bool hasCard,
|
||||
bool isTyping,
|
||||
bool isLoading,
|
||||
)?
|
||||
|
||||
@@ -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<ChatScreen> createState() => _ChatScreenState();
|
||||
@@ -73,14 +71,9 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
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<ChatScreen> {
|
||||
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<ChatScreen> {
|
||||
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<ChatScreen> {
|
||||
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<ChatRoomCubit>().markMessagesAsRead(state.chatRoom.id, unreadMessagesIdsCopy);
|
||||
if (!result) return;
|
||||
context
|
||||
.read<ChatsCubit>()
|
||||
.reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIdsCopy.length);
|
||||
unreadMessagesIdsCopy.clear();
|
||||
},
|
||||
);
|
||||
EasyDebounce.debounce('mark_as_read', Duration(milliseconds: 500), () async {
|
||||
final result = await context.read<ChatRoomCubit>().markMessagesAsRead(state.chatRoom.id, unreadMessagesIdsCopy);
|
||||
if (!result) return;
|
||||
context.read<ChatsCubit>().reduceUnreadMessagesCount(
|
||||
chatId: state.chatRoom.id,
|
||||
count: unreadMessagesIdsCopy.length,
|
||||
);
|
||||
unreadMessagesIdsCopy.clear();
|
||||
});
|
||||
}
|
||||
},
|
||||
child: ChatBubbleWidget(
|
||||
@@ -233,16 +228,12 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
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<ChatRoomCubit>().markMessagesAsRead(state.chatRoom.id, unreadMessagesIds);
|
||||
if (!result) return;
|
||||
context.read<ChatsCubit>().reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIds.length);
|
||||
unreadMessagesIds.clear();
|
||||
},
|
||||
);
|
||||
EasyDebounce.debounce('mark_as_read', Duration(milliseconds: 500), () async {
|
||||
final result = await context.read<ChatRoomCubit>().markMessagesAsRead(state.chatRoom.id, unreadMessagesIds);
|
||||
if (!result) return;
|
||||
context.read<ChatsCubit>().reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIds.length);
|
||||
unreadMessagesIds.clear();
|
||||
});
|
||||
}
|
||||
},
|
||||
child: ChatBubbleWidget(
|
||||
@@ -282,6 +273,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
},
|
||||
),
|
||||
),
|
||||
if (bannerType != null)
|
||||
Padding(padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), child: NotificationBanner(bannerType: bannerType)),
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -324,24 +317,14 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
|
||||
if (result != null) {
|
||||
List<File> 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<ChatScreen> {
|
||||
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<ChatScreen> {
|
||||
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<ChatScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
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<ChatScreen> {
|
||||
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)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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});
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -23,6 +23,7 @@ RecipeCreateModel _$RecipeCreateModelFromJson(Map<String, dynamic> 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;
|
||||
|
||||
@@ -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<String, dynamic> _$$RecipeCreateModelImplToJson(
|
||||
) => <String, dynamic>{
|
||||
'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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<DevToolsScreenContent> {
|
||||
@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<DevToolsScreenContent> {
|
||||
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<DevToolsScreenContent> {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
CustomOutlinedButton(
|
||||
text: 'add token to server',
|
||||
buttonStyle: ButtonStyle(),
|
||||
onPressed: () async {
|
||||
try {
|
||||
final dio = sl<Dio>();
|
||||
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<Dio>();
|
||||
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<Dio>();
|
||||
Future.delayed(Duration(seconds: 3), () async {
|
||||
await dio.post('/api/profile/notification/token/test');
|
||||
});
|
||||
} catch (e) {
|
||||
showInfoToast('Не удалось добавть токен');
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 300),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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<ExpandableText> {
|
||||
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<ExpandableText> {
|
||||
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<ExpandableText> {
|
||||
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)),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -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<int, Map<int, Map<int, DailySchedule>>> dailySchedule,
|
||||
@JsonKey(name: "author") required Author author,
|
||||
@JsonKey(name: "total_likes") required int totalLikes,
|
||||
|
||||
@@ -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<int, Map<int, Map<int, DailySchedule>>> 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<int, Map<int, Map<int, DailySchedule>>> 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<int, Map<int, Map<int, DailySchedule>>> 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<int, Map<int, Map<int, DailySchedule>>> 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<int, Map<int, Map<int, DailySchedule>>> _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<int, Map<int, Map<int, DailySchedule>>> 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")
|
||||
|
||||
@@ -32,7 +32,7 @@ _$DietImpl _$$DietImplFromJson(Map<String, dynamic> json) => _$DietImpl(
|
||||
duration: (json['duration'] as num).toInt(),
|
||||
state: $enumDecode(_$DietStateEnumMap, json['state']),
|
||||
type: DietType.fromJson(json['type'] as Map<String, dynamic>),
|
||||
details: json['details'] as String,
|
||||
details: json['description_md'] as String,
|
||||
dailySchedule: (json['daily_schedule'] as Map<String, dynamic>).map(
|
||||
(k, e) => MapEntry(
|
||||
int.parse(k),
|
||||
@@ -70,7 +70,7 @@ Map<String, dynamic> _$$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(),
|
||||
|
||||
@@ -58,7 +58,7 @@ class PacketOptions with _$PacketOptions {
|
||||
@JsonKey(name: "items") required List<String> 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<String, dynamic> json) => _$PacketOptionsFromJson(json);
|
||||
|
||||
@@ -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<String> 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<String> 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<String> 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<String, dynamic> 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<String> 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<String, dynamic> 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
|
||||
|
||||
@@ -93,7 +93,7 @@ _$PacketOptionsImpl _$$PacketOptionsImplFromJson(Map<String, dynamic> json) =>
|
||||
items: (json['items'] as List<dynamic>).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<String, dynamic> _$$PacketOptionsImplToJson(_$PacketOptionsImpl instance) =>
|
||||
@@ -101,7 +101,7 @@ Map<String, dynamic> _$$PacketOptionsImplToJson(_$PacketOptionsImpl instance) =>
|
||||
'items': instance.items,
|
||||
'price': instance.price,
|
||||
'short': instance.short,
|
||||
'description': instance.description,
|
||||
'description_md': instance.description,
|
||||
};
|
||||
|
||||
_$PlanTypeImpl _$$PlanTypeImplFromJson(Map<String, dynamic> json) =>
|
||||
|
||||
@@ -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<String, Object?> 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<String, Object?> json) => _$StepFromJson(json);
|
||||
}
|
||||
|
||||
@@ -929,6 +929,7 @@ Step _$StepFromJson(Map<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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
|
||||
|
||||
@@ -78,11 +78,11 @@ Map<String, dynamic> _$$IngredientImplToJson(_$IngredientImpl instance) =>
|
||||
|
||||
_$StepImpl _$$StepImplFromJson(Map<String, dynamic> json) => _$StepImpl(
|
||||
image: json['image'] as String,
|
||||
description: json['description'] as String,
|
||||
description: json['description_md'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$StepImplToJson(_$StepImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'image': instance.image,
|
||||
'description': instance.description,
|
||||
'description_md': instance.description,
|
||||
};
|
||||
|
||||
@@ -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<UserCardsState> {
|
||||
Future<void> 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<UserCardsState> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<CardModel> cards,
|
||||
@Default(false) bool isLoading,
|
||||
@Default([]) List<CardModel> cards,
|
||||
@Default(null) String? error,
|
||||
@Default(BaseState.initial) BaseState state,
|
||||
}) = _UserCardsState;
|
||||
|
||||
}
|
||||
@@ -18,7 +18,8 @@ final _privateConstructorUsedError = UnsupportedError(
|
||||
/// @nodoc
|
||||
mixin _$UserCardsState {
|
||||
List<CardModel> 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<CardModel> cards, bool isLoading});
|
||||
$Res call({List<CardModel> 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<CardModel>,
|
||||
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<CardModel> cards, bool isLoading});
|
||||
$Res call({List<CardModel> 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<CardModel>,
|
||||
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<CardModel> cards = const [],
|
||||
this.isLoading = false,
|
||||
this.error = null,
|
||||
this.state = BaseState.initial,
|
||||
}) : _cards = cards;
|
||||
|
||||
final List<CardModel> _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<CardModel> cards, final bool isLoading}) =
|
||||
_$UserCardsStateImpl;
|
||||
factory _UserCardsState({
|
||||
final List<CardModel> cards,
|
||||
final String? error,
|
||||
final BaseState state,
|
||||
}) = _$UserCardsStateImpl;
|
||||
|
||||
@override
|
||||
List<CardModel> 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.
|
||||
|
||||
@@ -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<UserCardsCubit, UserCardsState>(
|
||||
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<UserCardsCubit>().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()));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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<UserCardsCubit>().addCard();
|
||||
return Stack(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap:
|
||||
enabledAddCard
|
||||
? () async {
|
||||
final addCardUrl = await context.read<UserCardsCubit>().addCard();
|
||||
|
||||
if (addCardUrl != null) {
|
||||
final uri = Uri.parse(addCardUrl.paymentUrl);
|
||||
if (await canLaunchUrl(uri)) {
|
||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
}
|
||||
}
|
||||
}
|
||||
: () {
|
||||
context.read<UserCardsCubit>().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<UserCardsCubit>().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<UserCardsCubit>().deleteCard(id: cardId),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,9 +67,7 @@ class _AboutRecipeScreenState extends State<AboutRecipeScreen> {
|
||||
|
||||
void _scrollToBottom() {
|
||||
_jumped = true;
|
||||
scrollController.jumpTo(
|
||||
scrollController.position.maxScrollExtent,
|
||||
);
|
||||
scrollController.jumpTo(scrollController.position.maxScrollExtent);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -78,12 +76,7 @@ class _AboutRecipeScreenState extends State<AboutRecipeScreen> {
|
||||
return BlocProvider(
|
||||
create: (context) => recipeCubit..getRecipe(widget.recipe.slug),
|
||||
child: BlocProvider<CommentsCubit>(
|
||||
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<CommentsCubit, CommentsState>(
|
||||
listener: (BuildContext context, CommentsState commentsState) {
|
||||
if (commentsState is CommentsStateLoaded) {
|
||||
@@ -106,14 +99,7 @@ class _AboutRecipeScreenState extends State<AboutRecipeScreen> {
|
||||
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<AboutRecipeScreen> {
|
||||
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<AboutRecipeScreen> {
|
||||
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<AboutRecipeScreen> {
|
||||
}
|
||||
},
|
||||
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<AboutRecipeScreen> {
|
||||
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<AboutRecipeScreen> {
|
||||
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<AboutRecipeScreen> {
|
||||
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<AboutRecipeScreen> {
|
||||
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<AboutRecipeScreen> {
|
||||
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<AboutRecipeScreen> {
|
||||
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<AboutRecipeCubit>().getRecipe(widget.recipe.slug, index: widget.index),
|
||||
),
|
||||
body: DataErrorWidget(onReload: () => context.read<AboutRecipeCubit>().getRecipe(widget.recipe.slug, index: widget.index)),
|
||||
);
|
||||
}
|
||||
return Scaffold(
|
||||
@@ -523,22 +443,14 @@ class _AboutRecipeScreenState extends State<AboutRecipeScreen> {
|
||||
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),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
70
lib/firebase_options.dart
Normal file
70
lib/firebase_options.dart
Normal file
@@ -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',
|
||||
);
|
||||
}
|
||||
@@ -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<void> 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')],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user