forked from eatvio/eatvio_app
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0ac156307 | ||
|
|
4a9d45a18d | ||
|
|
65fabefdb9 | ||
|
|
f573bb28f8 | ||
|
|
20aca4b9a4 | ||
|
|
5354c3f517 | ||
| 17dbc1d5bf | |||
|
|
09a00a41ad | ||
|
|
24675714e0 | ||
|
|
21492a1ad9 | ||
|
|
239ff675db | ||
|
|
fa6c2f9000 | ||
|
|
ae0c3a53be | ||
| 21555bfb10 | |||
|
|
f90f1d3284 | ||
| f9fed539c2 | |||
|
|
654edc5457 | ||
| 928a55ae93 | |||
|
|
b2433b87b6 | ||
|
|
183fa012d2 | ||
|
|
9ac576221a | ||
|
|
5013ffe06b | ||
| 2993c05dd1 | |||
|
|
79de6ee6fa | ||
|
|
b0d2d86a18 | ||
|
|
03448ebd2d |
37
integration_test/auth_screen/auth_login_test.dart
Normal file
37
integration_test/auth_screen/auth_login_test.dart
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import 'package:eatvio_app/app_keys.dart';
|
||||||
|
import 'package:eatvio_app/core/app_initializer.dart';
|
||||||
|
import 'package:eatvio_app/main.dart' as app;
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import '../common_cases/skip_welcome_screen.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
setUpAll(() async {
|
||||||
|
await AppInitializer.initialize(buildType: AppBuildType.tests);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Signs in successfully with valid credentials', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(const app.MyApp());
|
||||||
|
await tester.pumpAndSettle(const Duration(seconds: 3));
|
||||||
|
await skipWelcomeScreen(tester);
|
||||||
|
final emailFieldFinder = find.byKey(AppKeys.emailTextFieldAuthScreen);
|
||||||
|
final passwordFieldFinder = find.byKey(AppKeys.passwordTextFieldAuthScreen);
|
||||||
|
final signInButtonFinder = find.byKey(AppKeys.signInButtonAuthScreen);
|
||||||
|
|
||||||
|
expect(emailFieldFinder, findsOneWidget, reason: 'Email text field should be found.');
|
||||||
|
expect(passwordFieldFinder, findsOneWidget, reason: 'Password text field should be found.');
|
||||||
|
expect(signInButtonFinder, findsOneWidget, reason: 'Sign In button should be found.');
|
||||||
|
|
||||||
|
await tester.enterText(emailFieldFinder, 'reshetnick.mike+user4@gmail.com');
|
||||||
|
await tester.enterText(passwordFieldFinder, '1234567890');
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(signInButtonFinder);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle(const Duration(seconds: 3));
|
||||||
|
|
||||||
|
expect(signInButtonFinder, findsNothing, reason: 'Sign-in button should not be visible after successful login and navigation.');
|
||||||
|
});
|
||||||
|
}
|
||||||
31
integration_test/auth_screen/auth_logo_button_test.dart
Normal file
31
integration_test/auth_screen/auth_logo_button_test.dart
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import 'package:eatvio_app/app_keys.dart';
|
||||||
|
import 'package:eatvio_app/core/app_initializer.dart';
|
||||||
|
import 'package:eatvio_app/features/dev_tools/presentation/dev_tools_screen.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'package:eatvio_app/main.dart' as app;
|
||||||
|
import '../common_cases/skip_welcome_screen.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
setUpAll(() async {
|
||||||
|
await AppInitializer.initialize(buildType: AppBuildType.tests);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('tapping logo 7 times opens dev tools', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(const app.MyApp());
|
||||||
|
await tester.pumpAndSettle(const Duration(seconds: 3));
|
||||||
|
await skipWelcomeScreen(tester);
|
||||||
|
final logoButtonFinder = find.byKey(AppKeys.hiddenLogoButtonAuthScreen);
|
||||||
|
expect(logoButtonFinder, findsOneWidget, reason: 'The logo GestureDetector should be found in auth screen');
|
||||||
|
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
await tester.tap(logoButtonFinder);
|
||||||
|
await tester.pump(const Duration(milliseconds: 50));
|
||||||
|
}
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.byType(DevToolsScreen), findsOneWidget, reason: 'DevToolsScreen should be visible after tapping the logo 7 times.');
|
||||||
|
});
|
||||||
|
}
|
||||||
8
integration_test/common_cases/skip_welcome_screen.dart
Normal file
8
integration_test/common_cases/skip_welcome_screen.dart
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import 'package:eatvio_app/app_keys.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
Future<void> skipWelcomeScreen(WidgetTester tester) async {
|
||||||
|
final welcomeScreenButtonFinder = find.byKey(AppKeys.welcomeScreenButton);
|
||||||
|
await tester.tap(welcomeScreenButtonFinder);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
}
|
||||||
13
lib/app_keys.dart
Normal file
13
lib/app_keys.dart
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class AppKeys {
|
||||||
|
|
||||||
|
// Auth Screen
|
||||||
|
static const hiddenLogoButtonAuthScreen = ValueKey('hiddenLogoButtonAuthScreen');
|
||||||
|
static const emailTextFieldAuthScreen = ValueKey('emailTextFieldAuthScreen');
|
||||||
|
static const passwordTextFieldAuthScreen = ValueKey('passwordTextFieldAuthScreen');
|
||||||
|
static const signInButtonAuthScreen = ValueKey('signInButtonAuthScreen');
|
||||||
|
|
||||||
|
// Welcome Screen
|
||||||
|
static const welcomeScreenButton = ValueKey('welcomeScreenButton');
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'package:eatvio_app/core/app_initializer.dart';
|
||||||
|
import 'package:eatvio_app/core/env_config.dart';
|
||||||
import 'package:eatvio_app/core/internet_connection_cubit/internet_connection_cubit.dart';
|
import 'package:eatvio_app/core/internet_connection_cubit/internet_connection_cubit.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.dart';
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/views/cubit/views_cubit.dart';
|
import 'package:eatvio_app/core/views/cubit/views_cubit.dart';
|
||||||
@@ -13,8 +15,24 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
|||||||
|
|
||||||
/// Конфигурация приложения
|
/// Конфигурация приложения
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
AppConfig({required this.buildType}){
|
||||||
|
_baseUrl = switch (buildType) {
|
||||||
|
AppBuildType.prod => EnvConfig.baseUrl,
|
||||||
|
AppBuildType.tests => EnvConfig.devBaseUrl,
|
||||||
|
AppBuildType.dev => EnvConfig.devBaseUrl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
final AppBuildType buildType;
|
||||||
|
late final String _baseUrl;
|
||||||
|
String get baseUrl => _baseUrl;
|
||||||
|
|
||||||
|
void setBaseUrl(String baseUrls) {
|
||||||
|
_baseUrl = baseUrls;
|
||||||
|
}
|
||||||
|
|
||||||
/// Список глобальных BlocProvider'ов
|
/// Список глобальных BlocProvider'ов
|
||||||
static List<BlocProvider> get globalBlocProviders => [
|
List<BlocProvider> get globalBlocProviders => [
|
||||||
BlocProvider<NewMessagesCubit>(create: (context) => sl<NewMessagesCubit>()),
|
BlocProvider<NewMessagesCubit>(create: (context) => sl<NewMessagesCubit>()),
|
||||||
BlocProvider<NotificationsCubit>(create: (context) => sl<NotificationsCubit>()..getNotifications()),
|
BlocProvider<NotificationsCubit>(create: (context) => sl<NotificationsCubit>()..getNotifications()),
|
||||||
BlocProvider<FeedCubit>(create: (context) => sl<FeedCubit>()..loadFeedBlogPostList()),
|
BlocProvider<FeedCubit>(create: (context) => sl<FeedCubit>()..loadFeedBlogPostList()),
|
||||||
@@ -25,7 +43,7 @@ class AppConfig {
|
|||||||
];
|
];
|
||||||
|
|
||||||
/// Делегаты локализации
|
/// Делегаты локализации
|
||||||
static const List<LocalizationsDelegate> localizationDelegates = [
|
List<LocalizationsDelegate> get localizationDelegates => [
|
||||||
S.delegate,
|
S.delegate,
|
||||||
GlobalMaterialLocalizations.delegate,
|
GlobalMaterialLocalizations.delegate,
|
||||||
GlobalWidgetsLocalizations.delegate,
|
GlobalWidgetsLocalizations.delegate,
|
||||||
@@ -33,5 +51,5 @@ class AppConfig {
|
|||||||
];
|
];
|
||||||
|
|
||||||
/// Поддерживаемые локали
|
/// Поддерживаемые локали
|
||||||
static const List<Locale> supportedLocales = [Locale.fromSubtags(languageCode: 'ru')];
|
List<Locale> get supportedLocales => [const Locale.fromSubtags(languageCode: 'ru')];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import 'dart:io' as io;
|
import 'dart:io' as io;
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/env_config.dart';
|
import 'package:eatvio_app/core/env_config.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.dart' as di;
|
import 'package:eatvio_app/core/locator_service.dart' as di;
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/firebase_options.dart';
|
import 'package:eatvio_app/firebase_options.dart';
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
@@ -13,11 +15,11 @@ import 'package:sentry_flutter/sentry_flutter.dart';
|
|||||||
/// Класс для инициализации приложения
|
/// Класс для инициализации приложения
|
||||||
class AppInitializer {
|
class AppInitializer {
|
||||||
/// Инициализация всех сервисов приложения
|
/// Инициализация всех сервисов приложения
|
||||||
static Future<void> initialize() async {
|
static Future<void> initialize({required AppBuildType buildType}) async {
|
||||||
await _initializeSentry();
|
|
||||||
await _initializeEnvironment();
|
await _initializeEnvironment();
|
||||||
|
await _initializeDependencyInjection(buildType: buildType);
|
||||||
|
await _initializeSentry();
|
||||||
await _initializeFirebase();
|
await _initializeFirebase();
|
||||||
await _initializeDependencyInjection();
|
|
||||||
await _initializeDebugMode();
|
await _initializeDebugMode();
|
||||||
await _initializeAnalytics();
|
await _initializeAnalytics();
|
||||||
}
|
}
|
||||||
@@ -36,12 +38,14 @@ class AppInitializer {
|
|||||||
/// Инициализация Firebase
|
/// Инициализация Firebase
|
||||||
static Future<void> _initializeFirebase() async {
|
static Future<void> _initializeFirebase() async {
|
||||||
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
||||||
await FirebaseMessaging.instance.requestPermission();
|
if (sl<AppConfig>().buildType == AppBuildType.prod) {
|
||||||
|
await FirebaseMessaging.instance.requestPermission();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Инициализация системы внедрения зависимостей
|
/// Инициализация системы внедрения зависимостей
|
||||||
static Future<void> _initializeDependencyInjection() async {
|
static Future<void> _initializeDependencyInjection({required AppBuildType buildType}) async {
|
||||||
await di.init();
|
await di.init(buildType: buildType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Настройка режима отладки
|
/// Настройка режима отладки
|
||||||
@@ -66,3 +70,5 @@ class AppInitializer {
|
|||||||
}, appRunner: appRunner);
|
}, appRunner: appRunner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum AppBuildType { prod, tests, dev }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:eatvio_app/core/routing/main_navigation_routes.dart';
|
|||||||
import 'package:eatvio_app/core/routing/other_routes.dart';
|
import 'package:eatvio_app/core/routing/other_routes.dart';
|
||||||
import 'package:eatvio_app/core/routing/route_constants.dart';
|
import 'package:eatvio_app/core/routing/route_constants.dart';
|
||||||
import 'package:eatvio_app/core/routing/settings_routes.dart';
|
import 'package:eatvio_app/core/routing/settings_routes.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/entities/auth_result_entity.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
@@ -50,4 +51,8 @@ class AppRouter {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void navigateToRegisterViaSocial({required AuthResultEntity authResult, required String provider}) {
|
||||||
|
appRouter.pushNamed('registerViaSocialScreen', extra: {'authResult': authResult, 'provider': provider});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
import 'package:eatvio_app/core/env_config.dart';
|
|
||||||
|
|
||||||
String baseUrl = EnvConfig.devBaseUrl;
|
|
||||||
bool hidePlans = const bool.fromEnvironment('HIDE_PLANS', defaultValue: false);
|
bool hidePlans = const bool.fromEnvironment('HIDE_PLANS', defaultValue: false);
|
||||||
const buildDate = String.fromEnvironment('BUILD_DATE', defaultValue: '');
|
const buildDate = String.fromEnvironment('BUILD_DATE', defaultValue: '');
|
||||||
|
|
||||||
|
|||||||
12
lib/core/di/app_config_registration.dart
Normal file
12
lib/core/di/app_config_registration.dart
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/app_initializer.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
|
||||||
|
class AppConfigRegistration {
|
||||||
|
static final sl = GetIt.instance;
|
||||||
|
|
||||||
|
/// Регистрация AppConfig
|
||||||
|
static void registerAppConfig({required AppBuildType buildType}) {
|
||||||
|
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: buildType));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:eatvio_app/core/internet_connection_cubit/internet_connection_cubit.dart';
|
import 'package:eatvio_app/core/internet_connection_cubit/internet_connection_cubit.dart';
|
||||||
import 'package:eatvio_app/core/views/cubit/views_cubit.dart';
|
import 'package:eatvio_app/core/views/cubit/views_cubit.dart';
|
||||||
import 'package:eatvio_app/features/auth/presentation/bloc/auth_cubit/auth_cubit.dart';
|
import 'package:eatvio_app/features/auth/presentation/bloc/auth_cubit/auth_cubit.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/presentation/bloc/oauth_cubit/oauth_cubit.dart';
|
||||||
import 'package:eatvio_app/features/auth/presentation/bloc/reset_password_cubit/reset_password_cubit.dart';
|
import 'package:eatvio_app/features/auth/presentation/bloc/reset_password_cubit/reset_password_cubit.dart';
|
||||||
import 'package:eatvio_app/features/blog_post/presentation/cubit/blog_post_cubit.dart';
|
import 'package:eatvio_app/features/blog_post/presentation/cubit/blog_post_cubit.dart';
|
||||||
import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart';
|
import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart';
|
||||||
@@ -75,7 +76,7 @@ class CubitRegistrations {
|
|||||||
sl.registerFactory<RegistrationCubit>(() => RegistrationCubit(registrationRepository: sl()));
|
sl.registerFactory<RegistrationCubit>(() => RegistrationCubit(registrationRepository: sl()));
|
||||||
sl.registerFactory<ResetPasswordCubit>(() => ResetPasswordCubit(resetPasswordRepository: sl()));
|
sl.registerFactory<ResetPasswordCubit>(() => ResetPasswordCubit(resetPasswordRepository: sl()));
|
||||||
sl.registerFactory<VerifyEmailCubit>(() => VerifyEmailCubit(profileRepository: sl()));
|
sl.registerFactory<VerifyEmailCubit>(() => VerifyEmailCubit(profileRepository: sl()));
|
||||||
|
sl.registerFactory<OAuthCubit>(() => OAuthCubit(authRepository: sl()));
|
||||||
// Feed related cubits
|
// Feed related cubits
|
||||||
sl.registerFactory<FeedCubit>(() => FeedCubit(feedRepository: sl()));
|
sl.registerFactory<FeedCubit>(() => FeedCubit(feedRepository: sl()));
|
||||||
sl.registerFactory<RecipesCubit>(() => RecipesCubit(feedRepository: sl(), recipeRepository: sl(), aboutRecipeRepository: sl()));
|
sl.registerFactory<RecipesCubit>(() => RecipesCubit(feedRepository: sl(), recipeRepository: sl(), aboutRecipeRepository: sl()));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/dio/phone_verify_error_interceptor.dart';
|
import 'package:eatvio_app/core/interceptors/phone_verify_error_interceptor.dart';
|
||||||
import 'package:eatvio_app/core/interceptors/token_interceptor.dart';
|
import 'package:eatvio_app/core/interceptors/token_interceptor.dart';
|
||||||
import 'package:get_it/get_it.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ class ExternalRegistrations {
|
|||||||
sl.registerLazySingleton(
|
sl.registerLazySingleton(
|
||||||
() => Dio(
|
() => Dio(
|
||||||
BaseOptions(
|
BaseOptions(
|
||||||
baseUrl: baseUrl,
|
baseUrl: sl<AppConfig>().baseUrl,
|
||||||
headers: {
|
headers: {
|
||||||
'accept': 'application/json',
|
'accept': 'application/json',
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ class EnvConfig {
|
|||||||
static String get yandexCheckUrl => dotenv.env['YANDEX_CHECK_URL'] ?? '';
|
static String get yandexCheckUrl => dotenv.env['YANDEX_CHECK_URL'] ?? '';
|
||||||
|
|
||||||
// VK ID Configuration
|
// VK ID Configuration
|
||||||
static String get vkClientId => dotenv.env['VK_CLIENT_ID'] ?? '';
|
static String get vkClientIdIos => dotenv.env['VK_CLIENT_ID_IOS'] ?? '';
|
||||||
|
static String get vkClientIdAndroid => dotenv.env['VK_CLIENT_ID_ANDROID'] ?? '';
|
||||||
|
|
||||||
// Yandex ID Configuration
|
// Yandex ID Configuration
|
||||||
static String get yandexClientId => dotenv.env['YANDEX_CLIENT_ID'] ?? '';
|
static String get yandexClientId => dotenv.env['YANDEX_CLIENT_ID'] ?? '';
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/app_initializer.dart';
|
||||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
@@ -19,7 +21,9 @@ class FirebaseApi {
|
|||||||
if (await _isHuaweiDevice()) {
|
if (await _isHuaweiDevice()) {
|
||||||
token = await _getHuaweiPushTokenNative();
|
token = await _getHuaweiPushTokenNative();
|
||||||
} else {
|
} else {
|
||||||
await _firebaseMessaging.requestPermission();
|
if ((sl<AppConfig>().buildType == AppBuildType.prod)) {
|
||||||
|
await _firebaseMessaging.requestPermission();
|
||||||
|
}
|
||||||
token = await _firebaseMessaging.getToken();
|
token = await _firebaseMessaging.getToken();
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'package:eatvio_app/core/app_initializer.dart';
|
||||||
|
import 'package:eatvio_app/core/di/app_config_registration.dart';
|
||||||
import 'package:eatvio_app/core/di/cubit_registrations.dart';
|
import 'package:eatvio_app/core/di/cubit_registrations.dart';
|
||||||
import 'package:eatvio_app/core/di/external_registrations.dart';
|
import 'package:eatvio_app/core/di/external_registrations.dart';
|
||||||
import 'package:eatvio_app/core/di/repository_registrations.dart';
|
import 'package:eatvio_app/core/di/repository_registrations.dart';
|
||||||
@@ -9,19 +11,22 @@ import 'package:get_it/get_it.dart';
|
|||||||
final sl = GetIt.instance;
|
final sl = GetIt.instance;
|
||||||
|
|
||||||
/// Инициализация системы внедрения зависимостей
|
/// Инициализация системы внедрения зависимостей
|
||||||
Future<void> init() async {
|
Future<void> init({required AppBuildType buildType}) async {
|
||||||
|
// Регистрация AppConfig
|
||||||
|
AppConfigRegistration.registerAppConfig(buildType: buildType);
|
||||||
|
|
||||||
// Регистрация внешних зависимостей (Dio, etc.)
|
// Регистрация внешних зависимостей (Dio, etc.)
|
||||||
ExternalRegistrations.registerAll();
|
ExternalRegistrations.registerAll();
|
||||||
|
|
||||||
// Регистрация сервисов
|
// Регистрация сервисов
|
||||||
ServiceRegistrations.registerAll();
|
ServiceRegistrations.registerAll();
|
||||||
|
|
||||||
// Регистрация репозиториев
|
// Регистрация репозиториев
|
||||||
RepositoryRegistrations.registerAll();
|
RepositoryRegistrations.registerAll();
|
||||||
|
|
||||||
// Регистрация Cubit'ов
|
// Регистрация Cubit'ов
|
||||||
CubitRegistrations.registerAll();
|
CubitRegistrations.registerAll();
|
||||||
|
|
||||||
// Регистрация WebSocket менеджера
|
// Регистрация WebSocket менеджера
|
||||||
sl.registerLazySingleton<WsManager>(() => WsManager(wsService: sl()));
|
sl.registerLazySingleton<WsManager>(() => WsManager(wsService: sl()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import 'package:eatvio_app/core/routing/route_constants.dart';
|
import 'package:eatvio_app/core/routing/route_constants.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/entities/auth_result_entity.dart';
|
||||||
import 'package:eatvio_app/features/auth/presentation/pages/auth_screen.dart';
|
import 'package:eatvio_app/features/auth/presentation/pages/auth_screen.dart';
|
||||||
import 'package:eatvio_app/features/auth/presentation/pages/forget_password_screen.dart';
|
import 'package:eatvio_app/features/auth/presentation/pages/forget_password_screen.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/presentation/pages/register_via_social_screen.dart';
|
||||||
import 'package:eatvio_app/features/auth/presentation/pages/scan_qr_code_screen.dart';
|
import 'package:eatvio_app/features/auth/presentation/pages/scan_qr_code_screen.dart';
|
||||||
import 'package:eatvio_app/features/registration/presentation/pages/registration_screen.dart';
|
import 'package:eatvio_app/features/registration/presentation/pages/registration_screen.dart';
|
||||||
import 'package:eatvio_app/features/registration/presentation/pages/verify_screen.dart';
|
import 'package:eatvio_app/features/registration/presentation/pages/verify_screen.dart';
|
||||||
@@ -32,6 +34,14 @@ class AuthRoutes {
|
|||||||
builder: (context, state) => VerifyScreen(passKey: state.extra as String),
|
builder: (context, state) => VerifyScreen(passKey: state.extra as String),
|
||||||
),
|
),
|
||||||
GoRoute(path: RouteConstants.verifyEmailScreen, name: 'verifyEmailScreen', builder: (context, state) => const VerifyEmailScreen()),
|
GoRoute(path: RouteConstants.verifyEmailScreen, name: 'verifyEmailScreen', builder: (context, state) => const VerifyEmailScreen()),
|
||||||
|
GoRoute(
|
||||||
|
path: RouteConstants.registerViaSocialScreen,
|
||||||
|
name: 'registerViaSocialScreen',
|
||||||
|
builder: (context, state) {
|
||||||
|
final extra = state.extra as Map<String, dynamic>?;
|
||||||
|
return RegisterViaSocialScreen(authResult: extra?['authResult'] as AuthResultEntity?, provider: extra?['provider'] as String?);
|
||||||
|
},
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,10 +44,15 @@ class ContentRoutes {
|
|||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final slug = state.uri.queryParameters['slug'];
|
final slug = state.uri.queryParameters['slug'];
|
||||||
if (slug != null) {
|
if (slug != null) {
|
||||||
return AboutDietScreen(slug: slug, index: null, navigateToComments: false);
|
return AboutDietScreen(id: null, slug: slug, index: null, navigateToComments: false);
|
||||||
}
|
}
|
||||||
final data = state.extra as Map<String, dynamic>;
|
final data = state.extra as Map<String, dynamic>;
|
||||||
return AboutDietScreen(slug: data['slug'] as String, index: data['index'] as int?, navigateToComments: data['navigateToComments'] as bool);
|
return AboutDietScreen(
|
||||||
|
id: data['id'] as int?,
|
||||||
|
slug: data['slug'] as String?,
|
||||||
|
index: data['index'] as int?,
|
||||||
|
navigateToComments: data['navigateToComments'] as bool,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/firebase_api.dart';
|
import 'package:eatvio_app/core/firebase_api.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.dart';
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/routing/route_constants.dart';
|
import 'package:eatvio_app/core/routing/route_constants.dart';
|
||||||
@@ -76,7 +76,7 @@ class OtherRoutes {
|
|||||||
builder: (context, state) => const UpdateScreen(),
|
builder: (context, state) => const UpdateScreen(),
|
||||||
redirect: (context, state) async {
|
redirect: (context, state) async {
|
||||||
try {
|
try {
|
||||||
final versions = (await sl<Dio>().get('$baseUrl/api/app_versions')).data;
|
final versions = (await sl<Dio>().get('${sl<AppConfig>().baseUrl}/api/app_versions')).data;
|
||||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||||
String version = packageInfo.version;
|
String version = packageInfo.version;
|
||||||
Version currentVersion = Version.parse(version);
|
Version currentVersion = Version.parse(version);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ class RouteConstants {
|
|||||||
static const String scanQRCodeScreen = 'scan-qr-code-screen';
|
static const String scanQRCodeScreen = 'scan-qr-code-screen';
|
||||||
static const String verifyScreen = '/verify-screen';
|
static const String verifyScreen = '/verify-screen';
|
||||||
static const String verifyEmailScreen = '/verify-email-screen';
|
static const String verifyEmailScreen = '/verify-email-screen';
|
||||||
|
static const String registerViaSocialScreen = '/register-via-social-screen';
|
||||||
|
|
||||||
// Main navigation routes
|
// Main navigation routes
|
||||||
static const String myProfileScreen = '/my-profile-screen';
|
static const String myProfileScreen = '/my-profile-screen';
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'dart:developer';
|
|||||||
|
|
||||||
import 'package:dart_pusher_channels/dart_pusher_channels.dart';
|
import 'package:dart_pusher_channels/dart_pusher_channels.dart';
|
||||||
import 'package:easy_debounce/easy_debounce.dart';
|
import 'package:easy_debounce/easy_debounce.dart';
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/const.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.dart';
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/websockets/ws_service.dart';
|
import 'package:eatvio_app/core/websockets/ws_service.dart';
|
||||||
@@ -111,7 +112,7 @@ class WsManager {
|
|||||||
_privateNotificationChannel = client?.privateChannel(
|
_privateNotificationChannel = client?.privateChannel(
|
||||||
'$newNotificationsChannelName.$userId',
|
'$newNotificationsChannelName.$userId',
|
||||||
authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel(
|
authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel(
|
||||||
authorizationEndpoint: Uri.parse('$baseUrl/broadcasting/auth'),
|
authorizationEndpoint: Uri.parse('${sl<AppConfig>().baseUrl}/broadcasting/auth'),
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': 'Bearer $token',
|
'Authorization': 'Bearer $token',
|
||||||
},
|
},
|
||||||
@@ -124,7 +125,7 @@ class WsManager {
|
|||||||
_privateMessagesChannel = client?.privateChannel(
|
_privateMessagesChannel = client?.privateChannel(
|
||||||
'$newMessagesChannelName.$userId',
|
'$newMessagesChannelName.$userId',
|
||||||
authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel(
|
authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel(
|
||||||
authorizationEndpoint: Uri.parse('$baseUrl/broadcasting/auth'),
|
authorizationEndpoint: Uri.parse('${sl<AppConfig>().baseUrl}/broadcasting/auth'),
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': 'Bearer $token',
|
'Authorization': 'Bearer $token',
|
||||||
},
|
},
|
||||||
@@ -137,7 +138,7 @@ class WsManager {
|
|||||||
_privateDirectChatChannel = client?.privateChannel(
|
_privateDirectChatChannel = client?.privateChannel(
|
||||||
'$directChatChannelName.$chatId',
|
'$directChatChannelName.$chatId',
|
||||||
authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel(
|
authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel(
|
||||||
authorizationEndpoint: Uri.parse('$baseUrl/broadcasting/auth'),
|
authorizationEndpoint: Uri.parse('${sl<AppConfig>().baseUrl}/broadcasting/auth'),
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': 'Bearer $token',
|
'Authorization': 'Bearer $token',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.dart';
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
@@ -86,7 +86,7 @@ class CustomPopup extends StatelessWidget {
|
|||||||
|
|
||||||
if (isAuthor) {
|
if (isAuthor) {
|
||||||
addItem('assets/icons/copy2.svg', 'Скопировать ссылку', () {
|
addItem('assets/icons/copy2.svg', 'Скопировать ссылку', () {
|
||||||
Clipboard.setData(ClipboardData(text: '$baseUrl/ru/$path'));
|
Clipboard.setData(ClipboardData(text: '${sl<AppConfig>().baseUrl}/ru/$path'));
|
||||||
showInfoToast(s.link_was_copied);
|
showInfoToast(s.link_was_copied);
|
||||||
});
|
});
|
||||||
addItem('assets/icons/share2.svg', 'Поделиться', () {
|
addItem('assets/icons/share2.svg', 'Поделиться', () {
|
||||||
@@ -94,7 +94,7 @@ class CustomPopup extends StatelessWidget {
|
|||||||
SharePlus.instance.share(
|
SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse(
|
uri: Uri.parse(
|
||||||
'$baseUrl/ru/$path',
|
'${sl<AppConfig>().baseUrl}/ru/$path',
|
||||||
),
|
),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
@@ -140,7 +140,7 @@ class CustomPopup extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
addItem('assets/icons/copy2.svg', 'Скопировать ссылку', () {
|
addItem('assets/icons/copy2.svg', 'Скопировать ссылку', () {
|
||||||
Clipboard.setData(ClipboardData(text: '$baseUrl/ru/$path'));
|
Clipboard.setData(ClipboardData(text: '${sl<AppConfig>().baseUrl}/ru/$path'));
|
||||||
showInfoToast(s.link_was_copied);
|
showInfoToast(s.link_was_copied);
|
||||||
});
|
});
|
||||||
addItem('assets/icons/share2.svg', 'Поделиться', () {
|
addItem('assets/icons/share2.svg', 'Поделиться', () {
|
||||||
@@ -148,7 +148,7 @@ class CustomPopup extends StatelessWidget {
|
|||||||
SharePlus.instance.share(
|
SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse(
|
uri: Uri.parse(
|
||||||
'$baseUrl/ru/$path',
|
'${sl<AppConfig>().baseUrl}/ru/$path',
|
||||||
),
|
),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
|
|||||||
15
lib/features/auth/models/oauth_login_request.dart
Normal file
15
lib/features/auth/models/oauth_login_request.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'oauth_login_request.freezed.dart';
|
||||||
|
part 'oauth_login_request.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class OAuthLoginRequest with _$OAuthLoginRequest {
|
||||||
|
const factory OAuthLoginRequest({
|
||||||
|
required String provider,
|
||||||
|
@JsonKey(name: 'access_token') required String accessToken,
|
||||||
|
@JsonKey(name: 'refresh_token') required String refreshToken,
|
||||||
|
}) = _OAuthLoginRequest;
|
||||||
|
|
||||||
|
factory OAuthLoginRequest.fromJson(Map<String, dynamic> json) => _$OAuthLoginRequestFromJson(json);
|
||||||
|
}
|
||||||
24
lib/features/auth/models/oauth_model.dart
Normal file
24
lib/features/auth/models/oauth_model.dart
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'oauth_model.freezed.dart';
|
||||||
|
part 'oauth_model.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class OAuthModel with _$OAuthModel {
|
||||||
|
const factory OAuthModel({
|
||||||
|
required String provider,
|
||||||
|
required String id,
|
||||||
|
@JsonKey(name: 'access_token') required String accessToken,
|
||||||
|
@JsonKey(name: 'refresh_token') required String refreshToken,
|
||||||
|
@JsonKey(name: 'first_name') required String firstName,
|
||||||
|
@JsonKey(name: 'last_name') required String lastName,
|
||||||
|
required String email,
|
||||||
|
required String phone,
|
||||||
|
@JsonKey(name: 'date_of_birth') required String dateOfBirth,
|
||||||
|
required String gender,
|
||||||
|
required int weight,
|
||||||
|
required int height,
|
||||||
|
}) = _OAuthModel;
|
||||||
|
|
||||||
|
factory OAuthModel.fromJson(Map<String, dynamic> json) => _$OAuthModelFromJson(json);
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
import 'package:eatvio_app/features/auth/presentation/bloc/oauth_cubit/oauth_state.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/repositories/auth_repository.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
class OAuthCubit extends Cubit<OAuthState> {
|
||||||
|
final AuthRepository authRepository;
|
||||||
|
|
||||||
|
OAuthCubit({required this.authRepository}) : super(const OAuthState());
|
||||||
|
|
||||||
|
Future<void> getOAuthLogin({required String provider, required String accessToken, required String refreshToken}) async {
|
||||||
|
try {
|
||||||
|
log('OAuthCubit: Starting OAuth login for provider: $provider');
|
||||||
|
emit(const OAuthState.loading());
|
||||||
|
log('OAuthCubit: Emitted loading state');
|
||||||
|
|
||||||
|
final tokenModel = await authRepository.getOAuthLogin(provider: provider, accessToken: accessToken, refreshToken: refreshToken);
|
||||||
|
log('OAuthCubit: Got token model: ${tokenModel.token}');
|
||||||
|
emit(OAuthState.loaded(token: tokenModel.token));
|
||||||
|
log('OAuthCubit: Emitted loaded state');
|
||||||
|
} catch (e) {
|
||||||
|
log('OAuthCubit: Error occurred: $e');
|
||||||
|
emit(OAuthState.error(errorMessage: e.toString()));
|
||||||
|
log('OAuthCubit: Emitted error state');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getOAuthToken({
|
||||||
|
required String provider,
|
||||||
|
required String accessToken,
|
||||||
|
required String id,
|
||||||
|
required String refreshToken,
|
||||||
|
required String firstName,
|
||||||
|
required String lastName,
|
||||||
|
required String email,
|
||||||
|
required String phone,
|
||||||
|
required String dateOfBirth,
|
||||||
|
required String gender,
|
||||||
|
required int weight,
|
||||||
|
required int height,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
emit(const OAuthState.loading());
|
||||||
|
final token = await authRepository.getOAuthToken(
|
||||||
|
provider: provider,
|
||||||
|
accessToken: accessToken,
|
||||||
|
id: id,
|
||||||
|
refreshToken: refreshToken,
|
||||||
|
firstName: firstName,
|
||||||
|
lastName: lastName,
|
||||||
|
email: email,
|
||||||
|
phone: phone,
|
||||||
|
dateOfBirth: dateOfBirth,
|
||||||
|
gender: gender,
|
||||||
|
weight: weight,
|
||||||
|
height: height,
|
||||||
|
);
|
||||||
|
emit(OAuthState.loaded(token: token));
|
||||||
|
} catch (e) {
|
||||||
|
emit(OAuthState.error(errorMessage: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'oauth_state.freezed.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class OAuthState with _$OAuthState {
|
||||||
|
const factory OAuthState() = _OAuthState;
|
||||||
|
|
||||||
|
const factory OAuthState.loading() = OAuthStateLoading;
|
||||||
|
|
||||||
|
const factory OAuthState.loaded({required String token}) = OAuthStateLoaded;
|
||||||
|
|
||||||
|
const factory OAuthState.error({required String errorMessage}) = OAuthStateError;
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
import 'package:eatvio_app/app_keys.dart';
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/app_router.dart';
|
import 'package:eatvio_app/core/app_router.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/const.dart';
|
||||||
import 'package:eatvio_app/core/firebase_api.dart';
|
import 'package:eatvio_app/core/firebase_api.dart';
|
||||||
@@ -14,6 +16,10 @@ import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
|||||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||||
import 'package:eatvio_app/features/auth/presentation/bloc/auth_cubit/auth_cubit.dart';
|
import 'package:eatvio_app/features/auth/presentation/bloc/auth_cubit/auth_cubit.dart';
|
||||||
import 'package:eatvio_app/features/auth/presentation/bloc/auth_cubit/auth_state.dart';
|
import 'package:eatvio_app/features/auth/presentation/bloc/auth_cubit/auth_state.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/presentation/bloc/oauth_cubit/oauth_cubit.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/presentation/bloc/oauth_cubit/oauth_state.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/entities/auth_result_entity.dart';
|
||||||
|
import 'package:eatvio_app/core/di/cubit_registrations.dart';
|
||||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
||||||
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
|
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
|
||||||
import 'package:eatvio_app/features/dev_tools/presentation/dev_tools_screen.dart';
|
import 'package:eatvio_app/features/dev_tools/presentation/dev_tools_screen.dart';
|
||||||
@@ -46,7 +52,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
late StreamSubscription<bool> keyboardSubscription;
|
late StreamSubscription<bool> keyboardSubscription;
|
||||||
bool isFocused = false;
|
bool isFocused = false;
|
||||||
int tapsCount = 0;
|
int tapsCount = 0;
|
||||||
|
bool _isLoading = false;
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -92,6 +98,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var shortestSide = MediaQuery.sizeOf(context).shortestSide;
|
var shortestSide = MediaQuery.sizeOf(context).shortestSide;
|
||||||
|
final screenSize = MediaQuery.of(context).size;
|
||||||
final bool useMobileLayout = shortestSide < 600;
|
final bool useMobileLayout = shortestSide < 600;
|
||||||
if (!useMobileLayout) isFocused = true;
|
if (!useMobileLayout) isFocused = true;
|
||||||
final s = S.of(context);
|
final s = S.of(context);
|
||||||
@@ -102,9 +109,10 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
builder: (BuildContext context, AuthState state) {
|
builder: (BuildContext context, AuthState state) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
toolbarHeight: screenSize.height * 0.15,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
toolbarHeight: isFocused ? 64 : MediaQuery.of(context).size.width - 64,
|
|
||||||
title: GestureDetector(
|
title: GestureDetector(
|
||||||
|
key: AppKeys.hiddenLogoButtonAuthScreen,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
tapsCount++;
|
tapsCount++;
|
||||||
if (tapsCount == 7) {
|
if (tapsCount == 7) {
|
||||||
@@ -112,7 +120,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
GoRouter.of(context).pushNamed(DevToolsScreen.name);
|
GoRouter.of(context).pushNamed(DevToolsScreen.name);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: SvgPicture.asset(ImageConstant.imgLogoEatvio, height: isFocused ? 64 : MediaQuery.of(context).size.width - 64, fit: BoxFit.contain),
|
child: SvgPicture.asset(ImageConstant.imgLogoEatvio, height: screenSize.height * 0.20),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
@@ -122,8 +130,8 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// Social auth buttons at the top (outlined)
|
// Social auth buttons at the top (outlined)
|
||||||
const Text('Авторизация через:', style: TextStyle(fontWeight: FontWeight.w600)),
|
const Center(child: Text('Авторизация через')),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 12),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@@ -164,6 +172,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
keyboardType: TextInputType.emailAddress,
|
keyboardType: TextInputType.emailAddress,
|
||||||
textInputType: TextInputType.emailAddress,
|
textInputType: TextInputType.emailAddress,
|
||||||
|
key: AppKeys.emailTextFieldAuthScreen,
|
||||||
hintText: 'Введите email',
|
hintText: 'Введите email',
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
@@ -172,6 +181,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
CustomTextFormField(
|
CustomTextFormField(
|
||||||
obscureText: hidePassword,
|
obscureText: hidePassword,
|
||||||
controller: passwordController,
|
controller: passwordController,
|
||||||
|
key: AppKeys.passwordTextFieldAuthScreen,
|
||||||
hintText: 'Введите пароль',
|
hintText: 'Введите пароль',
|
||||||
suffix: IconButton(
|
suffix: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@@ -224,7 +234,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
decorationColor: appTheme.blueA400,
|
decorationColor: appTheme.blueA400,
|
||||||
decoration: TextDecoration.underline,
|
decoration: TextDecoration.underline,
|
||||||
),
|
),
|
||||||
recognizer: TapGestureRecognizer()..onTap = () async => await launchUrl(Uri.parse('$baseUrl/oferta_bs.pdf')),
|
recognizer: TapGestureRecognizer()..onTap = () async => await launchUrl(Uri.parse('${sl<AppConfig>().baseUrl}/oferta_bs.pdf')),
|
||||||
),
|
),
|
||||||
const TextSpan(text: ' и '),
|
const TextSpan(text: ' и '),
|
||||||
],
|
],
|
||||||
@@ -236,7 +246,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
decorationColor: appTheme.blueA400,
|
decorationColor: appTheme.blueA400,
|
||||||
decoration: TextDecoration.underline,
|
decoration: TextDecoration.underline,
|
||||||
),
|
),
|
||||||
recognizer: TapGestureRecognizer()..onTap = () async => await launchUrl(Uri.parse('$baseUrl/docs/privacy.pdf')),
|
recognizer: TapGestureRecognizer()..onTap = () async => await launchUrl(Uri.parse('${sl<AppConfig>().baseUrl}/docs/privacy.pdf')),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -249,21 +259,28 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
height: 48,
|
height: 48,
|
||||||
width: MediaQuery.of(context).size.width - 88,
|
width: MediaQuery.of(context).size.width - 88,
|
||||||
child: FloatingActionButton.extended(
|
child: FloatingActionButton.extended(
|
||||||
|
key: AppKeys.signInButtonAuthScreen,
|
||||||
heroTag: 'authButton',
|
heroTag: 'authButton',
|
||||||
highlightElevation: 0,
|
highlightElevation: 0,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
focusElevation: 0,
|
focusElevation: 0,
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||||
backgroundColor: state is AuthStateLoading ? Colors.black.withAlpha(50) : appTheme.blueA400,
|
backgroundColor: (state is AuthStateLoading || _isLoading) ? Colors.black.withAlpha(50) : appTheme.blueA400,
|
||||||
onPressed: state is AuthStateLoading
|
onPressed: (state is AuthStateLoading || _isLoading)
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
|
setState(() {
|
||||||
|
_isLoading = true;
|
||||||
|
});
|
||||||
final isAuthenticated = await authCubit.getTokenByCredentials(emailController.text, passwordController.text);
|
final isAuthenticated = await authCubit.getTokenByCredentials(emailController.text, passwordController.text);
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
_reconnectWebSocket(context);
|
await _reconnectWebSocket(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setState(() {
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
label: state is AuthStateLoading
|
label: state is AuthStateLoading
|
||||||
? const CupertinoActivityIndicator()
|
? const CupertinoActivityIndicator()
|
||||||
@@ -296,7 +313,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
children: [
|
children: [
|
||||||
const Text('Где взять QR-код?\n', style: TextStyle(fontSize: 18)),
|
const Text('Где взять QR-код?\n', style: TextStyle(fontSize: 18)),
|
||||||
Text(
|
Text(
|
||||||
'1. Войдите на сайте $baseUrl в свой аккаунт\n\n2. Перейдите в настройки профиля\n\n3. В разделе "Доп информация" перейдите на "QR Login"',
|
'1. Войдите на сайте ${sl<AppConfig>().baseUrl} в свой аккаунт\n\n2. Перейдите в настройки профиля\n\n3. В разделе "Доп информация" перейдите на "QR Login"',
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Row(
|
Row(
|
||||||
@@ -391,21 +408,46 @@ class _SocialButton extends StatelessWidget {
|
|||||||
|
|
||||||
void _onVkPressed() async {
|
void _onVkPressed() async {
|
||||||
try {
|
try {
|
||||||
final accessToken = await SocialAuthFacade.signInWithVk();
|
log('VK button pressed');
|
||||||
if (accessToken == null) {
|
final context = AppRouter.navigatorKey.currentContext;
|
||||||
|
if (context == null) {
|
||||||
|
log('Context is null');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log('Getting VK auth result');
|
||||||
|
final authResult = await SocialAuthFacade.signInWithVkAndFetchProfile(context: context);
|
||||||
|
if (authResult == null) {
|
||||||
|
log('VK auth result is null');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log('VK auth result received, trying OAuth login');
|
||||||
|
// Пробуем сначала авторизоваться через новый API
|
||||||
|
if (context.mounted) {
|
||||||
|
await _tryOAuthLogin(context, authResult, 'vk');
|
||||||
|
} else {
|
||||||
|
log('Context is not mounted');
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e.toString());
|
log('VK button error: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onOkPressed() async {
|
void _onOkPressed() async {
|
||||||
try {
|
try {
|
||||||
final accessToken = await SocialAuthFacade.signInWithOk();
|
final context = AppRouter.navigatorKey.currentContext;
|
||||||
if (accessToken == null) {
|
if (context == null) return;
|
||||||
|
|
||||||
|
final authResult = await SocialAuthFacade.signInWithOkAndFetchProfile();
|
||||||
|
if (authResult == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Пробуем сначала авторизоваться через новый API
|
||||||
|
if (context.mounted) {
|
||||||
|
await _tryOAuthLogin(context, authResult, 'ok');
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e.toString());
|
log(e.toString());
|
||||||
}
|
}
|
||||||
@@ -413,18 +455,78 @@ void _onOkPressed() async {
|
|||||||
|
|
||||||
void _onMailRuPressed() async {
|
void _onMailRuPressed() async {
|
||||||
try {
|
try {
|
||||||
final accessToken = await SocialAuthFacade.signInWithMailRu();
|
final context = AppRouter.navigatorKey.currentContext;
|
||||||
if (accessToken == null) {
|
if (context == null) return;
|
||||||
|
|
||||||
|
final authResult = await SocialAuthFacade.signInWithMailRuAndFetchProfile();
|
||||||
|
if (authResult == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Пробуем сначала авторизоваться через новый API
|
||||||
|
if (context.mounted) {
|
||||||
|
await _tryOAuthLogin(context, authResult, 'mailru');
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e.toString());
|
log(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onYandexPressed() async {
|
void _onYandexPressed() async {
|
||||||
final accessToken = await SocialAuthFacade.signInWithYandex();
|
try {
|
||||||
if (accessToken == null) return;
|
final context = AppRouter.navigatorKey.currentContext;
|
||||||
|
if (context == null) return;
|
||||||
|
|
||||||
|
final authResult = await SocialAuthFacade.signInWithYandex();
|
||||||
|
if (authResult == null) return;
|
||||||
|
|
||||||
|
// Пробуем сначала авторизоваться через новый API
|
||||||
|
if (context.mounted) {
|
||||||
|
await _tryOAuthLogin(context, authResult, 'yandex');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Пробует авторизоваться через новый OAuth login API
|
||||||
|
/// Если получает ошибку (включая 422 - пользователь не найден), переходит к регистрации
|
||||||
|
Future<void> _tryOAuthLogin(BuildContext context, AuthResultEntity authResult, String provider) async {
|
||||||
|
log('Starting OAuth login for provider: $provider');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Создаем OAuth cubit
|
||||||
|
final oauthCubit = CubitRegistrations.sl<OAuthCubit>();
|
||||||
|
StreamSubscription? subscription;
|
||||||
|
|
||||||
|
// Слушаем изменения состояния
|
||||||
|
subscription = oauthCubit.stream.listen((state) {
|
||||||
|
log('OAuth state changed: ${state.runtimeType}');
|
||||||
|
|
||||||
|
if (state is OAuthStateLoaded) {
|
||||||
|
// Успешная авторизация - переходим на главный экран
|
||||||
|
log('OAuth login successful, navigating to main screen');
|
||||||
|
subscription?.cancel();
|
||||||
|
_reconnectAfterAuth();
|
||||||
|
} else if (state is OAuthStateError) {
|
||||||
|
// Ошибка авторизации (включая 422 - пользователь не найден) - переходим к регистрации
|
||||||
|
log('OAuth login failed: ${state.errorMessage}');
|
||||||
|
subscription?.cancel();
|
||||||
|
AppRouter.navigateToRegisterViaSocial(authResult: authResult, provider: provider);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Пробуем авторизоваться
|
||||||
|
log('Calling getOAuthLogin with provider: $provider');
|
||||||
|
await oauthCubit.getOAuthLogin(provider: provider, accessToken: authResult.accessToken, refreshToken: authResult.refreshToken ?? '');
|
||||||
|
|
||||||
|
// Ждем немного, чтобы состояние успело обновиться
|
||||||
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
|
} catch (e) {
|
||||||
|
// В случае любой ошибки (включая 422 - пользователь не найден) переходим к регистрации
|
||||||
|
log('OAuth login error in catch block: $e');
|
||||||
|
AppRouter.navigateToRegisterViaSocial(authResult: authResult, provider: provider);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _reconnectAfterAuth() async {
|
Future<void> _reconnectAfterAuth() async {
|
||||||
|
|||||||
@@ -0,0 +1,484 @@
|
|||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/const.dart';
|
||||||
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
|
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||||
|
import 'package:eatvio_app/core/di/cubit_registrations.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/presentation/bloc/oauth_cubit/oauth_cubit.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/presentation/bloc/oauth_cubit/oauth_state.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/entities/auth_result_entity.dart';
|
||||||
|
import 'package:eatvio_app/core/app_router.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
|
import 'package:eatvio_app/core/websockets/ws_manager.dart';
|
||||||
|
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
||||||
|
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
|
||||||
|
import 'package:eatvio_app/features/notifications/presentation/notifications_cubit/notifications_cubit.dart';
|
||||||
|
import 'package:eatvio_app/core/firebase_api.dart';
|
||||||
|
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class RegisterViaSocialScreen extends StatefulWidget {
|
||||||
|
final AuthResultEntity? authResult;
|
||||||
|
final String? provider;
|
||||||
|
|
||||||
|
const RegisterViaSocialScreen({super.key, this.authResult, this.provider});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<RegisterViaSocialScreen> createState() => _RegisterViaSocialScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RegisterViaSocialScreenState extends State<RegisterViaSocialScreen> {
|
||||||
|
final maskFormatter = MaskTextInputFormatter(mask: '+7 (###) ### ## ##', filter: {"#": RegExp(r'[0-9]')}, type: MaskAutoCompletionType.lazy);
|
||||||
|
final maskFormatterForBirthday = MaskTextInputFormatter(mask: '##.##.####', filter: {"#": RegExp(r'[0-9]')}, type: MaskAutoCompletionType.lazy);
|
||||||
|
|
||||||
|
// Контроллеры для полей ввода
|
||||||
|
final firstNameController = TextEditingController();
|
||||||
|
final lastNameController = TextEditingController();
|
||||||
|
final emailController = TextEditingController();
|
||||||
|
final phoneController = TextEditingController();
|
||||||
|
final dateOfBirthController = TextEditingController();
|
||||||
|
final weightController = TextEditingController();
|
||||||
|
final heightController = TextEditingController();
|
||||||
|
|
||||||
|
// Состояние для выбора пола
|
||||||
|
bool isMaleSelected = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_initializeFieldsFromAuthResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _reconnectWebSocket(BuildContext context) async {
|
||||||
|
try {
|
||||||
|
await sl<WsManager>().clear();
|
||||||
|
await sl<WsManager>().initialize();
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
if (context.mounted) {
|
||||||
|
try {
|
||||||
|
await sl<ProfileAvatarCubit>().getMyProfile();
|
||||||
|
await sl<ChatsCubit>().getChatRoomsWithLoading();
|
||||||
|
await sl<ChatsCubit>().connectToWebSocket();
|
||||||
|
await sl<NotificationsCubit>().getNotifications();
|
||||||
|
await sl<NotificationsCubit>().connectToWebSocket();
|
||||||
|
await sl<FirebaseApi>().registerPushToken();
|
||||||
|
showSuccessToast('Успешная регистрация');
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AppRouter.appRouter.go('/feed-screen', extra: {'needToInitializeWebSocket': false});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _initializeFieldsFromAuthResult() {
|
||||||
|
if (widget.authResult != null) {
|
||||||
|
final authResult = widget.authResult!;
|
||||||
|
|
||||||
|
if (authResult.firstName != null) {
|
||||||
|
firstNameController.text = authResult.firstName!;
|
||||||
|
}
|
||||||
|
if (authResult.lastName != null) {
|
||||||
|
lastNameController.text = authResult.lastName!;
|
||||||
|
}
|
||||||
|
if (authResult.email != null) {
|
||||||
|
emailController.text = authResult.email!;
|
||||||
|
}
|
||||||
|
if (authResult.phone != null) {
|
||||||
|
final cleanPhone = authResult.phone!.replaceAll(RegExp(r'[^\d]'), '');
|
||||||
|
final normalizedPhone = cleanPhone.startsWith('8') ? '7${cleanPhone.substring(1)}' : cleanPhone;
|
||||||
|
final phoneWithCountryCode = normalizedPhone.startsWith('7') ? normalizedPhone : '7$normalizedPhone';
|
||||||
|
final formattedPhone = maskFormatter.maskText('+$phoneWithCountryCode');
|
||||||
|
phoneController.text = formattedPhone;
|
||||||
|
}
|
||||||
|
if (authResult.birthDate != null) {
|
||||||
|
final formattedDate = _formatBirthDate(authResult.birthDate!);
|
||||||
|
final maskedDate = maskFormatterForBirthday.maskText(formattedDate);
|
||||||
|
dateOfBirthController.text = maskedDate;
|
||||||
|
}
|
||||||
|
if (authResult.gender != null) {
|
||||||
|
isMaleSelected = authResult.gender == GenderEnum.male;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatBirthDate(String birthDate) {
|
||||||
|
try {
|
||||||
|
// Пытаемся распарсить различные форматы даты
|
||||||
|
DateTime? date;
|
||||||
|
|
||||||
|
// Если дата в формате ISO (YYYY-MM-DD)
|
||||||
|
if (birthDate.contains('-')) {
|
||||||
|
date = DateTime.tryParse(birthDate);
|
||||||
|
}
|
||||||
|
// Если дата в формате DD.MM.YYYY
|
||||||
|
else if (birthDate.contains('.')) {
|
||||||
|
final parts = birthDate.split('.');
|
||||||
|
if (parts.length == 3) {
|
||||||
|
final day = int.tryParse(parts[0]);
|
||||||
|
final month = int.tryParse(parts[1]);
|
||||||
|
final year = int.tryParse(parts[2]);
|
||||||
|
if (day != null && month != null && year != null) {
|
||||||
|
date = DateTime(year, month, day);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (date != null) {
|
||||||
|
// Форматируем в DD.MM.YYYY
|
||||||
|
final day = date.day.toString().padLeft(2, '0');
|
||||||
|
final month = date.month.toString().padLeft(2, '0');
|
||||||
|
final year = date.year.toString();
|
||||||
|
return '$day.$month.$year';
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Если не удалось распарсить, возвращаем исходную строку
|
||||||
|
}
|
||||||
|
|
||||||
|
return birthDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
firstNameController.dispose();
|
||||||
|
lastNameController.dispose();
|
||||||
|
emailController.dispose();
|
||||||
|
phoneController.dispose();
|
||||||
|
dateOfBirthController.dispose();
|
||||||
|
weightController.dispose();
|
||||||
|
heightController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocProvider<OAuthCubit>(
|
||||||
|
create: (context) => CubitRegistrations.sl<OAuthCubit>(),
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: AppBar(),
|
||||||
|
body: BlocBuilder<OAuthCubit, OAuthState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Center(
|
||||||
|
child: Text(
|
||||||
|
'Регистрация',
|
||||||
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.w700, height: 1.1, color: Color(0xFF323F4B)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width / 2 - 22,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Text('Имя'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
CustomTextFormField(controller: firstNameController, hintText: 'Введите имя', onChanged: (newValue) {}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width / 2 - 22,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text('Фамилия'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
CustomTextFormField(controller: lastNameController, hintText: 'Введите фамилию', onChanged: (newValue) {}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
const Text('Почта'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
CustomTextFormField(
|
||||||
|
controller: emailController,
|
||||||
|
textInputType: TextInputType.emailAddress,
|
||||||
|
keyboardType: TextInputType.emailAddress,
|
||||||
|
hintText: 'Введите email',
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
onChanged: (newValue) {},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
const Text('Номер телефона'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
CustomTextFormField(
|
||||||
|
textInputAction: TextInputAction.done,
|
||||||
|
hintText: '+7 (999) 999 99 99',
|
||||||
|
controller: phoneController,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: [maskFormatter],
|
||||||
|
onChanged: (newValue) {
|
||||||
|
// Дополнительная обработка изменений номера телефона
|
||||||
|
// Это поможет маске корректно работать при редактировании
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width / 2 - 22,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Text('Дата рождения'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
CustomTextFormField(
|
||||||
|
textInputAction: TextInputAction.done,
|
||||||
|
hintText: '01.01.2000',
|
||||||
|
controller: dateOfBirthController,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: [maskFormatterForBirthday],
|
||||||
|
onChanged: (newValue) {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width / 2 - 22,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text('Пол'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: _genderButton('М', isMaleSelected)),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Expanded(child: _genderButton('Ж', !isMaleSelected)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width / 2 - 22,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Text('Вес'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
CustomTextFormField(controller: weightController, hintText: 'Введите вес', onChanged: (newValue) {}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width / 2 - 22,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text('Рост'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
CustomTextFormField(controller: heightController, hintText: 'Введите рост', onChanged: (newValue) {}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 28),
|
||||||
|
const Center(
|
||||||
|
child: Text(
|
||||||
|
'Проверьте правильность заполненных\nданных. Пол, рост и вес требуются для\nрасчета вашей дневной нормы калорий',
|
||||||
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF323F4B)),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 28),
|
||||||
|
InkWell(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
onTap: () => _handleRegistration(context),
|
||||||
|
child: Ink(
|
||||||
|
width: MediaQuery.of(context).size.width - 32,
|
||||||
|
height: 52,
|
||||||
|
decoration: BoxDecoration(color: state is OAuthStateLoading ? Colors.grey : appTheme.blueA400, borderRadius: BorderRadius.circular(20)),
|
||||||
|
child: Center(
|
||||||
|
child: state is OAuthStateLoading
|
||||||
|
? const CircularProgressIndicator(color: Colors.white)
|
||||||
|
: const Text(
|
||||||
|
'Зарегистрироваться',
|
||||||
|
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18, color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Center(
|
||||||
|
child: RichText(
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
text: TextSpan(
|
||||||
|
text: 'Нажимая "Зарегистрироваться", Вы соглашаетесь\n',
|
||||||
|
style: const TextStyle(fontSize: 16, color: Colors.black),
|
||||||
|
children: [
|
||||||
|
const TextSpan(
|
||||||
|
text: 'c ',
|
||||||
|
style: TextStyle(fontSize: 16, color: Colors.black),
|
||||||
|
),
|
||||||
|
if (!hidePlans) ...[
|
||||||
|
TextSpan(
|
||||||
|
text: ' Публичной офертой',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: appTheme.blueA400,
|
||||||
|
decorationColor: appTheme.blueA400,
|
||||||
|
decoration: TextDecoration.underline,
|
||||||
|
),
|
||||||
|
recognizer: TapGestureRecognizer()..onTap = () async => await launchUrl(Uri.parse('${sl<AppConfig>().baseUrl}oferta_bs.pdf')),
|
||||||
|
),
|
||||||
|
const TextSpan(
|
||||||
|
text: ' и ',
|
||||||
|
style: TextStyle(fontSize: 16, color: Colors.black),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
TextSpan(
|
||||||
|
text: 'Политикой конфиденциальности и защитой персональных данных',
|
||||||
|
style: TextStyle(fontSize: 16, color: appTheme.blueA400, decorationColor: appTheme.blueA400, decoration: TextDecoration.underline),
|
||||||
|
recognizer: TapGestureRecognizer()..onTap = () async => await launchUrl(Uri.parse('${sl<AppConfig>().baseUrl}/docs/privacy.pdf')),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Показываем ошибки если есть
|
||||||
|
if (state is OAuthStateError) ...[
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.red.shade50,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(color: Colors.red.shade200),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
state.errorMessage,
|
||||||
|
style: TextStyle(color: Colors.red.shade700),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
// Обработка успешной регистрации
|
||||||
|
if (state is OAuthStateLoaded) ...[
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.green.shade50,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(color: Colors.green.shade200),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Регистрация успешно завершена!',
|
||||||
|
style: TextStyle(color: Colors.green),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Автоматический переход на главный экран после успешной регистрации
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_reconnectWebSocket(context);
|
||||||
|
});
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _genderButton(String gender, bool isActive) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
isMaleSelected = gender == 'М';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
child: Ink(
|
||||||
|
height: 52,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFF6F6F6),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
border: isActive ? Border.all(width: 2, color: appTheme.blueA400) : null,
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
gender,
|
||||||
|
style: TextStyle(color: isActive ? appTheme.blueA400 : const Color(0xFF323F4B), fontSize: 16, fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleRegistration(BuildContext context) {
|
||||||
|
// Валидация полей
|
||||||
|
if (firstNameController.text.isEmpty ||
|
||||||
|
lastNameController.text.isEmpty ||
|
||||||
|
emailController.text.isEmpty ||
|
||||||
|
phoneController.text.isEmpty ||
|
||||||
|
dateOfBirthController.text.isEmpty ||
|
||||||
|
weightController.text.isEmpty ||
|
||||||
|
heightController.text.isEmpty) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Пожалуйста, заполните все поля')));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Парсим числовые значения
|
||||||
|
int? weight;
|
||||||
|
int? height;
|
||||||
|
try {
|
||||||
|
weight = int.parse(weightController.text);
|
||||||
|
height = int.parse(heightController.text);
|
||||||
|
} catch (e) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Вес и рост должны быть числами')));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Очищаем номер телефона от маски для отправки
|
||||||
|
final cleanPhone = phoneController.text.replaceAll(RegExp(r'[^\d+]'), '');
|
||||||
|
|
||||||
|
// Вызываем OAuth регистрацию
|
||||||
|
context.read<OAuthCubit>().getOAuthToken(
|
||||||
|
provider: widget.provider ?? 'social',
|
||||||
|
accessToken: widget.authResult?.accessToken ?? 'dummy_token',
|
||||||
|
id: widget.authResult?.userId ?? 'dummy_id',
|
||||||
|
refreshToken: widget.authResult?.refreshToken ?? 'dummy_refresh_token',
|
||||||
|
firstName: firstNameController.text,
|
||||||
|
lastName: lastNameController.text,
|
||||||
|
email: emailController.text,
|
||||||
|
phone: cleanPhone,
|
||||||
|
dateOfBirth: dateOfBirthController.text,
|
||||||
|
gender: isMaleSelected ? 'М' : 'Ж',
|
||||||
|
weight: weight,
|
||||||
|
height: height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/app_router.dart';
|
import 'package:eatvio_app/core/app_router.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
|
||||||
import 'package:eatvio_app/core/firebase_api.dart';
|
import 'package:eatvio_app/core/firebase_api.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.dart';
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/token_storage.dart';
|
import 'package:eatvio_app/core/token_storage.dart';
|
||||||
@@ -40,17 +40,11 @@ class _ScanQRCodeScreenState extends State<ScanQRCodeScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(title: const Text('Сканирование QR-кода'), centerTitle: true),
|
||||||
title: const Text('Сканирование QR-кода'),
|
|
||||||
centerTitle: true,
|
|
||||||
),
|
|
||||||
body: Column(
|
body: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: QRView(
|
child: QRView(key: qrKey, onQRViewCreated: _onQRViewCreated),
|
||||||
key: qrKey,
|
|
||||||
onQRViewCreated: _onQRViewCreated,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -68,17 +62,9 @@ class _ScanQRCodeScreenState extends State<ScanQRCodeScreen> {
|
|||||||
final scannedUrl = scanData.code;
|
final scannedUrl = scanData.code;
|
||||||
final uri = Uri.parse(scannedUrl ?? '');
|
final uri = Uri.parse(scannedUrl ?? '');
|
||||||
final scannedBaseUrl = (uri.hasAuthority) ? '${uri.scheme}://${uri.host}' : '';
|
final scannedBaseUrl = (uri.hasAuthority) ? '${uri.scheme}://${uri.host}' : '';
|
||||||
baseUrl = scannedBaseUrl;
|
sl<AppConfig>().setBaseUrl(scannedBaseUrl);
|
||||||
sl<Dio>().options.baseUrl = baseUrl;
|
sl<Dio>().options.baseUrl = scannedBaseUrl;
|
||||||
final response = await Dio().getUri(
|
final response = await Dio().getUri(uri, options: Options(headers: {'accept': 'application/json', 'content-type': 'application/json'}));
|
||||||
uri,
|
|
||||||
options: Options(
|
|
||||||
headers: {
|
|
||||||
'accept': 'application/json',
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
final token = response.data['token'];
|
final token = response.data['token'];
|
||||||
await TokenStorage.saveTokenInStorage(token);
|
await TokenStorage.saveTokenInStorage(token);
|
||||||
try {
|
try {
|
||||||
@@ -97,10 +83,7 @@ class _ScanQRCodeScreenState extends State<ScanQRCodeScreen> {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
AppRouter.navigatorKey.currentContext?.go(
|
AppRouter.navigatorKey.currentContext?.go('/feed-screen', extra: {'needToInitializeWebSocket': false});
|
||||||
'/feed-screen',
|
|
||||||
extra: {'needToInitializeWebSocket': false},
|
|
||||||
);
|
|
||||||
showSuccessToast('Добро пожаловать!');
|
showSuccessToast('Добро пожаловать!');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await controller.resumeCamera();
|
await controller.resumeCamera();
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import 'package:eatvio_app/features/auth/models/credentials_model.dart';
|
import 'package:eatvio_app/features/auth/models/credentials_model.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/models/oauth_model.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/models/oauth_login_request.dart';
|
||||||
import 'package:eatvio_app/features/auth/models/token_model.dart';
|
import 'package:eatvio_app/features/auth/models/token_model.dart';
|
||||||
import 'package:eatvio_app/features/auth/services/auth_service.dart';
|
import 'package:eatvio_app/features/auth/services/auth_service.dart';
|
||||||
import 'package:eatvio_app/features/auth/models/social_exchange_request.dart';
|
import 'package:eatvio_app/features/auth/models/social_exchange_request.dart';
|
||||||
@@ -8,26 +10,17 @@ class AuthRepository {
|
|||||||
|
|
||||||
AuthRepository({required this.authService});
|
AuthRepository({required this.authService});
|
||||||
|
|
||||||
Future<TokenModel> getTokenByCredentials(
|
Future<TokenModel> getTokenByCredentials(String email, String password) async {
|
||||||
String email,
|
|
||||||
String password,
|
|
||||||
) async {
|
|
||||||
try {
|
try {
|
||||||
return await authService.getTokenByCredentials(
|
return await authService.getTokenByCredentials(
|
||||||
credentials: CredentialsModel(
|
credentials: CredentialsModel(email: email, password: password),
|
||||||
email: email,
|
|
||||||
password: password,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<TokenModel> getTokenBySocial({
|
Future<TokenModel> getTokenBySocial({required String provider, required String accessToken}) async {
|
||||||
required String provider,
|
|
||||||
required String accessToken,
|
|
||||||
}) async {
|
|
||||||
try {
|
try {
|
||||||
return await authService.getTokenBySocial(
|
return await authService.getTokenBySocial(
|
||||||
body: SocialExchangeRequest(provider: provider, accessToken: accessToken),
|
body: SocialExchangeRequest(provider: provider, accessToken: accessToken),
|
||||||
@@ -36,4 +29,51 @@ class AuthRepository {
|
|||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<TokenModel> getOAuthLogin({required String provider, required String accessToken, required String refreshToken}) async {
|
||||||
|
try {
|
||||||
|
return await authService.getOAuthLogin(
|
||||||
|
body: OAuthLoginRequest(provider: provider, accessToken: accessToken, refreshToken: refreshToken),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> getOAuthToken({
|
||||||
|
required String provider,
|
||||||
|
required String accessToken,
|
||||||
|
required String id,
|
||||||
|
required String refreshToken,
|
||||||
|
required String firstName,
|
||||||
|
required String lastName,
|
||||||
|
required String email,
|
||||||
|
required String phone,
|
||||||
|
required String dateOfBirth,
|
||||||
|
required String gender,
|
||||||
|
required int weight,
|
||||||
|
required int height,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
return (await authService.getOAuthToken(
|
||||||
|
body: OAuthModel(
|
||||||
|
provider: provider,
|
||||||
|
accessToken: accessToken,
|
||||||
|
id: id,
|
||||||
|
refreshToken: refreshToken,
|
||||||
|
firstName: firstName,
|
||||||
|
lastName: lastName,
|
||||||
|
email: email,
|
||||||
|
phone: phone,
|
||||||
|
dateOfBirth: dateOfBirth,
|
||||||
|
gender: gender == 'М' ? 'male' : 'female',
|
||||||
|
weight: weight,
|
||||||
|
height: height,
|
||||||
|
),
|
||||||
|
))['token']!
|
||||||
|
as String;
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:eatvio_app/features/auth/entities/auth_result_entity.dart';
|
import 'package:eatvio_app/features/auth/entities/auth_result_entity.dart';
|
||||||
import 'package:eatvio_app/features/auth/models/yandex_profile_model.dart';
|
import 'package:eatvio_app/features/auth/models/yandex_profile_model.dart';
|
||||||
@@ -20,14 +21,14 @@ class SocialAuthFacade {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<AuthResultEntity?> signInWithVkAndFetchProfile({required BuildContext context}) async {
|
static Future<AuthResultEntity?> signInWithVkAndFetchProfile({required BuildContext context}) async {
|
||||||
final clientIdStr = EnvConfig.vkClientId.trim();
|
final clientIdStr = Platform.isIOS ? EnvConfig.vkClientIdIos.trim() : EnvConfig.vkClientIdAndroid.trim();
|
||||||
if (clientIdStr.isEmpty) {
|
if (clientIdStr.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final controller = VkIDController(clID: int.parse(clientIdStr));
|
final controller = VkIDController(clID: int.parse(clientIdStr));
|
||||||
final authUri = controller.generateAuthorizeLinkWithCodeVerifier();
|
final authUri = controller.generateAuthorizeLinkWithCodeVerifier(provider: VkProvider.vkID, scopes: [VkScope.email, VkScope.phone]);
|
||||||
|
|
||||||
final authUrl = authUri.value.toString();
|
final authUrl = authUri.value.toString();
|
||||||
final codeVerifier = authUri.key;
|
final codeVerifier = authUri.key;
|
||||||
@@ -90,33 +91,16 @@ class SocialAuthFacade {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>?> exchangeCodeForToken(String code, String clientId, String clientSecret) async {
|
static Future<AuthResultEntity?> signInWithOkAndFetchProfile() async {
|
||||||
final response = await http.post(
|
|
||||||
Uri.parse('https://oauth.yandex.ru/token'),
|
|
||||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
|
||||||
body: {'grant_type': 'authorization_code', 'code': code, 'client_id': clientId, 'client_secret': clientSecret},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
return jsonDecode(response.body) as Map<String, dynamic>;
|
|
||||||
} else {
|
|
||||||
log('Error exchanging code: ${response.body}');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<String?> signInWithOk() async {
|
|
||||||
final context = AppRouter.navigatorKey.currentContext;
|
final context = AppRouter.navigatorKey.currentContext;
|
||||||
if (context == null) return null;
|
if (context == null) return null;
|
||||||
final vkAuthRes = await _signInWithVkIdProvider(context: context, provider: VkProvider.okRu);
|
return await _signInWithVkIdProvider(context: context, provider: VkProvider.okRu);
|
||||||
return vkAuthRes?.accessToken;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<String?> signInWithMailRu() async {
|
static Future<AuthResultEntity?> signInWithMailRuAndFetchProfile() async {
|
||||||
final context = AppRouter.navigatorKey.currentContext;
|
final context = AppRouter.navigatorKey.currentContext;
|
||||||
if (context == null) return null;
|
if (context == null) return null;
|
||||||
final vkAuthRes = await _signInWithVkIdProvider(context: context, provider: VkProvider.mailRu);
|
return await _signInWithVkIdProvider(context: context, provider: VkProvider.mailRu);
|
||||||
return vkAuthRes?.accessToken;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<AuthResultEntity?> signInWithYandex() async {
|
static Future<AuthResultEntity?> signInWithYandex() async {
|
||||||
@@ -135,7 +119,7 @@ class SocialAuthFacade {
|
|||||||
'response_type': 'code',
|
'response_type': 'code',
|
||||||
'client_id': clientId,
|
'client_id': clientId,
|
||||||
'redirect_uri': redirectUri,
|
'redirect_uri': redirectUri,
|
||||||
'force_confirm': 'yes',
|
'force_confirm': 'true',
|
||||||
}).toString();
|
}).toString();
|
||||||
|
|
||||||
final redirectSchemePrefix = redirectUri;
|
final redirectSchemePrefix = redirectUri;
|
||||||
@@ -197,14 +181,14 @@ class SocialAuthFacade {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<AuthResultEntity?> _signInWithVkIdProvider({required BuildContext context, required VkProvider provider}) async {
|
static Future<AuthResultEntity?> _signInWithVkIdProvider({required BuildContext context, required VkProvider provider}) async {
|
||||||
final clientIdStr = EnvConfig.vkClientId.trim();
|
final clientIdStr = Platform.isIOS ? EnvConfig.vkClientIdIos.trim() : EnvConfig.vkClientIdAndroid.trim();
|
||||||
if (clientIdStr.isEmpty) {
|
if (clientIdStr.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final controller = VkIDController(clID: int.parse(clientIdStr));
|
final controller = VkIDController(clID: int.parse(clientIdStr));
|
||||||
|
|
||||||
final authUri = controller.generateAuthorizeLinkWithCodeVerifier(provider: provider);
|
final authUri = controller.generateAuthorizeLinkWithCodeVerifier(provider: provider, scopes: [VkScope.phone, VkScope.email,]);
|
||||||
final codeVerifier = authUri.key;
|
final codeVerifier = authUri.key;
|
||||||
final authUrl = authUri.value.toString();
|
final authUrl = authUri.value.toString();
|
||||||
final redirectScheme = 'vk$clientIdStr://';
|
final redirectScheme = 'vk$clientIdStr://';
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:eatvio_app/features/auth/models/credentials_model.dart';
|
import 'package:eatvio_app/features/auth/models/credentials_model.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/models/oauth_model.dart';
|
||||||
|
import 'package:eatvio_app/features/auth/models/oauth_login_request.dart';
|
||||||
import 'package:eatvio_app/features/auth/models/token_model.dart';
|
import 'package:eatvio_app/features/auth/models/token_model.dart';
|
||||||
import 'package:eatvio_app/features/auth/models/social_exchange_request.dart';
|
import 'package:eatvio_app/features/auth/models/social_exchange_request.dart';
|
||||||
import 'package:retrofit/retrofit.dart';
|
import 'package:retrofit/retrofit.dart';
|
||||||
@@ -11,12 +13,14 @@ abstract class AuthService {
|
|||||||
factory AuthService(Dio dio, {String? baseUrl}) = _AuthService;
|
factory AuthService(Dio dio, {String? baseUrl}) = _AuthService;
|
||||||
|
|
||||||
@POST('/api/login')
|
@POST('/api/login')
|
||||||
Future<TokenModel> getTokenByCredentials({
|
Future<TokenModel> getTokenByCredentials({@Body() required CredentialsModel credentials});
|
||||||
@Body() required CredentialsModel credentials,
|
|
||||||
});
|
|
||||||
|
|
||||||
@POST('/api/social/login')
|
@POST('/api/social/login')
|
||||||
Future<TokenModel> getTokenBySocial({
|
Future<TokenModel> getTokenBySocial({@Body() required SocialExchangeRequest body});
|
||||||
@Body() required SocialExchangeRequest body,
|
|
||||||
});
|
@POST('/api/oauth/callback')
|
||||||
|
Future<Map<String, Object?>> getOAuthToken({@Body() required OAuthModel body});
|
||||||
|
|
||||||
|
@POST('/api/oauth/login')
|
||||||
|
Future<TokenModel> getOAuthLogin({@Body() required OAuthLoginRequest body});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||||
@@ -207,7 +207,7 @@ class _BlogPostScreenState extends State<BlogPostScreen> {
|
|||||||
children: [
|
children: [
|
||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
radius: 16,
|
radius: 16,
|
||||||
foregroundImage: NetworkImage(baseUrl + (blogPostState.blogPostModel?.author.authorProfileIcon ?? '')),
|
foregroundImage: NetworkImage(sl<AppConfig>().baseUrl + (blogPostState.blogPostModel?.author.authorProfileIcon ?? '')),
|
||||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
@@ -239,7 +239,7 @@ class _BlogPostScreenState extends State<BlogPostScreen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
if (blogPostState.blogPostModel?.image.isNotEmpty ?? false)
|
if (blogPostState.blogPostModel?.image.isNotEmpty ?? false)
|
||||||
CachedNetworkImage(imageUrl: '$baseUrl/storage/${blogPostState.blogPostModel?.image ?? ''}'),
|
CachedNetworkImage(imageUrl: '${sl<AppConfig>().baseUrl}/storage/${blogPostState.blogPostModel?.image ?? ''}'),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -267,7 +267,7 @@ class _BlogPostScreenState extends State<BlogPostScreen> {
|
|||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
SharePlus.instance.share(
|
SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse('$baseUrl/ru/blog_post/${widget.id}'),
|
uri: Uri.parse('${sl<AppConfig>().baseUrl}/ru/blog_post/${widget.id}'),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/app_router.dart';
|
import 'package:eatvio_app/core/app_router.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
|
||||||
import 'package:eatvio_app/core/permission_handler/permission_handler.dart';
|
import 'package:eatvio_app/core/permission_handler/permission_handler.dart';
|
||||||
import 'package:eatvio_app/core/theme/app_decoration.dart';
|
import 'package:eatvio_app/core/theme/app_decoration.dart';
|
||||||
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
|
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
|
||||||
@@ -304,7 +304,7 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
|||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
child: Image(
|
child: Image(
|
||||||
image: NetworkImage('$baseUrl/storage/${widget.feedBlogPostModel!.image}'),
|
image: NetworkImage('${sl<AppConfig>().baseUrl}/storage/${widget.feedBlogPostModel!.image}'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
||||||
import 'package:eatvio_app/features/blog_post_create/services/blog_post_service.dart';
|
import 'package:eatvio_app/features/blog_post_create/services/blog_post_service.dart';
|
||||||
@@ -36,7 +37,7 @@ class BlogPostRepository {
|
|||||||
Future<XFile?> downloadImage(String imageUrl) async {
|
Future<XFile?> downloadImage(String imageUrl) async {
|
||||||
try {
|
try {
|
||||||
// Загрузка изображения
|
// Загрузка изображения
|
||||||
final response = await http.get(Uri.parse('$baseUrl/storage/$imageUrl'));
|
final response = await http.get(Uri.parse('${sl<AppConfig>().baseUrl}/storage/$imageUrl'));
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// Получение временной директории
|
// Получение временной директории
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:badges/badges.dart' as badges;
|
import 'package:badges/badges.dart' as badges;
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/utils/image_constant.dart';
|
import 'package:eatvio_app/core/utils/image_constant.dart';
|
||||||
import 'package:eatvio_app/features/dev_tools/presentation/dev_tools_screen.dart';
|
import 'package:eatvio_app/features/dev_tools/presentation/dev_tools_screen.dart';
|
||||||
import 'package:eatvio_app/features/notifications/presentation/notifications_cubit/notifications_cubit.dart';
|
import 'package:eatvio_app/features/notifications/presentation/notifications_cubit/notifications_cubit.dart';
|
||||||
@@ -102,7 +103,7 @@ class _BottomNavigationBarWidgetState extends State<BottomNavigationBarWidget> {
|
|||||||
label: '',
|
label: '',
|
||||||
icon: CircleAvatar(
|
icon: CircleAvatar(
|
||||||
foregroundImage: NetworkImage(
|
foregroundImage: NetworkImage(
|
||||||
widget.profileModel.profilePhotoUrl.contains('https') ? widget.profileModel.profilePhotoUrl : baseUrl + widget.profileModel.profilePhotoUrl,
|
widget.profileModel.profilePhotoUrl.contains('https') ? widget.profileModel.profilePhotoUrl : sl<AppConfig>().baseUrl + widget.profileModel.profilePhotoUrl,
|
||||||
),
|
),
|
||||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||||
radius: 16,
|
radius: 16,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:dismissible_page/dismissible_page.dart';
|
import 'package:dismissible_page/dismissible_page.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/theme/app_decoration.dart';
|
import 'package:eatvio_app/core/theme/app_decoration.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
@@ -88,7 +89,7 @@ class _PhotoViewScreenState extends State<PhotoViewScreen> {
|
|||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
widget.imageUrls[index].replaceAll('$baseUrl/storage/chat_files/', ''),
|
widget.imageUrls[index].replaceAll('${sl<AppConfig>().baseUrl}/storage/chat_files/', ''),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.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/custom_text_style.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||||
@@ -47,7 +48,7 @@ class _OrderCardState extends State<OrderCard> {
|
|||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
child: Image.network(
|
child: Image.network(
|
||||||
'$baseUrl/storage/${widget.plan.image}',
|
'${sl<AppConfig>().baseUrl}/storage/${widget.plan.image}',
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/const.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart';
|
import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -49,7 +51,7 @@ class _LastStepScreenState extends State<LastStepScreen> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () async => await launchUrl(Uri.parse(hidePlans ? '$baseUrl/docs/privacy.pdf' : '$baseUrl/oferta_bs.pdf')),
|
onPressed: () async => await launchUrl(Uri.parse(hidePlans ? '${sl<AppConfig>().baseUrl}/docs/privacy.pdf' : '${sl<AppConfig>().baseUrl}/oferta_bs.pdf')),
|
||||||
child: Text(
|
child: Text(
|
||||||
hidePlans ? 'Политика конфиденциальности и пользовательское соглашение' : 'Договор офёрты',
|
hidePlans ? 'Политика конфиденциальности и пользовательское соглашение' : 'Договор офёрты',
|
||||||
style: const TextStyle(height: 1, fontSize: 16, color: Color(0xFF323F4B), decoration: TextDecoration.underline),
|
style: const TextStyle(height: 1, fontSize: 16, color: Color(0xFF323F4B), decoration: TextDecoration.underline),
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ import 'dart:convert';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/const.dart';
|
||||||
import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart';
|
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart';
|
||||||
import 'package:eatvio_app/features/create_diet/repositories/create_diet_repository.dart';
|
import 'package:eatvio_app/features/create_diet/repositories/create_diet_repository.dart';
|
||||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||||
@@ -53,7 +55,7 @@ class CreateDietCubit extends Cubit<CreateDietState> {
|
|||||||
name: diet.name,
|
name: diet.name,
|
||||||
duration: diet.duration,
|
duration: diet.duration,
|
||||||
type: type,
|
type: type,
|
||||||
imageUrl: '$baseUrl/storage/${diet.image}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${diet.image}',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
emit(state.copyWith(dietState: diet.state, durationIndex: durationValues.indexOf(diet.duration)));
|
emit(state.copyWith(dietState: diet.state, durationIndex: durationValues.indexOf(diet.duration)));
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/features/create_recipe/entities/recipe_create_entity.dart';
|
import 'package:eatvio_app/features/create_recipe/entities/recipe_create_entity.dart';
|
||||||
import 'package:eatvio_app/features/create_recipe/models/ingredient.dart' as i;
|
import 'package:eatvio_app/features/create_recipe/models/ingredient.dart' as i;
|
||||||
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_state.dart';
|
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_state.dart';
|
||||||
@@ -187,13 +188,13 @@ class CreateRecipeCubit extends Cubit<CreateRecipeState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> recipeToEntity(Recipe recipe) async {
|
Future<void> recipeToEntity(Recipe recipe) async {
|
||||||
final file = await downloadImageAsFile('$baseUrl/storage/${recipe.image}');
|
final file = await downloadImageAsFile('${sl<AppConfig>().baseUrl}/storage/${recipe.image}');
|
||||||
|
|
||||||
final List<StepEntity> steps = await Future.wait(
|
final List<StepEntity> steps = await Future.wait(
|
||||||
recipe.steps!.map(
|
recipe.steps!.map(
|
||||||
(e) async => StepEntity(
|
(e) async => StepEntity(
|
||||||
description: e.description,
|
description: e.description,
|
||||||
image: e.image.isEmpty ? null : await downloadImageAsFile('$baseUrl/storage/${e.image}'),
|
image: e.image.isEmpty ? null : await downloadImageAsFile('${sl<AppConfig>().baseUrl}/storage/${e.image}'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/app_router.dart';
|
import 'package:eatvio_app/core/app_router.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
|
||||||
import 'package:eatvio_app/core/firebase_api.dart';
|
import 'package:eatvio_app/core/firebase_api.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.dart';
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||||
@@ -84,7 +84,7 @@ class _DevToolsScreenContentState extends State<DevToolsScreenContent> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
setState(() {
|
setState(() {
|
||||||
baseUrlForTest = baseUrl;
|
baseUrlForTest = sl<AppConfig>().baseUrl;
|
||||||
});
|
});
|
||||||
testsStates = List.generate(testCases.length, (index) => TestState.notRun);
|
testsStates = List.generate(testCases.length, (index) => TestState.notRun);
|
||||||
}
|
}
|
||||||
@@ -111,8 +111,8 @@ class _DevToolsScreenContentState extends State<DevToolsScreenContent> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
baseUrlForTest = controller.text;
|
baseUrlForTest = controller.text;
|
||||||
baseUrl = baseUrlForTest.toLowerCase();
|
sl<AppConfig>().setBaseUrl(baseUrlForTest.toLowerCase());
|
||||||
sl<Dio>().options.baseUrl = baseUrl;
|
sl<Dio>().options.baseUrl = baseUrlForTest.toLowerCase();
|
||||||
controller.clear();
|
controller.clear();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -122,23 +122,23 @@ class _DevToolsScreenContentState extends State<DevToolsScreenContent> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
CustomOutlinedButton(
|
CustomOutlinedButton(
|
||||||
text: baseUrl == EnvConfig.devBaseUrl ? 'Set production base url' : 'Set dev2 base url',
|
text: sl<AppConfig>().baseUrl == EnvConfig.devBaseUrl ? 'Set production base url' : 'Set dev2 base url',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (baseUrl == EnvConfig.baseUrl) {
|
if (sl<AppConfig>().baseUrl == EnvConfig.baseUrl) {
|
||||||
baseUrlForTest = EnvConfig.devBaseUrl;
|
baseUrlForTest = EnvConfig.devBaseUrl;
|
||||||
} else {
|
} else {
|
||||||
baseUrlForTest = EnvConfig.baseUrl;
|
baseUrlForTest = EnvConfig.baseUrl;
|
||||||
}
|
}
|
||||||
baseUrl = baseUrlForTest.toLowerCase();
|
sl<AppConfig>().setBaseUrl(baseUrlForTest.toLowerCase());
|
||||||
sl<Dio>().options.baseUrl = baseUrl;
|
sl<Dio>().options.baseUrl = baseUrlForTest.toLowerCase();
|
||||||
controller.clear();
|
controller.clear();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
buttonStyle: const ButtonStyle(),
|
buttonStyle: const ButtonStyle(),
|
||||||
),
|
),
|
||||||
SizedBox(height: baseUrlForTest != baseUrl ? 40 : 10),
|
SizedBox(height: baseUrlForTest != sl<AppConfig>().baseUrl ? 40 : 10),
|
||||||
if (baseUrl.toLowerCase() != EnvConfig.baseUrl.toLowerCase())
|
if (sl<AppConfig>().baseUrl.toLowerCase() != EnvConfig.baseUrl.toLowerCase())
|
||||||
ListView.builder(
|
ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: testCases.length,
|
itemCount: testCases.length,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:eatvio_app/core/routing/route_constants.dart';
|
||||||
import 'package:eatvio_app/core/theme/custom_text_style.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/theme/theme_helper.dart';
|
||||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||||
@@ -6,77 +7,84 @@ import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
|||||||
import 'package:eatvio_app/generated/l10n.dart';
|
import 'package:eatvio_app/generated/l10n.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
class ChosenDietWidget extends StatelessWidget {
|
class ChosenDietWidget extends StatelessWidget {
|
||||||
const ChosenDietWidget({super.key});
|
const ChosenDietWidget({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<DiaryCubit, DiaryState>(builder: (context, state) {
|
return BlocBuilder<DiaryCubit, DiaryState>(
|
||||||
if (state is DiaryStateLoaded) {
|
builder: (context, state) {
|
||||||
if (state.diary.typeOfDiary.hasChosenDiet) {
|
if (state is DiaryStateLoaded) {
|
||||||
return ChosenDietWidgetContent(
|
if (state.diary.typeOfDiary.hasChosenDiet) {
|
||||||
currentDietDay: state.diary.dayOfChosenDiet ?? 0,
|
return ChosenDietWidgetContent(
|
||||||
dietName: state.diary.diet?.name ?? '',
|
currentDietDay: state.diary.dayOfChosenDiet ?? 0,
|
||||||
dietDuration: state.diary.diet?.duration ?? 0,
|
dietName: state.diary.diet?.name ?? '',
|
||||||
);
|
dietDuration: state.diary.diet?.duration ?? 0,
|
||||||
|
dietId: state.diary.diet?.id ?? 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (state is DiaryStateLoadedTomorrowWithDiet) {
|
||||||
if (state is DiaryStateLoadedTomorrowWithDiet) {
|
if (state.diary.typeOfDiary.hasChosenDiet) {
|
||||||
if (state.diary.typeOfDiary.hasChosenDiet) {
|
return Column(
|
||||||
return Column(
|
children: [
|
||||||
children: [
|
const CustomDivider(),
|
||||||
const CustomDivider(),
|
const SizedBox(height: 16),
|
||||||
const SizedBox(height: 16),
|
ChosenDietWidgetContent(
|
||||||
ChosenDietWidgetContent(
|
currentDietDay: state.diary.dayOfChosenDiet ?? 0,
|
||||||
currentDietDay: state.diary.dayOfChosenDiet ?? 0,
|
dietName: state.diary.diet?.name ?? '',
|
||||||
dietName: state.diary.diet?.name ?? '',
|
dietDuration: state.diary.diet?.duration ?? 0,
|
||||||
dietDuration: state.diary.diet?.duration ?? 0,
|
dietId: state.diary.diet?.id ?? 0,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChosenDietWidgetContent extends StatelessWidget {
|
class ChosenDietWidgetContent extends StatelessWidget {
|
||||||
const ChosenDietWidgetContent({
|
const ChosenDietWidgetContent({super.key, required this.currentDietDay, required this.dietName, required this.dietDuration, required this.dietId});
|
||||||
super.key,
|
|
||||||
required this.currentDietDay,
|
|
||||||
required this.dietName,
|
|
||||||
required this.dietDuration,
|
|
||||||
});
|
|
||||||
final int currentDietDay;
|
final int currentDietDay;
|
||||||
final String dietName;
|
final String dietName;
|
||||||
final int dietDuration;
|
final int dietDuration;
|
||||||
|
final int dietId;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final size = MediaQuery.sizeOf(context);
|
final size = MediaQuery.sizeOf(context);
|
||||||
final s = S.of(context);
|
final s = S.of(context);
|
||||||
return Column(
|
return GestureDetector(
|
||||||
children: [
|
onTap: () {
|
||||||
Row(
|
GoRouter.of(context).push(RouteConstants.aboutDietScreen, extra: {'id': dietId, 'navigateToComments': false});
|
||||||
children: [
|
},
|
||||||
SizedBox(
|
child: Column(
|
||||||
width: size.width * 0.4,
|
children: [
|
||||||
child: Text(dietName, style: TextStyles.textLMedium.copyWith(color: appTheme.black)),
|
Row(
|
||||||
),
|
children: [
|
||||||
const Spacer(),
|
SizedBox(
|
||||||
Container(
|
width: size.width * 0.4,
|
||||||
decoration: BoxDecoration(color: appTheme.dividerColor, borderRadius: BorderRadius.circular(12)),
|
child: Text(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
|
dietName,
|
||||||
child: Text('${s.day} $currentDietDay из $dietDuration', style: TextStyles.textMSemibold.copyWith(color: appTheme.gray)),
|
style: TextStyles.textLMedium.copyWith(color: appTheme.black, decoration: TextDecoration.underline),
|
||||||
)
|
),
|
||||||
],
|
),
|
||||||
),
|
const Spacer(),
|
||||||
const SizedBox(
|
Container(
|
||||||
height: 16,
|
decoration: BoxDecoration(color: appTheme.dividerColor, borderRadius: BorderRadius.circular(12)),
|
||||||
)
|
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
|
||||||
],
|
child: Text('${s.day} $currentDietDay из $dietDuration', style: TextStyles.textMSemibold.copyWith(color: appTheme.gray)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/app_router.dart';
|
import 'package:eatvio_app/core/app_router.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/permission_handler/permission_handler.dart';
|
import 'package:eatvio_app/core/permission_handler/permission_handler.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
|
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
|
||||||
@@ -139,7 +140,7 @@ class _PhotoGalleryWidgetState extends State<PhotoGalleryWidget> {
|
|||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: '$baseUrl/storage/${state.diary.meals[mealIndex].photos[currentSelectedPhotoIndex].path}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${state.diary.meals[mealIndex].photos[currentSelectedPhotoIndex].path}',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!state.isConsultantView && !state.isDiaryFinished && !state.isDiaryCommented)
|
if (!state.isConsultantView && !state.isDiaryFinished && !state.isDiaryCommented)
|
||||||
@@ -211,7 +212,7 @@ class _PhotoGalleryWidgetState extends State<PhotoGalleryWidget> {
|
|||||||
height: 52,
|
height: 52,
|
||||||
width: 52,
|
width: 52,
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: '$baseUrl/storage/${state.diary.meals[mealIndex].photos[i].path}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${state.diary.meals[mealIndex].photos[i].path}',
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -19,9 +19,14 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
|||||||
String? userStartedDietName;
|
String? userStartedDietName;
|
||||||
List<int> _selectedIndexes = [];
|
List<int> _selectedIndexes = [];
|
||||||
|
|
||||||
Future<void> getDiet(String slug, {int? index}) async {
|
Future<void> getDiet({String? slug, int? id, int? index}) async {
|
||||||
try {
|
try {
|
||||||
final diet = await dietsRepository.getDietBySlug(slug);
|
final Diet diet;
|
||||||
|
if (slug != null) {
|
||||||
|
diet = await dietsRepository.getDietBySlug(slug);
|
||||||
|
} else {
|
||||||
|
diet = await dietsRepository.getDiet(id!);
|
||||||
|
}
|
||||||
if (index != null) {
|
if (index != null) {
|
||||||
dietsRepository.emitCommentsStateToFeed(CommentsState(index: index, totalComments: diet.totalComments));
|
dietsRepository.emitCommentsStateToFeed(CommentsState(index: index, totalComments: diet.totalComments));
|
||||||
}
|
}
|
||||||
@@ -32,10 +37,16 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initDietPage(String slug) async {
|
Future<void> initDietPage({String? slug, int? id}) async {
|
||||||
try {
|
try {
|
||||||
emit(const AboutDietState.loading());
|
emit(const AboutDietState.loading());
|
||||||
final diet = await dietsRepository.getDietBySlug(slug);
|
final Diet diet;
|
||||||
|
if (slug != null) {
|
||||||
|
diet = await dietsRepository.getDietBySlug(slug);
|
||||||
|
} else {
|
||||||
|
diet = await dietsRepository.getDiet(id!);
|
||||||
|
}
|
||||||
|
|
||||||
final chosenDiets = await profileRepository.getChosenDiets();
|
final chosenDiets = await profileRepository.getChosenDiets();
|
||||||
final lastChosenDiet = chosenDiets.firstOrNull;
|
final lastChosenDiet = chosenDiets.firstOrNull;
|
||||||
if (lastChosenDiet != null && ['inited', 'started'].contains(lastChosenDiet.state)) {
|
if (lastChosenDiet != null && ['inited', 'started'].contains(lastChosenDiet.state)) {
|
||||||
@@ -50,12 +61,7 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_selectedIndexes = List.generate(diet.dailySchedule.length, (index) => 0);
|
_selectedIndexes = List.generate(diet.dailySchedule.length, (index) => 0);
|
||||||
emit(AboutDietState.loaded(
|
emit(AboutDietState.loaded(diet: diet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet, selectedIndexes: _selectedIndexes));
|
||||||
diet: diet,
|
|
||||||
isStarted: isCurrentDietStarted,
|
|
||||||
hasStartedDiet: hasStartedDiet,
|
|
||||||
selectedIndexes: _selectedIndexes,
|
|
||||||
));
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e.toString());
|
log(e.toString());
|
||||||
emit(AboutDietState.error(message: e.toString()));
|
emit(AboutDietState.error(message: e.toString()));
|
||||||
@@ -68,41 +74,30 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
|||||||
final currentDiet = (state as DietStateLoaded).diet;
|
final currentDiet = (state as DietStateLoaded).diet;
|
||||||
|
|
||||||
if (currentDiet.wasLikedByMe) {
|
if (currentDiet.wasLikedByMe) {
|
||||||
final updatedDiet = currentDiet.copyWith(
|
final updatedDiet = currentDiet.copyWith(totalLikes: currentDiet.totalLikes - 1, wasLikedByMe: false);
|
||||||
totalLikes: currentDiet.totalLikes - 1,
|
|
||||||
wasLikedByMe: false,
|
|
||||||
);
|
|
||||||
if (dietIndexInFeed != null) {
|
if (dietIndexInFeed != null) {
|
||||||
dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed));
|
dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed));
|
||||||
}
|
}
|
||||||
emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet, selectedIndexes: _selectedIndexes));
|
emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet, selectedIndexes: _selectedIndexes));
|
||||||
} else {
|
} else {
|
||||||
final updatedDiet = currentDiet.copyWith(
|
final updatedDiet = currentDiet.copyWith(totalLikes: currentDiet.totalLikes + 1, wasLikedByMe: true);
|
||||||
totalLikes: currentDiet.totalLikes + 1,
|
|
||||||
wasLikedByMe: true,
|
|
||||||
);
|
|
||||||
if (dietIndexInFeed != null) {
|
if (dietIndexInFeed != null) {
|
||||||
dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed));
|
dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed));
|
||||||
}
|
}
|
||||||
emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet, selectedIndexes: _selectedIndexes));
|
emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet, selectedIndexes: _selectedIndexes));
|
||||||
}
|
}
|
||||||
|
|
||||||
EasyDebounce.debounce(
|
EasyDebounce.debounce('like_diet', const Duration(seconds: 1), () async {
|
||||||
'like_diet',
|
try {
|
||||||
const Duration(seconds: 1),
|
await dietsRepository.likeDiet(id);
|
||||||
() async {
|
} catch (e) {
|
||||||
try {
|
log(e.toString());
|
||||||
await dietsRepository.likeDiet(id);
|
if (dietIndexInFeed != null) {
|
||||||
} catch (e) {
|
dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: currentDiet.wasLikedByMe, totalLikes: currentDiet.totalLikes, index: dietIndexInFeed));
|
||||||
log(e.toString());
|
|
||||||
if (dietIndexInFeed != null) {
|
|
||||||
dietsRepository
|
|
||||||
.emitLikesStateToFeed(LikesState(wasLikedByMe: currentDiet.wasLikedByMe, totalLikes: currentDiet.totalLikes, index: dietIndexInFeed));
|
|
||||||
}
|
|
||||||
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
|
||||||
}
|
}
|
||||||
},
|
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||||
);
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> addToFavorite(int id, int? dietIndex) async {
|
Future<void> addToFavorite(int id, int? dietIndex) async {
|
||||||
@@ -110,30 +105,24 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
|||||||
|
|
||||||
final currentDiet = (state as DietStateLoaded).diet;
|
final currentDiet = (state as DietStateLoaded).diet;
|
||||||
|
|
||||||
final updatedDiet = currentDiet.copyWith(
|
final updatedDiet = currentDiet.copyWith(isFavorite: true);
|
||||||
isFavorite: true,
|
|
||||||
);
|
|
||||||
if (dietIndex != null) {
|
if (dietIndex != null) {
|
||||||
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndex));
|
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndex));
|
||||||
}
|
}
|
||||||
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||||
|
|
||||||
EasyDebounce.debounce(
|
EasyDebounce.debounce('add_or_remove_diet_to_favorites', const Duration(seconds: 1), () async {
|
||||||
'add_or_remove_diet_to_favorites',
|
try {
|
||||||
const Duration(seconds: 1),
|
await dietsRepository.addToFavorite(id);
|
||||||
() async {
|
} catch (e) {
|
||||||
try {
|
log(e.toString());
|
||||||
await dietsRepository.addToFavorite(id);
|
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
|
||||||
} catch (e) {
|
if (dietIndex != null) {
|
||||||
log(e.toString());
|
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex));
|
||||||
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
|
|
||||||
if (dietIndex != null) {
|
|
||||||
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex));
|
|
||||||
}
|
|
||||||
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
|
||||||
}
|
}
|
||||||
},
|
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||||
);
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> removeFromFavorite(int id, int? dietIndex) async {
|
Future<void> removeFromFavorite(int id, int? dietIndex) async {
|
||||||
@@ -141,30 +130,24 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
|||||||
|
|
||||||
final currentDiet = (state as DietStateLoaded).diet;
|
final currentDiet = (state as DietStateLoaded).diet;
|
||||||
|
|
||||||
final updatedDiet = currentDiet.copyWith(
|
final updatedDiet = currentDiet.copyWith(isFavorite: false);
|
||||||
isFavorite: false,
|
|
||||||
);
|
|
||||||
if (dietIndex != null) {
|
if (dietIndex != null) {
|
||||||
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndex));
|
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndex));
|
||||||
}
|
}
|
||||||
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||||
|
|
||||||
EasyDebounce.debounce(
|
EasyDebounce.debounce('add_or_remove_diet_to_favorites', const Duration(seconds: 1), () async {
|
||||||
'add_or_remove_diet_to_favorites',
|
try {
|
||||||
const Duration(seconds: 1),
|
await dietsRepository.removeFromFavorite(id);
|
||||||
() async {
|
} catch (e) {
|
||||||
try {
|
log(e.toString());
|
||||||
await dietsRepository.removeFromFavorite(id);
|
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
|
||||||
} catch (e) {
|
if (dietIndex != null) {
|
||||||
log(e.toString());
|
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex));
|
||||||
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
|
|
||||||
if (dietIndex != null) {
|
|
||||||
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex));
|
|
||||||
}
|
|
||||||
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
|
||||||
}
|
}
|
||||||
},
|
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||||
);
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> startDiet(DateTime date) async {
|
Future<bool> startDiet(DateTime date) async {
|
||||||
@@ -199,13 +182,13 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
|||||||
void clearStartedDietsState() {
|
void clearStartedDietsState() {
|
||||||
if (state is! DietStateLoaded) return;
|
if (state is! DietStateLoaded) return;
|
||||||
final diet = (state as DietStateLoaded).diet;
|
final diet = (state as DietStateLoaded).diet;
|
||||||
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: diet));
|
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: diet));
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitCurrentStartedDietsState() {
|
void emitCurrentStartedDietsState() {
|
||||||
if (state is! DietStateLoaded) return;
|
if (state is! DietStateLoaded) return;
|
||||||
final diet = (state as DietStateLoaded).diet;
|
final diet = (state as DietStateLoaded).diet;
|
||||||
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: diet, isStarted: true));
|
emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: diet, isStarted: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Diet?> getDietBySlug(String slug) async {
|
Future<Diet?> getDietBySlug(String slug) async {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
import 'package:eatvio_app/core/enums/product_type.dart';
|
import 'package:eatvio_app/core/enums/product_type.dart';
|
||||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||||
@@ -35,11 +35,12 @@ import 'package:flutter_svg/svg.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
class AboutDietScreen extends StatefulWidget {
|
class AboutDietScreen extends StatefulWidget {
|
||||||
final String slug;
|
final String? slug;
|
||||||
|
final int? id;
|
||||||
final int? index;
|
final int? index;
|
||||||
final bool navigateToComments;
|
final bool navigateToComments;
|
||||||
|
|
||||||
const AboutDietScreen({super.key, required this.index, required this.navigateToComments, required this.slug});
|
const AboutDietScreen({super.key, required this.index, required this.navigateToComments, required this.slug, required this.id});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AboutDietScreen> createState() => _AboutDietScreenState();
|
State<AboutDietScreen> createState() => _AboutDietScreenState();
|
||||||
@@ -79,7 +80,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
|||||||
final s = S.of(context);
|
final s = S.of(context);
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => dietsCubit..initDietPage(widget.slug),
|
create: (context) => dietsCubit..initDietPage(slug: widget.slug, id: widget.id),
|
||||||
child: BlocProvider<CommentsCubit>(
|
child: BlocProvider<CommentsCubit>(
|
||||||
create: (BuildContext context) => commentsCubit,
|
create: (BuildContext context) => commentsCubit,
|
||||||
child: BlocConsumer<CommentsCubit, CommentsState>(
|
child: BlocConsumer<CommentsCubit, CommentsState>(
|
||||||
@@ -283,7 +284,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
|||||||
replyId = null;
|
replyId = null;
|
||||||
});
|
});
|
||||||
Future.delayed(const Duration(milliseconds: 500), () {
|
Future.delayed(const Duration(milliseconds: 500), () {
|
||||||
dietsCubit.getDiet(dietState.diet.slug, index: widget.index);
|
dietsCubit.getDiet(slug: dietState.diet.slug, index: widget.index);
|
||||||
});
|
});
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
}
|
}
|
||||||
@@ -353,7 +354,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
|||||||
Stack(
|
Stack(
|
||||||
children: [
|
children: [
|
||||||
CachedNetworkImage(
|
CachedNetworkImage(
|
||||||
imageUrl: '$baseUrl/storage/${dietState.diet.image}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${dietState.diet.image}',
|
||||||
height: 300,
|
height: 300,
|
||||||
width: MediaQuery.sizeOf(context).width,
|
width: MediaQuery.sizeOf(context).width,
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
@@ -526,7 +527,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: DataErrorWidget(
|
body: DataErrorWidget(
|
||||||
onReload: () => context.read<AboutDietCubit>().getDiet(widget.slug, index: widget.index),
|
onReload: () => context.read<AboutDietCubit>().getDiet(slug: widget.slug, id: widget.id, index: widget.index),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
||||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||||
@@ -37,45 +38,25 @@ class AuthorCard extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: NetworkImage(baseUrl + author.authorProfileIcon),
|
image: NetworkImage(
|
||||||
|
author.authorProfileIcon.contains('https') ? author.authorProfileIcon : sl<AppConfig>().baseUrl + author.authorProfileIcon,
|
||||||
|
),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(author.authorName, style: TextStyles.textLSemibold.copyWith(color: appTheme.black)),
|
||||||
author.authorName,
|
title: Text(title, style: titleStyle ?? TextStyles.textSSemibold.copyWith(color: appTheme.gray)),
|
||||||
style: TextStyles.textLSemibold.copyWith(
|
|
||||||
color: appTheme.black,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
title,
|
|
||||||
style: titleStyle ?? TextStyles.textSSemibold.copyWith(
|
|
||||||
color: appTheme.gray,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text('Консультант', style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||||
'Консультант',
|
|
||||||
style: TextStyles.textMMedium.copyWith(
|
|
||||||
color: appTheme.black,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
if (author.authorPlaceInRating != null)
|
if (author.authorPlaceInRating != null)
|
||||||
InfoBouble(
|
InfoBouble(
|
||||||
radius: 12,
|
radius: 12,
|
||||||
backgroundColor: appTheme.whiteA700,
|
backgroundColor: appTheme.whiteA700,
|
||||||
children: [
|
children: [Text('${author.authorPlaceInRating}-й в рейтинге', style: TextStyles.textMMediumAuto.copyWith(color: appTheme.blueA400))],
|
||||||
Text(
|
|
||||||
'${author.authorPlaceInRating}-й в рейтинге',
|
|
||||||
style: TextStyles.textMMediumAuto.copyWith(
|
|
||||||
color: appTheme.blueA400,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -88,18 +69,8 @@ class AuthorCard extends StatelessWidget {
|
|||||||
child: Container(
|
child: Container(
|
||||||
width: 28,
|
width: 28,
|
||||||
height: 28,
|
height: 28,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(color: appTheme.whiteA700, borderRadius: BorderRadius.circular(8)),
|
||||||
color: appTheme.whiteA700,
|
child: Center(child: SvgPicture.asset('assets/icons/arrow.svg', width: 12, height: 12, fit: BoxFit.none)),
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
'assets/icons/arrow.svg',
|
|
||||||
width: 12,
|
|
||||||
height: 12,
|
|
||||||
fit: BoxFit.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||||
import 'package:eatvio_app/features/complaining/presentation/complaining_bottom_sheet.dart';
|
import 'package:eatvio_app/features/complaining/presentation/complaining_bottom_sheet.dart';
|
||||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||||
@@ -35,7 +36,7 @@ class MoreOptions extends StatelessWidget {
|
|||||||
onTap: disableActions == true
|
onTap: disableActions == true
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
Clipboard.setData(ClipboardData(text: '$baseUrl/ru/$path'));
|
Clipboard.setData(ClipboardData(text: '${sl<AppConfig>().baseUrl}/ru/$path'));
|
||||||
showInfoToast(s.link_was_copied);
|
showInfoToast(s.link_was_copied);
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -62,7 +63,7 @@ class MoreOptions extends StatelessWidget {
|
|||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
SharePlus.instance.share(
|
SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse('$baseUrl/ru/$path',),
|
uri: Uri.parse('${sl<AppConfig>().baseUrl}/ru/$path',),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:dismissible_page/dismissible_page.dart';
|
import 'package:dismissible_page/dismissible_page.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||||
@@ -64,7 +65,7 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
|
|||||||
authorName: state.feedBlogPostList[widget.index].author.authorName,
|
authorName: state.feedBlogPostList[widget.index].author.authorName,
|
||||||
authorProfileIcon: state.feedBlogPostList[widget.index].author.authorProfileIcon.contains('https')
|
authorProfileIcon: state.feedBlogPostList[widget.index].author.authorProfileIcon.contains('https')
|
||||||
? state.feedBlogPostList[widget.index].author.authorProfileIcon
|
? state.feedBlogPostList[widget.index].author.authorProfileIcon
|
||||||
: baseUrl + state.feedBlogPostList[widget.index].author.authorProfileIcon,
|
: sl<AppConfig>().baseUrl + state.feedBlogPostList[widget.index].author.authorProfileIcon,
|
||||||
authorIsMe: state.feedBlogPostList[widget.index].author.authorIsMe,
|
authorIsMe: state.feedBlogPostList[widget.index].author.authorIsMe,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -75,7 +76,7 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
|
|||||||
foregroundImage: NetworkImage(
|
foregroundImage: NetworkImage(
|
||||||
state.feedBlogPostList[widget.index].author.authorProfileIcon.contains('https')
|
state.feedBlogPostList[widget.index].author.authorProfileIcon.contains('https')
|
||||||
? state.feedBlogPostList[widget.index].author.authorProfileIcon
|
? state.feedBlogPostList[widget.index].author.authorProfileIcon
|
||||||
: baseUrl + state.feedBlogPostList[widget.index].author.authorProfileIcon,
|
: sl<AppConfig>().baseUrl + state.feedBlogPostList[widget.index].author.authorProfileIcon,
|
||||||
),
|
),
|
||||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||||
),
|
),
|
||||||
@@ -157,15 +158,15 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushTransparentRoute(
|
context.pushTransparentRoute(
|
||||||
rootNavigator: true,
|
rootNavigator: true,
|
||||||
PhotoViewScreen(imageUrls: ['$baseUrl/storage/${state.feedBlogPostList[widget.index].image}'], index: 0),
|
PhotoViewScreen(imageUrls: ['${sl<AppConfig>().baseUrl}/storage/${state.feedBlogPostList[widget.index].image}'], index: 0),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Hero(
|
child: Hero(
|
||||||
tag: '$baseUrl/storage/${state.feedBlogPostList[widget.index].image}',
|
tag: '${sl<AppConfig>().baseUrl}/storage/${state.feedBlogPostList[widget.index].image}',
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
width: MediaQuery.of(context).size.width,
|
width: MediaQuery.of(context).size.width,
|
||||||
imageUrl: '$baseUrl/storage/${state.feedBlogPostList[widget.index].image}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${state.feedBlogPostList[widget.index].image}',
|
||||||
errorWidget: (context, str, object) => const SizedBox.shrink(),
|
errorWidget: (context, str, object) => const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -219,7 +220,7 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
|
|||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
SharePlus.instance.share(
|
SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse('$baseUrl/ru/blog_post/${state.feedBlogPostList[widget.index].id}'),
|
uri: Uri.parse('${sl<AppConfig>().baseUrl}/ru/blog_post/${state.feedBlogPostList[widget.index].id}'),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/comments/presentation/comments_actions_bottom_sheet.dart';
|
import 'package:eatvio_app/core/comments/presentation/comments_actions_bottom_sheet.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.dart';
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||||
@@ -99,13 +99,13 @@ class _CommentsWidgetState extends State<CommentsWidget> {
|
|||||||
extra: Author(
|
extra: Author(
|
||||||
authorSlug: comment.authorSlug,
|
authorSlug: comment.authorSlug,
|
||||||
authorName: comment.authorName,
|
authorName: comment.authorName,
|
||||||
authorProfileIcon: comment.authorProfileIcon.contains('https') ? comment.authorProfileIcon : baseUrl + comment.authorProfileIcon,
|
authorProfileIcon: comment.authorProfileIcon.contains('https') ? comment.authorProfileIcon : sl<AppConfig>().baseUrl + comment.authorProfileIcon,
|
||||||
authorIsMe: isMe,
|
authorIsMe: isMe,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: CircleAvatar(
|
child: CircleAvatar(
|
||||||
foregroundImage: NetworkImage(comment.authorProfileIcon.contains('https') ? comment.authorProfileIcon : baseUrl + comment.authorProfileIcon),
|
foregroundImage: NetworkImage(comment.authorProfileIcon.contains('https') ? comment.authorProfileIcon : sl<AppConfig>().baseUrl + comment.authorProfileIcon),
|
||||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||||
radius: radius,
|
radius: radius,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.dart';
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
||||||
@@ -14,10 +14,7 @@ import 'package:go_router/go_router.dart';
|
|||||||
class ConsultantWidget extends StatelessWidget {
|
class ConsultantWidget extends StatelessWidget {
|
||||||
final FeedConsultantModel consultant;
|
final FeedConsultantModel consultant;
|
||||||
|
|
||||||
const ConsultantWidget({
|
const ConsultantWidget({super.key, required this.consultant});
|
||||||
super.key,
|
|
||||||
required this.consultant,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -36,10 +33,7 @@ class ConsultantWidget extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
child: Ink(
|
child: Ink(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: const Color(0xFFF6F6F6)),
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
color: const Color(0xFFF6F6F6),
|
|
||||||
),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -51,46 +45,32 @@ class ConsultantWidget extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Ink(
|
Ink(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
|
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
child: Text(
|
child: Text(
|
||||||
'${consultant.ratingPlace}',
|
'${consultant.ratingPlace}',
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: 20, color: appTheme.blueA400, fontWeight: FontWeight.w600),
|
||||||
fontSize: 20,
|
|
||||||
color: appTheme.blueA400,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
CircleAvatar(
|
if (consultant.photo.contains('https'))
|
||||||
foregroundImage: NetworkImage(baseUrl + consultant.photo),
|
CircleAvatar(foregroundImage: NetworkImage(consultant.photo), backgroundImage: const AssetImage('assets/images/no_avatar.png'))
|
||||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
else
|
||||||
),
|
CircleAvatar(
|
||||||
|
foregroundImage: NetworkImage(sl<AppConfig>().baseUrl + consultant.photo),
|
||||||
|
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||||
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
consultant.name,
|
consultant.name,
|
||||||
style: const TextStyle(
|
style: const TextStyle(height: 1, fontWeight: FontWeight.w500, fontSize: 15, color: Color(0xFF323F4B)),
|
||||||
height: 1,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
fontSize: 15,
|
|
||||||
color: Color(0xFF323F4B),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
'Рейтинг: ${consultant.totalScores}',
|
'Рейтинг: ${consultant.totalScores}',
|
||||||
style: TextStyle(
|
style: TextStyle(color: appTheme.blueA400, height: 1, fontWeight: FontWeight.w500, fontSize: 12),
|
||||||
color: appTheme.blueA400,
|
|
||||||
height: 1,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -98,21 +78,13 @@ class ConsultantWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Ink(
|
Ink(
|
||||||
padding: const EdgeInsets.all(6),
|
padding: const EdgeInsets.all(6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(borderRadius: BorderRadius.circular(4), color: Colors.white),
|
||||||
borderRadius: BorderRadius.circular(4),
|
child: SvgPicture.asset('assets/icons/go_to_arrow.svg'),
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
'assets/icons/go_to_arrow.svg',
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(consultant.description, maxLines: 2),
|
||||||
consultant.description,
|
|
||||||
maxLines: 2,
|
|
||||||
),
|
|
||||||
if (consultant.badges.isNotEmpty) const SizedBox(height: 8),
|
if (consultant.badges.isNotEmpty) const SizedBox(height: 8),
|
||||||
_badges(consultant.badges, context),
|
_badges(consultant.badges, context),
|
||||||
],
|
],
|
||||||
@@ -128,16 +100,8 @@ class ConsultantWidget extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
for (int i = 0; i < badges.length; i++) ...[
|
for (int i = 0; i < badges.length; i++) ...[
|
||||||
badges[i].image.contains('svg')
|
badges[i].image.contains('svg')
|
||||||
? SvgPicture.network(
|
? SvgPicture.network('${sl<AppConfig>().baseUrl}/storage/${badges[i].image}', width: 28, height: 28)
|
||||||
'$baseUrl/storage/${badges[i].image}',
|
: CachedNetworkImage(imageUrl: '${sl<AppConfig>().baseUrl}/storage/${badges[i].image}', width: 28, height: 28),
|
||||||
width: 28,
|
|
||||||
height: 28,
|
|
||||||
)
|
|
||||||
: CachedNetworkImage(
|
|
||||||
imageUrl: '$baseUrl/storage/${badges[i].image}',
|
|
||||||
width: 28,
|
|
||||||
height: 28,
|
|
||||||
),
|
|
||||||
i < badges.length - 1 ? const SizedBox(width: 8) : const SizedBox.shrink(),
|
i < badges.length - 1 ? const SizedBox(width: 8) : const SizedBox.shrink(),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
import 'package:eatvio_app/core/enums/product_type.dart';
|
import 'package:eatvio_app/core/enums/product_type.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
||||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||||
import 'package:eatvio_app/core/widgets/info_row.dart';
|
import 'package:eatvio_app/core/widgets/info_row.dart';
|
||||||
@@ -56,7 +57,7 @@ class _DietsWidgetState extends State<DietsWidget> {
|
|||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: '$baseUrl/storage/${widget.diet.image}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${widget.diet.image}',
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
width: MediaQuery.of(context).size.width,
|
width: MediaQuery.of(context).size.width,
|
||||||
),
|
),
|
||||||
@@ -189,7 +190,7 @@ class _DietsWidgetState extends State<DietsWidget> {
|
|||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
final result = await SharePlus.instance.share(
|
final result = await SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse('$baseUrl/ru/diet/${widget.diet.id}'),
|
uri: Uri.parse('${sl<AppConfig>().baseUrl}/ru/diet/${widget.diet.id}'),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
import 'package:eatvio_app/core/enums/product_type.dart';
|
import 'package:eatvio_app/core/enums/product_type.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
||||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||||
import 'package:eatvio_app/core/widgets/info_row.dart';
|
import 'package:eatvio_app/core/widgets/info_row.dart';
|
||||||
@@ -61,7 +62,7 @@ class _PlanWidgetState extends State<PlanWidget> {
|
|||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: '$baseUrl/storage/${widget.plan.image}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${widget.plan.image}',
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
width: MediaQuery.of(context).size.width,
|
width: MediaQuery.of(context).size.width,
|
||||||
height: 426,
|
height: 426,
|
||||||
@@ -187,7 +188,7 @@ class _PlanWidgetState extends State<PlanWidget> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: NetworkImage(baseUrl + widget.plan.author.authorProfileIcon),
|
image: NetworkImage(sl<AppConfig>().baseUrl + widget.plan.author.authorProfileIcon),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -263,7 +264,7 @@ class _PlanWidgetState extends State<PlanWidget> {
|
|||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
final result = await SharePlus.instance.share(
|
final result = await SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse('$baseUrl/ru/diet/${widget.plan.id}'),
|
uri: Uri.parse('${sl<AppConfig>().baseUrl}/ru/diet/${widget.plan.id}'),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
// ignore_for_file: dead_code
|
// ignore_for_file: dead_code
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.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/custom_text_style.dart';
|
||||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||||
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
||||||
@@ -75,7 +76,7 @@ class _RecipesWidgetState extends State<RecipesWidget> {
|
|||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: '$baseUrl/storage/${widget.recipe.image}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${widget.recipe.image}',
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
width: MediaQuery.of(context).size.width,
|
width: MediaQuery.of(context).size.width,
|
||||||
),
|
),
|
||||||
@@ -231,7 +232,7 @@ class _RecipesWidgetState extends State<RecipesWidget> {
|
|||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
SharePlus.instance.share(
|
SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse('$baseUrl/ru/recipe/${widget.recipe.id}'),
|
uri: Uri.parse('${sl<AppConfig>().baseUrl}/ru/recipe/${widget.recipe.id}'),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ class _GlossaryScreenState extends State<GlossaryScreen> {
|
|||||||
|
|
||||||
_controller = WebViewController()
|
_controller = WebViewController()
|
||||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||||
..loadRequest(Uri.parse('$baseUrl/product_nutritional_value'));
|
..loadRequest(Uri.parse('${sl<AppConfig>().baseUrl}/product_nutritional_value'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/const.dart';
|
||||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||||
import 'package:eatvio_app/core/token_storage.dart';
|
import 'package:eatvio_app/core/token_storage.dart';
|
||||||
@@ -117,7 +118,7 @@ class MenuScreen extends StatelessWidget {
|
|||||||
CupertinoDialogAction(
|
CupertinoDialogAction(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
try {
|
try {
|
||||||
await sl<Dio>().post('$baseUrl/api/profile/logout');
|
await sl<Dio>().post('${sl<AppConfig>().baseUrl}/api/profile/logout');
|
||||||
} finally {
|
} finally {
|
||||||
await TokenStorage.removeTokenInStorage();
|
await TokenStorage.removeTokenInStorage();
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||||
import 'package:eatvio_app/features/menu/presentation/blocked_user_cubit/blocked_users_cubit.dart';
|
import 'package:eatvio_app/features/menu/presentation/blocked_user_cubit/blocked_users_cubit.dart';
|
||||||
import 'package:eatvio_app/features/profile/models/profile_model.dart';
|
import 'package:eatvio_app/features/profile/models/profile_model.dart';
|
||||||
@@ -33,7 +34,7 @@ class _BlockedUserWidgetState extends State<BlockedUserWidget> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
foregroundImage: NetworkImage(baseUrl + widget.profile.profilePhotoUrl),
|
foregroundImage: NetworkImage(sl<AppConfig>().baseUrl + widget.profile.profilePhotoUrl),
|
||||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||||
radius: 28,
|
radius: 28,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/app_router.dart';
|
import 'package:eatvio_app/core/app_router.dart';
|
||||||
import 'package:eatvio_app/core/const.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/custom_text_style.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:eatvio_app/core/enums/product_type.dart';
|
import 'package:eatvio_app/core/enums/product_type.dart';
|
||||||
@@ -56,7 +57,7 @@ class _MyDietWidgetState extends State<MyDietWidget> {
|
|||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: '$baseUrl/storage/${widget.diet.image}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${widget.diet.image}',
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
width: MediaQuery.of(context).size.width,
|
width: MediaQuery.of(context).size.width,
|
||||||
),
|
),
|
||||||
@@ -153,7 +154,7 @@ class _MyDietWidgetState extends State<MyDietWidget> {
|
|||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
await SharePlus.instance.share(
|
await SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse('$baseUrl/ru/diet/${widget.diet.id}'),
|
uri: Uri.parse('${sl<AppConfig>().baseUrl}/ru/diet/${widget.diet.id}'),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.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/custom_text_style.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:eatvio_app/core/enums/product_type.dart';
|
import 'package:eatvio_app/core/enums/product_type.dart';
|
||||||
@@ -42,7 +43,7 @@ class _MyPlanWidgetState extends State<MyPlanWidget> {
|
|||||||
onTap: () => GoRouter.of(context).pushNamed('aboutPlanScreen', extra: {'slug': widget.plan.slug, 'navigateToComments': false}),
|
onTap: () => GoRouter.of(context).pushNamed('aboutPlanScreen', extra: {'slug': widget.plan.slug, 'navigateToComments': false}),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
||||||
child: CachedNetworkImage(imageUrl: '$baseUrl/storage/${widget.plan.image}', fit: BoxFit.fitWidth, width: MediaQuery.of(context).size.width),
|
child: CachedNetworkImage(imageUrl: '${sl<AppConfig>().baseUrl}/storage/${widget.plan.image}', fit: BoxFit.fitWidth, width: MediaQuery.of(context).size.width),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
@@ -157,7 +158,7 @@ class _MyPlanWidgetState extends State<MyPlanWidget> {
|
|||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
await SharePlus.instance.share(
|
await SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse('$baseUrl/ru/plan/${widget.plan.id}'),
|
uri: Uri.parse('${sl<AppConfig>().baseUrl}/ru/plan/${widget.plan.id}'),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.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/custom_text_style.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||||
@@ -31,7 +32,7 @@ class PlanInfo extends StatelessWidget {
|
|||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: '$baseUrl/storage/$imagePath',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/$imagePath',
|
||||||
height: 220,
|
height: 220,
|
||||||
width: MediaQuery.sizeOf(context).width,
|
width: MediaQuery.sizeOf(context).width,
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
import 'package:eatvio_app/core/enums/product_type.dart';
|
import 'package:eatvio_app/core/enums/product_type.dart';
|
||||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||||
@@ -401,7 +401,7 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
|||||||
Stack(
|
Stack(
|
||||||
children: [
|
children: [
|
||||||
CachedNetworkImage(
|
CachedNetworkImage(
|
||||||
imageUrl: '$baseUrl/storage/${state.planModel?.image}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${state.planModel?.image}',
|
||||||
height: 300,
|
height: 300,
|
||||||
width: MediaQuery.sizeOf(context).width,
|
width: MediaQuery.sizeOf(context).width,
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:dismissible_page/dismissible_page.dart';
|
import 'package:dismissible_page/dismissible_page.dart';
|
||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/app_router.dart';
|
import 'package:eatvio_app/core/app_router.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/const.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
@@ -655,7 +656,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
boxShadow: [BoxShadow(color: Colors.black.withAlpha((255 * 0.2).toInt()), blurRadius: 32)],
|
boxShadow: [BoxShadow(color: Colors.black.withAlpha((255 * 0.2).toInt()), blurRadius: 32)],
|
||||||
),
|
),
|
||||||
child: SvgPicture.network('$baseUrl/storage/${state.profile.badges[i].image}', width: 40, height: 40),
|
child: SvgPicture.network('${sl<AppConfig>().baseUrl}/storage/${state.profile.badges[i].image}', width: 40, height: 40),
|
||||||
)
|
)
|
||||||
: Tooltip(
|
: Tooltip(
|
||||||
message: state.profile.badges[i].description,
|
message: state.profile.badges[i].description,
|
||||||
@@ -667,7 +668,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
boxShadow: [BoxShadow(color: Colors.black.withAlpha((255 * 0.2).toInt()), blurRadius: 32)],
|
boxShadow: [BoxShadow(color: Colors.black.withAlpha((255 * 0.2).toInt()), blurRadius: 32)],
|
||||||
),
|
),
|
||||||
child: CachedNetworkImage(imageUrl: '$baseUrl/storage/${state.profile.badges[i].image}', width: 40, height: 40),
|
child: CachedNetworkImage(imageUrl: '${sl<AppConfig>().baseUrl}/storage/${state.profile.badges[i].image}', width: 40, height: 40),
|
||||||
),
|
),
|
||||||
i < state.profile.badges.length - 1 ? const SizedBox(width: 8) : const SizedBox.shrink(),
|
i < state.profile.badges.length - 1 ? const SizedBox(width: 8) : const SizedBox.shrink(),
|
||||||
],
|
],
|
||||||
@@ -803,7 +804,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
icon: 'assets/icons/eye.svg',
|
icon: 'assets/icons/eye.svg',
|
||||||
text: 'Посмотреть',
|
text: 'Посмотреть',
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
context.pushTransparentRoute(rootNavigator: true, PhotoViewScreen(imageUrls: [baseUrl + state.profile.profilePhotoUrl], index: 0));
|
context.pushTransparentRoute(rootNavigator: true, PhotoViewScreen(imageUrls: [sl<AppConfig>().baseUrl + state.profile.profilePhotoUrl], index: 0));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (widget.author == null || widget.author!.authorIsMe) ...[
|
if (widget.author == null || widget.author!.authorIsMe) ...[
|
||||||
@@ -885,7 +886,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
child: CircleAvatar(
|
child: CircleAvatar(
|
||||||
radius: 32,
|
radius: 32,
|
||||||
foregroundImage: NetworkImage(
|
foregroundImage: NetworkImage(
|
||||||
state.profile.profilePhotoUrl.contains('https') ? state.profile.profilePhotoUrl : baseUrl + state.profile.profilePhotoUrl,
|
state.profile.profilePhotoUrl.contains('https') ? state.profile.profilePhotoUrl : sl<AppConfig>().baseUrl + state.profile.profilePhotoUrl,
|
||||||
),
|
),
|
||||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||||
),
|
),
|
||||||
@@ -960,7 +961,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
SharePlus.instance.share(
|
SharePlus.instance.share(
|
||||||
ShareParams(uri: Uri.parse('$baseUrl/ru/profile/${state.profile.slug}'), sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size),
|
ShareParams(uri: Uri.parse('${sl<AppConfig>().baseUrl}/ru/profile/${state.profile.slug}'), sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:dismissible_page/dismissible_page.dart';
|
import 'package:dismissible_page/dismissible_page.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||||
import 'package:eatvio_app/core/widgets/feed_icon_button.dart';
|
import 'package:eatvio_app/core/widgets/feed_icon_button.dart';
|
||||||
@@ -69,7 +70,7 @@ class _ProfileBlogPostWidgetState extends State<ProfileBlogPostWidget> {
|
|||||||
foregroundImage: NetworkImage(
|
foregroundImage: NetworkImage(
|
||||||
state.blogPosts[widget.index].author.authorProfileIcon.contains('https')
|
state.blogPosts[widget.index].author.authorProfileIcon.contains('https')
|
||||||
? state.blogPosts[widget.index].author.authorProfileIcon
|
? state.blogPosts[widget.index].author.authorProfileIcon
|
||||||
: baseUrl + state.blogPosts[widget.index].author.authorProfileIcon,
|
: sl<AppConfig>().baseUrl + state.blogPosts[widget.index].author.authorProfileIcon,
|
||||||
),
|
),
|
||||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||||
),
|
),
|
||||||
@@ -157,17 +158,17 @@ class _ProfileBlogPostWidgetState extends State<ProfileBlogPostWidget> {
|
|||||||
context.pushTransparentRoute(
|
context.pushTransparentRoute(
|
||||||
rootNavigator: true,
|
rootNavigator: true,
|
||||||
PhotoViewScreen(
|
PhotoViewScreen(
|
||||||
imageUrls: ['$baseUrl/storage/${state.blogPosts[widget.index].image}'],
|
imageUrls: ['${sl<AppConfig>().baseUrl}/storage/${state.blogPosts[widget.index].image}'],
|
||||||
index: 0,
|
index: 0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Hero(
|
child: Hero(
|
||||||
tag: '$baseUrl/storage/${state.blogPosts[widget.index].image}',
|
tag: '${sl<AppConfig>().baseUrl}/storage/${state.blogPosts[widget.index].image}',
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
width: MediaQuery.of(context).size.width,
|
width: MediaQuery.of(context).size.width,
|
||||||
imageUrl: '$baseUrl/storage/${state.blogPosts[widget.index].image}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${state.blogPosts[widget.index].image}',
|
||||||
errorWidget: (context, str, object) => const SizedBox.shrink(),
|
errorWidget: (context, str, object) => const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -226,7 +227,7 @@ class _ProfileBlogPostWidgetState extends State<ProfileBlogPostWidget> {
|
|||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
SharePlus.instance.share(
|
SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse('$baseUrl/ru/blog_post/${state.blogPosts[widget.index].id}'),
|
uri: Uri.parse('${sl<AppConfig>().baseUrl}/ru/blog_post/${state.blogPosts[widget.index].id}'),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||||
import 'package:eatvio_app/features/profile/models/sub_model.dart';
|
import 'package:eatvio_app/features/profile/models/sub_model.dart';
|
||||||
import 'package:eatvio_app/features/profile/presentation/widgets/sub_action_button_widget.dart';
|
import 'package:eatvio_app/features/profile/presentation/widgets/sub_action_button_widget.dart';
|
||||||
@@ -36,7 +37,7 @@ class _SubWidgetState extends State<SubWidget> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
foregroundImage: NetworkImage(baseUrl + widget.subModel.profilePhotoUrl),
|
foregroundImage: NetworkImage(sl<AppConfig>().baseUrl + widget.subModel.profilePhotoUrl),
|
||||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||||
radius: 28,
|
radius: 28,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import 'dart:developer';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||||
import 'package:eatvio_app/core/enums/product_type.dart';
|
import 'package:eatvio_app/core/enums/product_type.dart';
|
||||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||||
@@ -247,7 +247,7 @@ class _AboutRecipeScreenState extends State<AboutRecipeScreen> {
|
|||||||
Stack(
|
Stack(
|
||||||
children: [
|
children: [
|
||||||
CachedNetworkImage(
|
CachedNetworkImage(
|
||||||
imageUrl: '$baseUrl/storage/${recipeState.recipe.image}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${recipeState.recipe.image}',
|
||||||
height: 300,
|
height: 300,
|
||||||
width: MediaQuery.sizeOf(context).width,
|
width: MediaQuery.sizeOf(context).width,
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.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/custom_text_style.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
@@ -71,7 +71,7 @@ class _MyRecipeWidgetState extends State<MyRecipeWidget> {
|
|||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: '$baseUrl/storage/${widget.recipe.image}',
|
imageUrl: '${sl<AppConfig>().baseUrl}/storage/${widget.recipe.image}',
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
width: MediaQuery.of(context).size.width,
|
width: MediaQuery.of(context).size.width,
|
||||||
),
|
),
|
||||||
@@ -162,7 +162,7 @@ class _MyRecipeWidgetState extends State<MyRecipeWidget> {
|
|||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
await SharePlus.instance.share(
|
await SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
uri: Uri.parse('$baseUrl/ru/recipe/${widget.recipe.slug}'),
|
uri: Uri.parse('${sl<AppConfig>().baseUrl}/ru/recipe/${widget.recipe.slug}'),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.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/custom_text_style.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||||
@@ -44,7 +45,7 @@ class StepsWidget extends StatelessWidget {
|
|||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
child: Image.network(
|
child: Image.network(
|
||||||
'$baseUrl/storage/${recipe.steps![index].image}',
|
'${sl<AppConfig>().baseUrl}/storage/${recipe.steps![index].image}',
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||||
import 'package:eatvio_app/features/registration/services/registration_analytics_service.dart';
|
import 'package:eatvio_app/features/registration/services/registration_analytics_service.dart';
|
||||||
@@ -89,7 +90,7 @@ class _VerifyScreenState extends State<VerifyScreen> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
..loadRequest(Uri.parse('$baseUrl/login_with_pass_key?id=${widget.passKey}'));
|
..loadRequest(Uri.parse('${sl<AppConfig>().baseUrl}/login_with_pass_key?id=${widget.passKey}'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.dart';
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/features/auth/presentation/bloc/auth_cubit/auth_cubit.dart';
|
import 'package:eatvio_app/features/auth/presentation/bloc/auth_cubit/auth_cubit.dart';
|
||||||
import 'package:eatvio_app/features/registration/services/registration_analytics_service.dart';
|
import 'package:eatvio_app/features/registration/services/registration_analytics_service.dart';
|
||||||
@@ -54,7 +54,7 @@ class _WebViewRegistrationScreenState extends State<WebViewRegistrationScreen> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
..loadRequest(Uri.parse('$baseUrl/registration/step1'));
|
..loadRequest(Uri.parse('${sl<AppConfig>().baseUrl}/registration/step1'));
|
||||||
|
|
||||||
_injectJavaScript();
|
_injectJavaScript();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/const.dart';
|
import 'package:eatvio_app/core/const.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||||
import 'package:eatvio_app/generated/l10n.dart';
|
import 'package:eatvio_app/generated/l10n.dart';
|
||||||
@@ -71,7 +73,7 @@ class SupportScreen extends StatelessWidget {
|
|||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
if (!hidePlans) ...[
|
if (!hidePlans) ...[
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async => await launchUrl(Uri.parse('$baseUrl/docs/public_offer.pdf')),
|
onTap: () async => await launchUrl(Uri.parse('${sl<AppConfig>().baseUrl}/docs/public_offer.pdf')),
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
child: const Padding(
|
child: const Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||||
@@ -81,7 +83,7 @@ class SupportScreen extends StatelessWidget {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
],
|
],
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async => await launchUrl(Uri.parse('$baseUrl/docs/privacy.pdf')),
|
onTap: () async => await launchUrl(Uri.parse('${sl<AppConfig>().baseUrl}/docs/privacy.pdf')),
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
child: const Padding(
|
child: const Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||||
@@ -90,7 +92,7 @@ class SupportScreen extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async => await launchUrl(Uri.parse('$baseUrl/company-details')),
|
onTap: () async => await launchUrl(Uri.parse('${sl<AppConfig>().baseUrl}/company-details')),
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
child: const Padding(
|
child: const Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:eatvio_app/app_keys.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:eatvio_app/core/token_storage.dart';
|
import 'package:eatvio_app/core/token_storage.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -79,6 +80,7 @@ class _WelcomeScreenState extends State<WelcomeScreen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
InkWell(
|
InkWell(
|
||||||
|
key: AppKeys.welcomeScreenButton,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final sharedPreferences = await SharedPreferences.getInstance();
|
final sharedPreferences = await SharedPreferences.getInstance();
|
||||||
await sharedPreferences.setBool('welcomeScreenWasShowed', true);
|
await sharedPreferences.setBool('welcomeScreenWasShowed', true);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:eatvio_app/core/app_config.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/app_initializer.dart';
|
import 'package:eatvio_app/core/app_initializer.dart';
|
||||||
import 'package:eatvio_app/core/app_router.dart';
|
import 'package:eatvio_app/core/app_router.dart';
|
||||||
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
@@ -8,7 +9,7 @@ import 'package:flutter_portal/flutter_portal.dart';
|
|||||||
import 'package:keyboard_dismisser/keyboard_dismisser.dart';
|
import 'package:keyboard_dismisser/keyboard_dismisser.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
await AppInitializer.initialize();
|
await AppInitializer.initialize(buildType: AppBuildType.prod);
|
||||||
await AppInitializer.runAppWithSentry(() => runApp(const MyApp()));
|
await AppInitializer.runAppWithSentry(() => runApp(const MyApp()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,15 +19,15 @@ class MyApp extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: AppConfig.globalBlocProviders,
|
providers: sl<AppConfig>().globalBlocProviders,
|
||||||
child: Portal(
|
child: Portal(
|
||||||
child: KeyboardDismisser(
|
child: KeyboardDismisser(
|
||||||
child: MaterialApp.router(
|
child: MaterialApp.router(
|
||||||
theme: ThemeHelper().themeData(),
|
theme: ThemeHelper().themeData(),
|
||||||
routerConfig: AppRouter.appRouter,
|
routerConfig: AppRouter.appRouter,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
localizationsDelegates: AppConfig.localizationDelegates,
|
localizationsDelegates: sl<AppConfig>().localizationDelegates,
|
||||||
supportedLocales: AppConfig.supportedLocales,
|
supportedLocales: sl<AppConfig>().supportedLocales,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ dev_dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
flutter_lints: ^6.0.0
|
flutter_lints: ^6.0.0
|
||||||
|
integration_test:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|||||||
Reference in New Issue
Block a user