mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-04-18 14:42:54 +00:00
crop images and small improvements
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
This commit is contained in:
parent
8810ecf360
commit
b7e6cbfc2f
10 changed files with 227 additions and 124 deletions
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
## 0.1.3
|
## 0.1.3
|
||||||
|
|
||||||
- New: Developer settings to reduce flames
|
- New: Video stabilization
|
||||||
|
- New: Crop or rotate images before share them
|
||||||
- New: Clicking on “Text Notifications” will now open the chat directly (Android only)
|
- New: Clicking on “Text Notifications” will now open the chat directly (Android only)
|
||||||
|
- New: Developer settings to reduce flames
|
||||||
- Improve: Improved troubleshooting for issues with push notifications
|
- Improve: Improved troubleshooting for issues with push notifications
|
||||||
- Fix: Flash not activated when starting a video recording
|
- Fix: Flash not activated when starting a video recording
|
||||||
- Fix: Problem sending media when a recipient has deleted their account.
|
- Fix: Problem sending media when a recipient has deleted their account.
|
||||||
|
|
|
||||||
|
|
@ -26,19 +26,19 @@ class ReactionsDao extends DatabaseAccessor<TwonlyDB> with _$ReactionsDaoMixin {
|
||||||
Log.error('Did not update reaction as it is not an emoji!');
|
Log.error('Did not update reaction as it is not an emoji!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final msg =
|
final msg = await twonlyDB.messagesDao
|
||||||
await twonlyDB.messagesDao.getMessageById(messageId).getSingleOrNull();
|
.getMessageById(messageId)
|
||||||
|
.getSingleOrNull();
|
||||||
if (msg == null || msg.groupId != groupId) return;
|
if (msg == null || msg.groupId != groupId) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (remove) {
|
if (remove) {
|
||||||
await (delete(reactions)
|
await (delete(reactions)..where(
|
||||||
..where(
|
(t) =>
|
||||||
(t) =>
|
t.senderId.equals(contactId) &
|
||||||
t.senderId.equals(contactId) &
|
t.messageId.equals(messageId) &
|
||||||
t.messageId.equals(messageId) &
|
t.emoji.equals(emoji),
|
||||||
t.emoji.equals(emoji),
|
))
|
||||||
))
|
|
||||||
.go();
|
.go();
|
||||||
} else {
|
} else {
|
||||||
await into(reactions).insertOnConflictUpdate(
|
await into(reactions).insertOnConflictUpdate(
|
||||||
|
|
@ -63,18 +63,18 @@ class ReactionsDao extends DatabaseAccessor<TwonlyDB> with _$ReactionsDaoMixin {
|
||||||
Log.error('Did not update reaction as it is not an emoji!');
|
Log.error('Did not update reaction as it is not an emoji!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final msg =
|
final msg = await twonlyDB.messagesDao
|
||||||
await twonlyDB.messagesDao.getMessageById(messageId).getSingleOrNull();
|
.getMessageById(messageId)
|
||||||
|
.getSingleOrNull();
|
||||||
if (msg == null) return;
|
if (msg == null) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await (delete(reactions)
|
await (delete(reactions)..where(
|
||||||
..where(
|
(t) =>
|
||||||
(t) =>
|
t.senderId.isNull() &
|
||||||
t.senderId.isNull() &
|
t.messageId.equals(messageId) &
|
||||||
t.messageId.equals(messageId) &
|
t.emoji.equals(emoji),
|
||||||
t.emoji.equals(emoji),
|
))
|
||||||
))
|
|
||||||
.go();
|
.go();
|
||||||
if (!remove) {
|
if (!remove) {
|
||||||
await into(reactions).insert(
|
await into(reactions).insert(
|
||||||
|
|
@ -98,20 +98,19 @@ class ReactionsDao extends DatabaseAccessor<TwonlyDB> with _$ReactionsDaoMixin {
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<Reaction?> watchLastReactions(String groupId) {
|
Stream<Reaction?> watchLastReactions(String groupId) {
|
||||||
final query = (select(reactions)
|
final query =
|
||||||
..orderBy([(t) => OrderingTerm.desc(t.createdAt)]))
|
(select(reactions)).join(
|
||||||
.join(
|
[
|
||||||
[
|
innerJoin(
|
||||||
innerJoin(
|
messages,
|
||||||
messages,
|
messages.messageId.equalsExp(reactions.messageId),
|
||||||
messages.messageId.equalsExp(reactions.messageId),
|
useColumns: false,
|
||||||
useColumns: false,
|
),
|
||||||
),
|
],
|
||||||
],
|
)
|
||||||
)
|
..where(messages.groupId.equals(groupId))
|
||||||
..where(messages.groupId.equals(groupId))
|
..orderBy([OrderingTerm.desc(messages.createdAt)])
|
||||||
// ..orderBy([(t) => OrderingTerm.asc(t.createdAt)]))
|
..limit(1);
|
||||||
..limit(1);
|
|
||||||
return query.map((row) => row.readTable(reactions)).watchSingleOrNull();
|
return query.map((row) => row.readTable(reactions)).watchSingleOrNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,8 @@ class UserData {
|
||||||
@JsonKey(defaultValue: false)
|
@JsonKey(defaultValue: false)
|
||||||
bool requestedAudioPermission = false;
|
bool requestedAudioPermission = false;
|
||||||
|
|
||||||
@JsonKey(defaultValue: false)
|
@JsonKey(defaultValue: true)
|
||||||
bool videoStabilizationEnabled = false;
|
bool videoStabilizationEnabled = true;
|
||||||
|
|
||||||
@JsonKey(defaultValue: true)
|
@JsonKey(defaultValue: true)
|
||||||
bool showFeedbackShortcut = true;
|
bool showFeedbackShortcut = true;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import 'package:camera/camera.dart';
|
||||||
import 'package:clock/clock.dart';
|
import 'package:clock/clock.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:drift/drift.dart' show Value;
|
import 'package:drift/drift.dart' show Value;
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:google_mlkit_barcode_scanning/google_mlkit_barcode_scanning.dart';
|
import 'package:google_mlkit_barcode_scanning/google_mlkit_barcode_scanning.dart';
|
||||||
|
|
@ -133,7 +134,7 @@ class MainCameraController {
|
||||||
await cameraController?.initialize();
|
await cameraController?.initialize();
|
||||||
await cameraController?.startImageStream(_processCameraImage);
|
await cameraController?.startImageStream(_processCameraImage);
|
||||||
await cameraController?.setZoomLevel(selectedCameraDetails.scaleFactor);
|
await cameraController?.setZoomLevel(selectedCameraDetails.scaleFactor);
|
||||||
if (gUser.videoStabilizationEnabled) {
|
if (gUser.videoStabilizationEnabled && !kDebugMode) {
|
||||||
await cameraController?.setVideoStabilizationMode(
|
await cameraController?.setVideoStabilizationMode(
|
||||||
VideoStabilizationMode.level1,
|
VideoStabilizationMode.level1,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -109,13 +109,21 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
sendingOrLoadingImage = false;
|
sendingOrLoadingImage = false;
|
||||||
loadingImage = false;
|
loadingImage = false;
|
||||||
});
|
});
|
||||||
videoController = VideoPlayerController.file(mediaService.originalPath);
|
videoController = VideoPlayerController.file(
|
||||||
|
mediaService.originalPath,
|
||||||
|
videoPlayerOptions: VideoPlayerOptions(
|
||||||
|
mixWithOthers: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
videoController?.setLooping(true);
|
videoController?.setLooping(true);
|
||||||
videoController?.initialize().then((_) async {
|
videoController
|
||||||
await videoController!.play();
|
?.initialize()
|
||||||
setState(() {});
|
.then((_) async {
|
||||||
// ignore: invalid_return_type_for_catch_error, argument_type_not_assignable_to_error_handler
|
await videoController!.play();
|
||||||
}).catchError(Log.error);
|
setState(() {});
|
||||||
|
})
|
||||||
|
// ignore: argument_type_not_assignable_to_error_handler, invalid_return_type_for_catch_error
|
||||||
|
.catchError(Log.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,8 +213,8 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
|
|
||||||
List<Widget> get actionsAtTheRight {
|
List<Widget> get actionsAtTheRight {
|
||||||
if (layers.isNotEmpty &&
|
if (layers.isNotEmpty &&
|
||||||
layers.last.isEditing &&
|
(layers.first.isEditing ||
|
||||||
layers.last.hasCustomActionButtons) {
|
(layers.last.isEditing && layers.last.hasCustomActionButtons))) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return <Widget>[
|
return <Widget>[
|
||||||
|
|
@ -246,13 +254,15 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
Icons.add_reaction_outlined,
|
Icons.add_reaction_outlined,
|
||||||
tooltipText: context.lang.addEmoji,
|
tooltipText: context.lang.addEmoji,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final layer = await showModalBottomSheet(
|
final layer =
|
||||||
context: context,
|
await showModalBottomSheet(
|
||||||
backgroundColor: Colors.black,
|
context: context,
|
||||||
builder: (context) {
|
backgroundColor: Colors.black,
|
||||||
return const EmojiPickerBottom();
|
builder: (context) {
|
||||||
},
|
return const EmojiPickerBottom();
|
||||||
) as Layer?;
|
},
|
||||||
|
)
|
||||||
|
as Layer?;
|
||||||
if (layer == null) return;
|
if (layer == null) return;
|
||||||
undoLayers.clear();
|
undoLayers.clear();
|
||||||
removedLayers.clear();
|
removedLayers.clear();
|
||||||
|
|
@ -265,19 +275,20 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
count: (media.type == MediaType.video)
|
count: (media.type == MediaType.video)
|
||||||
? '0'
|
? '0'
|
||||||
: media.displayLimitInMilliseconds == null
|
: media.displayLimitInMilliseconds == null
|
||||||
? '∞'
|
? '∞'
|
||||||
: (media.displayLimitInMilliseconds! ~/ 1000).toString(),
|
: (media.displayLimitInMilliseconds! ~/ 1000).toString(),
|
||||||
child: ActionButton(
|
child: ActionButton(
|
||||||
(media.type == MediaType.video)
|
(media.type == MediaType.video)
|
||||||
? media.displayLimitInMilliseconds == null
|
? media.displayLimitInMilliseconds == null
|
||||||
? Icons.repeat_rounded
|
? Icons.repeat_rounded
|
||||||
: Icons.repeat_one_rounded
|
: Icons.repeat_one_rounded
|
||||||
: Icons.timer_outlined,
|
: Icons.timer_outlined,
|
||||||
tooltipText: context.lang.protectAsARealTwonly,
|
tooltipText: context.lang.protectAsARealTwonly,
|
||||||
onPressed: _setImageDisplayTime,
|
onPressed: _setImageDisplayTime,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (media.type == MediaType.video)
|
if (media.type == MediaType.video) ...[
|
||||||
|
const SizedBox(height: 8),
|
||||||
ActionButton(
|
ActionButton(
|
||||||
(mediaService.removeAudio)
|
(mediaService.removeAudio)
|
||||||
? Icons.volume_off_rounded
|
? Icons.volume_off_rounded
|
||||||
|
|
@ -296,6 +307,29 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
if (mounted) setState(() {});
|
if (mounted) setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
if (media.type == MediaType.image) ...[
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
ActionButton(
|
||||||
|
Icons.crop_rotate_outlined,
|
||||||
|
tooltipText: 'Crop or rotate image',
|
||||||
|
color: Colors.white,
|
||||||
|
onPressed: () async {
|
||||||
|
final first = layers.first;
|
||||||
|
if (first is BackgroundLayerData) {
|
||||||
|
first.isEditing = !first.isEditing;
|
||||||
|
}
|
||||||
|
setState(() {});
|
||||||
|
// await mediaService.toggleRemoveAudio();
|
||||||
|
// if (mediaService.removeAudio) {
|
||||||
|
// await videoController?.setVolume(0);
|
||||||
|
// } else {
|
||||||
|
// await videoController?.setVolume(100);
|
||||||
|
// }
|
||||||
|
// if (mounted) setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
ActionButton(
|
ActionButton(
|
||||||
FontAwesomeIcons.shieldHeart,
|
FontAwesomeIcons.shieldHeart,
|
||||||
|
|
@ -348,8 +382,8 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
|
|
||||||
List<Widget> get actionsAtTheTop {
|
List<Widget> get actionsAtTheTop {
|
||||||
if (layers.isNotEmpty &&
|
if (layers.isNotEmpty &&
|
||||||
layers.last.isEditing &&
|
(layers.first.isEditing ||
|
||||||
layers.last.hasCustomActionButtons) {
|
(layers.last.isEditing && layers.last.hasCustomActionButtons))) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
|
|
@ -411,18 +445,20 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
|
|
||||||
await videoController?.pause();
|
await videoController?.pause();
|
||||||
if (isDisposed || !mounted) return;
|
if (isDisposed || !mounted) return;
|
||||||
final wasSend = await Navigator.push(
|
final wasSend =
|
||||||
context,
|
await Navigator.push(
|
||||||
MaterialPageRoute(
|
context,
|
||||||
builder: (context) => ShareImageView(
|
MaterialPageRoute(
|
||||||
selectedGroupIds: selectedGroupIds,
|
builder: (context) => ShareImageView(
|
||||||
updateSelectedGroupIds: updateSelectedGroupIds,
|
selectedGroupIds: selectedGroupIds,
|
||||||
mediaStoreFuture: mediaStoreFuture,
|
updateSelectedGroupIds: updateSelectedGroupIds,
|
||||||
mediaFileService: mediaService,
|
mediaStoreFuture: mediaStoreFuture,
|
||||||
additionalData: getAdditionalData(),
|
mediaFileService: mediaService,
|
||||||
),
|
additionalData: getAdditionalData(),
|
||||||
),
|
),
|
||||||
) as bool?;
|
),
|
||||||
|
)
|
||||||
|
as bool?;
|
||||||
if (wasSend != null && wasSend && mounted) {
|
if (wasSend != null && wasSend && mounted) {
|
||||||
widget.mainCameraController?.onImageSend();
|
widget.mainCameraController?.onImageSend();
|
||||||
Navigator.pop(context, true);
|
Navigator.pop(context, true);
|
||||||
|
|
@ -552,8 +588,9 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
});
|
});
|
||||||
// It is important that the user can sending the image only when the image is fully loaded otherwise if the user
|
// It is important that the user can sending the image only when the image is fully loaded otherwise if the user
|
||||||
// will click on send before the image is painted the screenshot will be transparent..
|
// will click on send before the image is painted the screenshot will be transparent..
|
||||||
_imageLoadingTimer =
|
_imageLoadingTimer = Timer.periodic(const Duration(milliseconds: 10), (
|
||||||
Timer.periodic(const Duration(milliseconds: 10), (timer) {
|
timer,
|
||||||
|
) {
|
||||||
final imageLayer = layers.first;
|
final imageLayer = layers.first;
|
||||||
if (imageLayer is BackgroundLayerData) {
|
if (imageLayer is BackgroundLayerData) {
|
||||||
if (imageLayer.imageLoaded) {
|
if (imageLayer.imageLoaded) {
|
||||||
|
|
@ -619,8 +656,9 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
await askToCloseThenClose();
|
await askToCloseThenClose();
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor:
|
backgroundColor: widget.sharedFromGallery
|
||||||
widget.sharedFromGallery ? null : Colors.white.withAlpha(0),
|
? null
|
||||||
|
: Colors.white.withAlpha(0),
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
body: Stack(
|
body: Stack(
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
|
|
@ -667,8 +705,9 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
iconColor: Theme.of(context).colorScheme.primary,
|
iconColor: Theme.of(context).colorScheme.primary,
|
||||||
foregroundColor:
|
foregroundColor: Theme.of(
|
||||||
Theme.of(context).colorScheme.primary,
|
context,
|
||||||
|
).colorScheme.primary,
|
||||||
),
|
),
|
||||||
onPressed: pushShareImageView,
|
onPressed: pushShareImageView,
|
||||||
child: const FaIcon(FontAwesomeIcons.userPlus),
|
child: const FaIcon(FontAwesomeIcons.userPlus),
|
||||||
|
|
@ -681,9 +720,9 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
width: 12,
|
width: 12,
|
||||||
child: CircularProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
color: Theme.of(context)
|
color: Theme.of(
|
||||||
.colorScheme
|
context,
|
||||||
.inversePrimary,
|
).colorScheme.inversePrimary,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: const FaIcon(FontAwesomeIcons.solidPaperPlane),
|
: const FaIcon(FontAwesomeIcons.solidPaperPlane),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:photo_view/photo_view.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
import 'package:twonly/src/views/camera/share_image_editor/action_button.dart';
|
||||||
import 'package:twonly/src/views/camera/share_image_editor/layer_data.dart';
|
import 'package:twonly/src/views/camera/share_image_editor/layer_data.dart';
|
||||||
|
|
||||||
class BackgroundLayer extends StatefulWidget {
|
class BackgroundLayer extends StatefulWidget {
|
||||||
|
|
@ -29,14 +33,47 @@ class _BackgroundLayerState extends State<BackgroundLayer> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final scImage = widget.layerData.image.image;
|
final scImage = widget.layerData.image.image;
|
||||||
if (scImage == null || scImage.image == null) return Container();
|
if (scImage == null || scImage.image == null) return Container();
|
||||||
return Container(
|
return Stack(
|
||||||
width: widget.layerData.image.width.toDouble(),
|
children: [
|
||||||
height: widget.layerData.image.height.toDouble(),
|
Positioned.fill(
|
||||||
padding: EdgeInsets.zero,
|
child: PhotoView.customChild(
|
||||||
color: Colors.transparent,
|
enableRotation: true,
|
||||||
child: CustomPaint(
|
initialScale: PhotoViewComputedScale.contained,
|
||||||
painter: UiImagePainter(scImage.image!),
|
minScale: PhotoViewComputedScale.contained,
|
||||||
),
|
backgroundDecoration: const BoxDecoration(
|
||||||
|
color: Colors.transparent,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
width: widget.layerData.image.width.toDouble(),
|
||||||
|
height: widget.layerData.image.height.toDouble(),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: CustomPaint(
|
||||||
|
painter: UiImagePainter(scImage.image!),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (widget.layerData.isEditing)
|
||||||
|
Positioned(
|
||||||
|
top: 5,
|
||||||
|
left: 5,
|
||||||
|
right: 50,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
ActionButton(
|
||||||
|
FontAwesomeIcons.check,
|
||||||
|
tooltipText: context.lang.imageEditorDrawOk,
|
||||||
|
onPressed: () async {
|
||||||
|
widget.layerData.isEditing = false;
|
||||||
|
widget.onUpdate!();
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,15 @@ class LayersViewer extends StatelessWidget {
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
...layers.whereType<BackgroundLayerData>().map((layerItem) {
|
...layers.whereType<BackgroundLayerData>().map((layerItem) {
|
||||||
return BackgroundLayer(
|
if (!layerItem.isEditing) {
|
||||||
key: layerItem.key,
|
return BackgroundLayer(
|
||||||
layerData: layerItem,
|
key: layerItem.key,
|
||||||
onUpdate: onUpdate,
|
layerData: layerItem,
|
||||||
);
|
onUpdate: onUpdate,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
...layers.whereType<FilterLayerData>().map((layerItem) {
|
...layers.whereType<FilterLayerData>().map((layerItem) {
|
||||||
return FilterLayer(
|
return FilterLayer(
|
||||||
|
|
@ -37,39 +41,50 @@ class LayersViewer extends StatelessWidget {
|
||||||
}),
|
}),
|
||||||
...layers
|
...layers
|
||||||
.where(
|
.where(
|
||||||
(layerItem) =>
|
(layerItem) =>
|
||||||
layerItem is EmojiLayerData ||
|
layerItem is EmojiLayerData ||
|
||||||
layerItem is DrawLayerData ||
|
layerItem is DrawLayerData ||
|
||||||
layerItem is LinkPreviewLayerData ||
|
layerItem is LinkPreviewLayerData ||
|
||||||
layerItem is TextLayerData,
|
layerItem is TextLayerData,
|
||||||
)
|
)
|
||||||
.map((layerItem) {
|
.map((layerItem) {
|
||||||
if (layerItem is EmojiLayerData) {
|
if (layerItem is EmojiLayerData) {
|
||||||
return EmojiLayer(
|
return EmojiLayer(
|
||||||
key: layerItem.key,
|
key: layerItem.key,
|
||||||
layerData: layerItem,
|
layerData: layerItem,
|
||||||
onUpdate: onUpdate,
|
onUpdate: onUpdate,
|
||||||
);
|
);
|
||||||
} else if (layerItem is DrawLayerData) {
|
} else if (layerItem is DrawLayerData) {
|
||||||
return DrawLayer(
|
return DrawLayer(
|
||||||
key: layerItem.key,
|
key: layerItem.key,
|
||||||
layerData: layerItem,
|
layerData: layerItem,
|
||||||
onUpdate: onUpdate,
|
onUpdate: onUpdate,
|
||||||
);
|
);
|
||||||
} else if (layerItem is TextLayerData) {
|
} else if (layerItem is TextLayerData) {
|
||||||
return TextLayer(
|
return TextLayer(
|
||||||
key: layerItem.key,
|
key: layerItem.key,
|
||||||
layerData: layerItem,
|
layerData: layerItem,
|
||||||
onUpdate: onUpdate,
|
onUpdate: onUpdate,
|
||||||
);
|
);
|
||||||
} else if (layerItem is LinkPreviewLayerData) {
|
} else if (layerItem is LinkPreviewLayerData) {
|
||||||
return LinkPreviewLayer(
|
return LinkPreviewLayer(
|
||||||
|
key: layerItem.key,
|
||||||
|
layerData: layerItem,
|
||||||
|
onUpdate: onUpdate,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Container();
|
||||||
|
}),
|
||||||
|
...layers.whereType<BackgroundLayerData>().map((layerItem) {
|
||||||
|
if (layerItem.isEditing) {
|
||||||
|
return BackgroundLayer(
|
||||||
key: layerItem.key,
|
key: layerItem.key,
|
||||||
layerData: layerItem,
|
layerData: layerItem,
|
||||||
onUpdate: onUpdate,
|
onUpdate: onUpdate,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return Container();
|
||||||
}
|
}
|
||||||
return Container();
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -75,9 +75,6 @@ class _UserListItem extends State<GroupListItem> {
|
||||||
setState(() {
|
setState(() {
|
||||||
_lastReaction = update;
|
_lastReaction = update;
|
||||||
});
|
});
|
||||||
// protectUpdateState.protect(() async {
|
|
||||||
// await updateState(lastMessage, update, messagesNotOpened);
|
|
||||||
// });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_messagesNotOpenedStream = twonlyDB.messagesDao
|
_messagesNotOpenedStream = twonlyDB.messagesDao
|
||||||
|
|
|
||||||
|
|
@ -287,7 +287,15 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
var timerRequired = false;
|
var timerRequired = false;
|
||||||
|
|
||||||
if (currentMediaLocal.mediaFile.type == MediaType.video) {
|
if (currentMediaLocal.mediaFile.type == MediaType.video) {
|
||||||
videoController = VideoPlayerController.file(currentMediaLocal.tempPath);
|
videoController = VideoPlayerController.file(
|
||||||
|
currentMediaLocal.tempPath,
|
||||||
|
videoPlayerOptions: VideoPlayerOptions(
|
||||||
|
// only mix in case the video can be played multiple times,
|
||||||
|
// otherwise stop the background music in case the video contains audio
|
||||||
|
mixWithOthers:
|
||||||
|
currentMediaLocal.mediaFile.displayLimitInMilliseconds == null,
|
||||||
|
),
|
||||||
|
);
|
||||||
await videoController?.setLooping(
|
await videoController?.setLooping(
|
||||||
currentMediaLocal.mediaFile.displayLimitInMilliseconds == null,
|
currentMediaLocal.mediaFile.displayLimitInMilliseconds == null,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,12 @@ class _VideoPlayerWrapperState extends State<VideoPlayerWrapper> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_controller = VideoPlayerController.file(widget.videoPath);
|
_controller = VideoPlayerController.file(
|
||||||
|
widget.videoPath,
|
||||||
|
videoPlayerOptions: VideoPlayerOptions(
|
||||||
|
mixWithOthers: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
unawaited(
|
unawaited(
|
||||||
_controller.initialize().then((_) async {
|
_controller.initialize().then((_) async {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue