forked from eatvio/eatvio_app
Compare commits
9 Commits
chat_messa
...
issue-1037
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b03a0d5e1 | ||
|
|
0208ed753a | ||
|
|
6265e865e9 | ||
| 1550b7ea0b | |||
|
|
db10895ebb | ||
|
|
a7361d3ab1 | ||
| 1c54063a35 | |||
| efae7fc958 | |||
| caf45a9050 |
@@ -78,12 +78,7 @@
|
|||||||
<data android:host="eatvio.com" />
|
<data android:host="eatvio.com" />
|
||||||
<data android:host="www.eatvio.com" />
|
<data android:host="www.eatvio.com" />
|
||||||
|
|
||||||
<!-- Development/Subdomains -->
|
|
||||||
<data android:host="*.eatvio.ru" />
|
|
||||||
<data android:host="*.eatvio.com" />
|
|
||||||
|
|
||||||
<!-- Simplify patterns to allow navigation within the app for all matching hosts -->
|
|
||||||
<data android:pathPattern="/.*" />
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<!-- Don't delete the meta-data below.
|
<!-- Don't delete the meta-data below.
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
<array>
|
<array>
|
||||||
<string>applinks:eatvio.ru</string>
|
<string>applinks:eatvio.ru</string>
|
||||||
<string>applinks:www.eatvio.ru</string>
|
<string>applinks:www.eatvio.ru</string>
|
||||||
|
<string>applinks:eatvio.com</string>
|
||||||
|
<string>applinks:www.eatvio.com</string>
|
||||||
<string>applinks:5399b03636104c6d920b87c1ad329254.oauth.yandex.ru</string>
|
<string>applinks:5399b03636104c6d920b87c1ad329254.oauth.yandex.ru</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
@@ -37,6 +37,17 @@ class BlogPostCreateCubit extends Cubit<BlogPostCreateState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setImagesError(String? error) {
|
||||||
|
if (state.imagesError == error &&
|
||||||
|
state.formError == null &&
|
||||||
|
state.errorMessage == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit(
|
||||||
|
state.copyWith(imagesError: error, formError: null, errorMessage: null),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void resetFormErrors() {
|
void resetFormErrors() {
|
||||||
if (!state.hasValidationErrors &&
|
if (!state.hasValidationErrors &&
|
||||||
!state.isSuccess &&
|
!state.isSuccess &&
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:eatvio_app/app_keys.dart';
|
import 'package:eatvio_app/app_keys.dart';
|
||||||
import 'package:eatvio_app/core/app_router.dart';
|
import 'package:eatvio_app/core/app_router.dart';
|
||||||
@@ -38,11 +39,15 @@ class BlogPostCreateScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
||||||
|
static const _minImageWidth = 500;
|
||||||
|
static const _minImageHeight = 500;
|
||||||
|
|
||||||
final blogPostCubit = sl<BlogPostCreateCubit>();
|
final blogPostCubit = sl<BlogPostCreateCubit>();
|
||||||
bool shrinkImage = false;
|
bool shrinkImage = false;
|
||||||
late StreamSubscription<bool> keyboardSubscription;
|
late StreamSubscription<bool> keyboardSubscription;
|
||||||
final List<FeedGalleryImage> savedImages = [];
|
final List<FeedGalleryImage> savedImages = [];
|
||||||
final List<XFile> pendingImages = [];
|
final List<XFile> pendingImages = [];
|
||||||
|
final Set<String> _undersizedPendingPaths = {};
|
||||||
final List<int> mediaIdsToDelete = [];
|
final List<int> mediaIdsToDelete = [];
|
||||||
final titleController = TextEditingController();
|
final titleController = TextEditingController();
|
||||||
final descriptionController = TextEditingController();
|
final descriptionController = TextEditingController();
|
||||||
@@ -531,10 +536,7 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
|||||||
source: ImageSource.camera,
|
source: ImageSource.camera,
|
||||||
);
|
);
|
||||||
if (image != null && _remainingSlots > 0) {
|
if (image != null && _remainingSlots > 0) {
|
||||||
setState(() {
|
await _addPendingImages([image]);
|
||||||
pendingImages.add(image);
|
|
||||||
});
|
|
||||||
blogPostCubit.clearImagesError();
|
|
||||||
}
|
}
|
||||||
AppRouter.navigatorKey.currentContext?.pop();
|
AppRouter.navigatorKey.currentContext?.pop();
|
||||||
},
|
},
|
||||||
@@ -561,10 +563,9 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
|||||||
limit: _remainingSlots,
|
limit: _remainingSlots,
|
||||||
);
|
);
|
||||||
if (images.isNotEmpty) {
|
if (images.isNotEmpty) {
|
||||||
setState(() {
|
await _addPendingImages(
|
||||||
pendingImages.addAll(images.take(_remainingSlots));
|
images.take(_remainingSlots).toList(),
|
||||||
});
|
);
|
||||||
blogPostCubit.clearImagesError();
|
|
||||||
}
|
}
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
AppRouter.navigatorKey.currentContext?.pop();
|
AppRouter.navigatorKey.currentContext?.pop();
|
||||||
@@ -603,9 +604,12 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _removePendingImage(int index) {
|
void _removePendingImage(int index) {
|
||||||
|
final path = pendingImages[index].path;
|
||||||
setState(() {
|
setState(() {
|
||||||
pendingImages.removeAt(index);
|
pendingImages.removeAt(index);
|
||||||
|
_undersizedPendingPaths.remove(path);
|
||||||
});
|
});
|
||||||
|
_syncImagesSizeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onReorderGallery(int oldIndex, int newIndex) {
|
void _onReorderGallery(int oldIndex, int newIndex) {
|
||||||
@@ -839,6 +843,11 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_undersizedPendingPaths.isNotEmpty) {
|
||||||
|
blogPostCubit.setImagesError(S.current.blog_post_image_min_size_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final title = titleController.text.trim();
|
final title = titleController.text.trim();
|
||||||
final description = descriptionController.text.trim();
|
final description = descriptionController.text.trim();
|
||||||
final videoUrl = videoUrlController.text.trim();
|
final videoUrl = videoUrlController.text.trim();
|
||||||
@@ -907,6 +916,50 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _addPendingImages(List<XFile> images) async {
|
||||||
|
if (images.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final undersizedPaths = <String>{};
|
||||||
|
for (final image in images) {
|
||||||
|
if (!await _isImageLargeEnough(image)) {
|
||||||
|
undersizedPaths.add(image.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
pendingImages.addAll(images);
|
||||||
|
_undersizedPendingPaths.addAll(undersizedPaths);
|
||||||
|
});
|
||||||
|
_syncImagesSizeError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _syncImagesSizeError() {
|
||||||
|
final minSizeError = S.current.blog_post_image_min_size_error;
|
||||||
|
if (_undersizedPendingPaths.isNotEmpty) {
|
||||||
|
blogPostCubit.setImagesError(minSizeError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (blogPostCubit.state.imagesError == minSizeError) {
|
||||||
|
blogPostCubit.clearImagesError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _isImageLargeEnough(XFile image) async {
|
||||||
|
try {
|
||||||
|
final bytes = await File(image.path).readAsBytes();
|
||||||
|
final descriptor = await ui.ImmutableBuffer.fromUint8List(bytes);
|
||||||
|
final codec = await ui.instantiateImageCodecFromBuffer(descriptor);
|
||||||
|
final frame = await codec.getNextFrame();
|
||||||
|
final width = frame.image.width;
|
||||||
|
final height = frame.image.height;
|
||||||
|
return width >= _minImageWidth && height >= _minImageHeight;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildGallery() {
|
Widget _buildGallery() {
|
||||||
final itemHeight = shrinkImage ? 72.0 : 112.0;
|
final itemHeight = shrinkImage ? 72.0 : 112.0;
|
||||||
|
|
||||||
@@ -946,6 +999,7 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
|||||||
child: _buildGalleryTile(
|
child: _buildGalleryTile(
|
||||||
index: index,
|
index: index,
|
||||||
height: itemHeight,
|
height: itemHeight,
|
||||||
|
hasError: _undersizedPendingPaths.contains(pending.path),
|
||||||
imageProvider: FileImage(File(pending.path)),
|
imageProvider: FileImage(File(pending.path)),
|
||||||
onRemove: () => _removePendingImage(pendingIndex),
|
onRemove: () => _removePendingImage(pendingIndex),
|
||||||
),
|
),
|
||||||
@@ -985,6 +1039,7 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
|||||||
required double height,
|
required double height,
|
||||||
required ImageProvider imageProvider,
|
required ImageProvider imageProvider,
|
||||||
required VoidCallback onRemove,
|
required VoidCallback onRemove,
|
||||||
|
bool hasError = false,
|
||||||
}) {
|
}) {
|
||||||
return ReorderableDelayedDragStartListener(
|
return ReorderableDelayedDragStartListener(
|
||||||
index: index,
|
index: index,
|
||||||
@@ -992,12 +1047,16 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
|||||||
width: height,
|
width: height,
|
||||||
height: height,
|
height: height,
|
||||||
margin: const EdgeInsets.only(right: 8),
|
margin: const EdgeInsets.only(right: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
border: hasError ? Border.all(color: appTheme.red, width: 2) : null,
|
||||||
|
),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(14),
|
||||||
child: Image(image: imageProvider, fit: BoxFit.cover),
|
child: Image(image: imageProvider, fit: BoxFit.cover),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -137,6 +137,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||||||
"Средние показатели давления:",
|
"Средние показатели давления:",
|
||||||
),
|
),
|
||||||
"back_to_chat": MessageLookupByLibrary.simpleMessage("Вернуться в чат"),
|
"back_to_chat": MessageLookupByLibrary.simpleMessage("Вернуться в чат"),
|
||||||
|
"blog_post_image_min_size_error": MessageLookupByLibrary.simpleMessage(
|
||||||
|
"Минимальный размер изображения — 500×500 px",
|
||||||
|
),
|
||||||
"bodymass_chart": MessageLookupByLibrary.simpleMessage("График ИМТ"),
|
"bodymass_chart": MessageLookupByLibrary.simpleMessage("График ИМТ"),
|
||||||
"by_default": MessageLookupByLibrary.simpleMessage("По умолчанию"),
|
"by_default": MessageLookupByLibrary.simpleMessage("По умолчанию"),
|
||||||
"calls_for_bullying": MessageLookupByLibrary.simpleMessage(
|
"calls_for_bullying": MessageLookupByLibrary.simpleMessage(
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||||||
"average_pressure": MessageLookupByLibrary.simpleMessage(
|
"average_pressure": MessageLookupByLibrary.simpleMessage(
|
||||||
"Средние показатели давления:",
|
"Средние показатели давления:",
|
||||||
),
|
),
|
||||||
|
"blog_post_image_min_size_error": MessageLookupByLibrary.simpleMessage(
|
||||||
|
"Минимальный размер изображения — 500×500 px",
|
||||||
|
),
|
||||||
"bodymass_chart": MessageLookupByLibrary.simpleMessage("График ИМТ"),
|
"bodymass_chart": MessageLookupByLibrary.simpleMessage("График ИМТ"),
|
||||||
"by_default": MessageLookupByLibrary.simpleMessage("По умолчанию"),
|
"by_default": MessageLookupByLibrary.simpleMessage("По умолчанию"),
|
||||||
"calories": MessageLookupByLibrary.simpleMessage("Калории"),
|
"calories": MessageLookupByLibrary.simpleMessage("Калории"),
|
||||||
|
|||||||
@@ -2569,6 +2569,16 @@ class S {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `Минимальный размер изображения — 500×500 px`
|
||||||
|
String get blog_post_image_min_size_error {
|
||||||
|
return Intl.message(
|
||||||
|
'Минимальный размер изображения — 500×500 px',
|
||||||
|
name: 'blog_post_image_min_size_error',
|
||||||
|
desc: '',
|
||||||
|
args: [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// `Информация о заказе`
|
/// `Информация о заказе`
|
||||||
String get infoAboutOrder {
|
String get infoAboutOrder {
|
||||||
return Intl.message(
|
return Intl.message(
|
||||||
|
|||||||
@@ -317,6 +317,7 @@
|
|||||||
"could_not_publish_blog_post": "Не удалось опубликовать пост",
|
"could_not_publish_blog_post": "Не удалось опубликовать пост",
|
||||||
"could_not_update_blog_post": "Не удалось обновить пост",
|
"could_not_update_blog_post": "Не удалось обновить пост",
|
||||||
"could_not_delete_blog_post": "Не удалось удалить пост",
|
"could_not_delete_blog_post": "Не удалось удалить пост",
|
||||||
|
"blog_post_image_min_size_error": "Минимальный размер изображения — 500×500 px",
|
||||||
"infoAboutOrder": "Информация о заказе",
|
"infoAboutOrder": "Информация о заказе",
|
||||||
"to_order": "Заказать",
|
"to_order": "Заказать",
|
||||||
"can_not_choose_start_date": "Дату старта плана невозможно выбрать, пока Вы не привяжите карту",
|
"can_not_choose_start_date": "Дату старта плана невозможно выбрать, пока Вы не привяжите карту",
|
||||||
|
|||||||
@@ -270,5 +270,6 @@
|
|||||||
"video_call_close": "Закрыть",
|
"video_call_close": "Закрыть",
|
||||||
"video_call_notification_in_progress": "Звонок идёт",
|
"video_call_notification_in_progress": "Звонок идёт",
|
||||||
"video_call_notification_return": "Вернуться к звонку",
|
"video_call_notification_return": "Вернуться к звонку",
|
||||||
"video_call_notification_end": "Завершить звонок"
|
"video_call_notification_end": "Завершить звонок",
|
||||||
|
"blog_post_image_min_size_error": "Минимальный размер изображения — 500×500 px"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: eatvio_app
|
name: eatvio_app
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
version: 1.3.40+129
|
version: 1.3.42+131
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
Reference in New Issue
Block a user