forked from eatvio/eatvio_app
fix-errors
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
# This builtInKotlin flag was added automatically by Flutter migrator
|
||||
android.builtInKotlin=false
|
||||
# This newDsl flag was added automatically by Flutter migrator
|
||||
android.newDsl=false
|
||||
|
||||
12
ios/Flutter/ephemeral/flutter_native_integration.env
Normal file
12
ios/Flutter/ephemeral/flutter_native_integration.env
Normal file
@@ -0,0 +1,12 @@
|
||||
FLUTTER_ROOT=C:\Users\Alexander\fvm\versions\3.44.0
|
||||
FLUTTER_APPLICATION_PATH=C:\Users\Alexander\eatvio_app
|
||||
FLUTTER_FRAMEWORK_SWIFT_PACKAGE_PATH=C:\Users\Alexander\eatvio_app\ios\Flutter\ephemeral\Packages\.packages\FlutterFramework
|
||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||
FLUTTER_TARGET=lib\main.dart
|
||||
FLUTTER_BUILD_DIR=build
|
||||
FLUTTER_BUILD_NAME=1.3.23
|
||||
FLUTTER_BUILD_NUMBER=105
|
||||
DART_OBFUSCATION=false
|
||||
TRACK_WIDGET_CREATION=true
|
||||
TREE_SHAKE_ICONS=false
|
||||
PACKAGE_CONFIG=.dart_tool/package_config.json
|
||||
@@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/core/env_config.dart';
|
||||
import 'package:eatvio_app/core/internet_connection_cubit/internet_connection_state.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
@@ -9,7 +10,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:eatvio_app/core/error_reporting/report_from.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class InternetConnectionCubit extends Cubit<InternetConnectionState> {
|
||||
InternetConnectionCubit() : super(InternetConnectionState()) {
|
||||
@@ -29,6 +29,16 @@ class InternetConnectionCubit extends Cubit<InternetConnectionState> {
|
||||
late StreamSubscription<List<ConnectivityResult>> _connectivitySubscription;
|
||||
late final AppLifecycleListener _listener;
|
||||
|
||||
/// Отдельный легковесный Dio без авторизационных интерцепторов —
|
||||
/// используется только для проверки доступности сети.
|
||||
final Dio _checkDio = Dio(BaseOptions(
|
||||
connectTimeout: const Duration(seconds: 5),
|
||||
receiveTimeout: const Duration(seconds: 5),
|
||||
followRedirects: true,
|
||||
// Любой HTTP-ответ = интернет доступен
|
||||
validateStatus: (status) => true,
|
||||
));
|
||||
|
||||
Future<void> checkConnection() async {
|
||||
late List<ConnectivityResult> result;
|
||||
|
||||
@@ -50,40 +60,61 @@ class InternetConnectionCubit extends Cubit<InternetConnectionState> {
|
||||
// Показываем toast только при переходе online → offline,
|
||||
// а не при каждом срабатывании проверки
|
||||
if (wasOnline && !hasInternet) showInternetConnectionToast();
|
||||
emit(state.copyWith(isInternetAvailable: hasInternet));
|
||||
if (!isClosed) {
|
||||
emit(state.copyWith(isInternetAvailable: hasInternet));
|
||||
}
|
||||
} catch (e, st) {
|
||||
await reportFrom(e, st, this);
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _checkInternetAccess(List<ConnectivityResult> result) async {
|
||||
// connectivity_plus может ошибочно возвращать 'none' на эмуляторах
|
||||
// и некоторых устройствах, поэтому ВСЕГДА проверяем через HTTP.
|
||||
// Если connectivity говорит 'none' — используем короткий таймаут.
|
||||
final isLikelyOffline = result.contains(ConnectivityResult.none);
|
||||
final timeout = Duration(seconds: isLikelyOffline ? 2 : 3);
|
||||
log('[InternetCheck] connectivity result: $result');
|
||||
|
||||
final uris = [
|
||||
Uri.parse(EnvConfig.googleCheckUrl),
|
||||
Uri.parse(EnvConfig.yandexCheckUrl),
|
||||
Uri.parse(EnvConfig.baseUrl),
|
||||
final rawUrls = [
|
||||
EnvConfig.googleCheckUrl,
|
||||
EnvConfig.yandexCheckUrl,
|
||||
EnvConfig.baseUrl,
|
||||
];
|
||||
|
||||
final futures = uris.map((uri) =>
|
||||
http.get(uri)
|
||||
.timeout(timeout)
|
||||
.then((r) => r.statusCode >= 100 && r.statusCode < 600)
|
||||
.catchError((_) => false)
|
||||
final urls = rawUrls
|
||||
.map((u) => u.trim())
|
||||
.where((u) => u.isNotEmpty && Uri.tryParse(u)?.hasScheme == true)
|
||||
.toList();
|
||||
|
||||
if (urls.isEmpty) {
|
||||
log('[InternetCheck] No valid check URLs configured, assuming online');
|
||||
return true;
|
||||
}
|
||||
|
||||
final futures = urls.map((url) =>
|
||||
_checkDio.get<void>(url)
|
||||
.then((_) {
|
||||
log('[InternetCheck] $url → OK');
|
||||
return true;
|
||||
})
|
||||
.catchError((Object e) {
|
||||
// DioException с ответом от сервера = интернет есть
|
||||
if (e is DioException && e.response != null) {
|
||||
log('[InternetCheck] $url → ${e.response!.statusCode} (has response, internet OK)');
|
||||
return true;
|
||||
}
|
||||
log('[InternetCheck] $url → FAILED: $e');
|
||||
return false;
|
||||
})
|
||||
);
|
||||
|
||||
final results = await Future.wait(futures);
|
||||
return results.any((ok) => ok);
|
||||
final hasInternet = results.any((ok) => ok);
|
||||
log('[InternetCheck] final result: hasInternet=$hasInternet');
|
||||
return hasInternet;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_connectivitySubscription.cancel();
|
||||
_listener.dispose();
|
||||
_checkDio.close();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ class _IngredientsWidgetState extends State<IngredientsWidget> {
|
||||
ReorderableListView(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
// ignore: deprecated_member_use
|
||||
onReorder: (int oldIndex, int newIndex) {
|
||||
setState(() {
|
||||
if (oldIndex < newIndex) {
|
||||
|
||||
@@ -116,6 +116,9 @@ class _PhotoGalleryWidgetState extends State<PhotoGalleryWidget> {
|
||||
builder: (context, state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
int mealIndex = state.selectedMeal - 1;
|
||||
if (mealIndex < 0 || mealIndex >= state.diary.meals.length) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final photos = state.diary.meals[mealIndex].photos;
|
||||
// BUG-5 fix: сбросить индекс, если он вышел за пределы
|
||||
// (например, после переключения на meal с меньшим числом фото)
|
||||
|
||||
@@ -20,6 +20,9 @@ class _ProductsListWidgetState extends State<ProductsListWidget> {
|
||||
builder: (BuildContext context, DiaryState state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
int mealIndex = state.selectedMeal - 1;
|
||||
if (mealIndex < 0 || mealIndex >= state.diary.meals.length) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final portions = state.diary.meals[mealIndex].portions;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -35,6 +38,9 @@ class _ProductsListWidgetState extends State<ProductsListWidget> {
|
||||
}
|
||||
if (state is DiaryStateLoadedTomorrowWithDiet) {
|
||||
int mealIndex = state.selectedMeal - 1;
|
||||
if (mealIndex < 0 || mealIndex >= state.diary.meals.length) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final portions = state.diary.meals[mealIndex].portions;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
||||
@@ -87,6 +87,11 @@ class _TimeOfMealPickerWidgetState extends State<TimeOfMealPickerWidget> {
|
||||
return BlocBuilder<DiaryCubit, DiaryState>(
|
||||
builder: (context, state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
final meals = state.diary.meals;
|
||||
final mealIndex = state.selectedMeal - 1;
|
||||
if (mealIndex < 0 || mealIndex >= meals.length) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Column(
|
||||
children: [
|
||||
const CustomDivider(),
|
||||
|
||||
@@ -12,7 +12,9 @@ class FeedProfileCubit extends Cubit<ProfileState> {
|
||||
Future<void> getProfile() async {
|
||||
try {
|
||||
final profile = await profileRepository.getMyProfile();
|
||||
emit(state.copyWith(profile: profile));
|
||||
if (!isClosed) {
|
||||
emit(state.copyWith(profile: profile));
|
||||
}
|
||||
} catch (e, stackTrace) {
|
||||
await reportFrom(e, stackTrace, this);
|
||||
log(e.toString(), stackTrace: stackTrace);
|
||||
|
||||
Reference in New Issue
Block a user