mirror front camera for android

This commit is contained in:
otsmr 2025-04-29 15:08:24 +02:00
parent 06715e8ac9
commit 0d36289169
7 changed files with 111 additions and 71 deletions

View file

@ -47,6 +47,7 @@ class MediaUploadMetadata {
late DateTime messageSendAt;
late bool isVideo;
late bool videoWithAudio;
late bool mirrorVideo;
MediaUploadMetadata();
@ -54,6 +55,7 @@ class MediaUploadMetadata {
return {
'contactIds': contactIds,
'isRealTwonly': isRealTwonly,
'mirrorVideo': mirrorVideo,
'maxShowTime': maxShowTime,
'isVideo': isVideo,
'videoWithAudio': videoWithAudio,
@ -67,6 +69,7 @@ class MediaUploadMetadata {
state.isRealTwonly = json['isRealTwonly'];
state.videoWithAudio = json['videoWithAudio'];
state.isVideo = json['isVideo'];
state.mirrorVideo = json['mirrorVideo'];
state.maxShowTime = json['maxShowTime'];
state.maxShowTime = json['maxShowTime'];
state.messageSendAt = DateTime.parse(json['messageSendAt']);

View file

@ -99,6 +99,7 @@ class MediaMessageContent extends MessageContent {
final int maxShowTime;
final bool isRealTwonly;
final bool isVideo;
final bool mirrorVideo;
final List<int>? downloadToken;
final List<int>? encryptionKey;
final List<int>? encryptionMac;
@ -108,6 +109,7 @@ class MediaMessageContent extends MessageContent {
required this.maxShowTime,
required this.isRealTwonly,
required this.isVideo,
required this.mirrorVideo,
this.downloadToken,
this.encryptionKey,
this.encryptionMac,
@ -131,6 +133,7 @@ class MediaMessageContent extends MessageContent {
maxShowTime: json['maxShowTime'],
isRealTwonly: json['isRealTwonly'],
isVideo: json['isVideo'] ?? false,
mirrorVideo: json['mirrorVideo'] ?? false,
);
}
@ -144,6 +147,7 @@ class MediaMessageContent extends MessageContent {
'isRealTwonly': isRealTwonly,
'maxShowTime': maxShowTime,
'isVideo': isVideo,
'mirrorVideo': mirrorVideo,
};
}
}

View file

@ -26,7 +26,7 @@ Future sendMediaFile(
int maxShowTime,
XFile? videoFilePath,
bool? enableVideoAudio,
) async {
bool mirrorVideo) async {
MediaUploadMetadata metadata = MediaUploadMetadata();
metadata.contactIds = userIds;
metadata.isRealTwonly = isRealTwonly;
@ -34,6 +34,7 @@ Future sendMediaFile(
metadata.isVideo = videoFilePath != null;
metadata.videoWithAudio = enableVideoAudio != null && enableVideoAudio;
metadata.maxShowTime = maxShowTime;
metadata.mirrorVideo = mirrorVideo;
int? mediaUploadId = await twonlyDatabase.mediaUploadsDao.insertMediaUpload(
MediaUploadsCompanion(
@ -62,7 +63,7 @@ Future retryMediaUpload() async {
final lockingHandleMediaFile = Mutex();
Future handleSingleMediaFile(int mediaUploadId) async {
// await lockingHandleMediaFile.protect(() async {
await lockingHandleMediaFile.protect(() async {
MediaUpload? media = await twonlyDatabase.mediaUploadsDao
.getMediaUploadById(mediaUploadId)
.getSingleOrNull();
@ -97,10 +98,6 @@ Future handleSingleMediaFile(int mediaUploadId) async {
case UploadState.receiverNotified:
return;
}
// this will be called until there is an recoverable error OR
// the upload is ready
await handleSingleMediaFile(mediaUploadId);
} catch (e) {
// if the messageIds are already there notify the user about this error...
if (media.messageIds != null) {
@ -116,8 +113,12 @@ Future handleSingleMediaFile(int mediaUploadId) async {
await twonlyDatabase.mediaUploadsDao.deleteMediaUpload(mediaUploadId);
Logger("media_send.dart")
.shout("Non recoverable error while sending media file: $e");
return;
}
// });
});
// this will be called until there is an recoverable error OR
// the upload is ready
await handleSingleMediaFile(mediaUploadId);
}
Future handleAddToMessageDb(MediaUpload media) async {
@ -137,6 +138,7 @@ Future handleAddToMessageDb(MediaUpload media) async {
maxShowTime: media.metadata.maxShowTime,
isRealTwonly: media.metadata.isRealTwonly,
isVideo: media.metadata.isVideo,
mirrorVideo: media.metadata.mirrorVideo,
).toJson(),
),
),
@ -357,7 +359,11 @@ Future<bool> handleUpload(MediaUpload media) async {
),
);
try {
await deleteMediaFile(media, "encrypted");
} catch (e) {
Logger("media_send.dart").shout("$e");
}
return true;
}
@ -395,6 +401,7 @@ Future<bool> handleNotifyReceiver(MediaUpload media) async {
maxShowTime: media.metadata.maxShowTime,
isRealTwonly: media.metadata.isRealTwonly,
isVideo: media.metadata.isVideo,
mirrorVideo: media.metadata.mirrorVideo,
encryptionKey: media.encryptionData!.encryptionKey,
encryptionMac: media.encryptionData!.encryptionMac,
encryptionNonce: media.encryptionData!.encryptionNonce,

View file

@ -232,6 +232,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
videoFilePath: videoFilePath,
imageBytes: imageBytes,
sendTo: widget.sendTo,
mirrorVideo: isFront && Platform.isAndroid,
),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return child;

View file

@ -30,11 +30,17 @@ List<Layer> removedLayers = [];
const gMediaShowInfinite = 999999;
class ShareImageEditorView extends StatefulWidget {
const ShareImageEditorView(
{super.key, this.imageBytes, this.sendTo, this.videoFilePath});
const ShareImageEditorView({
super.key,
this.imageBytes,
this.sendTo,
this.videoFilePath,
required this.mirrorVideo,
});
final Future<Uint8List?>? imageBytes;
final XFile? videoFilePath;
final Contact? sendTo;
final bool mirrorVideo;
@override
State<ShareImageEditorView> createState() => _ShareImageEditorView();
}
@ -289,6 +295,7 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
maxShowTime: maxShowTime,
preselectedUser: widget.sendTo,
videoFilePath: widget.videoFilePath,
mirrorVideo: widget.mirrorVideo,
),
),
);
@ -357,6 +364,7 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
maxShowTime,
widget.videoFilePath,
videoWithAudio,
widget.mirrorVideo,
);
if (context.mounted) {
// ignore: use_build_context_synchronously
@ -405,7 +413,12 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
child: Stack(
children: [
if (videoController != null)
Positioned.fill(child: VideoPlayer(videoController!)),
Positioned.fill(
child: Transform.flip(
flipX: widget.mirrorVideo,
child: VideoPlayer(videoController!),
),
),
Screenshot(
controller: screenshotController,
child: LayersViewer(

View file

@ -21,12 +21,14 @@ class ShareImageView extends StatefulWidget {
{super.key,
required this.imageBytesFuture,
required this.isRealTwonly,
required this.mirrorVideo,
required this.maxShowTime,
this.preselectedUser,
required this.videoFilePath,
this.enableVideoAudio});
final Future<Uint8List?> imageBytesFuture;
final bool isRealTwonly;
final bool mirrorVideo;
final int maxShowTime;
final XFile? videoFilePath;
final Contact? preselectedUser;
@ -237,7 +239,9 @@ class _ShareImageView extends State<ShareImageView> {
widget.isRealTwonly,
widget.maxShowTime,
widget.videoFilePath,
widget.enableVideoAudio);
widget.enableVideoAudio,
widget.mirrorVideo,
);
if (context.mounted) {
if (widget.preselectedUser != null) {
Navigator.pop(context, true);

View file

@ -47,6 +47,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
int maxShowTime = 999999;
double progress = 0;
bool isRealTwonly = false;
bool mirrorVideo = false;
bool isDownloading = false;
bool showSendTextMessageInput = false;
@ -120,6 +121,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
maxShowTime = 999999;
imageSaving = false;
imageSaved = false;
mirrorVideo = false;
progress = 0;
isDownloading = false;
isRealTwonly = false;
@ -226,6 +228,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
setState(() {
maxShowTime = content.maxShowTime;
isDownloading = false;
mirrorVideo = content.mirrorVideo;
});
}
@ -412,7 +415,12 @@ class _MediaViewerViewState extends State<MediaViewerView> {
child: Stack(
children: [
if (videoController != null)
Positioned.fill(child: VideoPlayer(videoController!)),
Positioned.fill(
child: Transform.flip(
flipX: mirrorVideo,
child: VideoPlayer(videoController!),
),
),
if (imageBytes != null)
Positioned.fill(
child: Image.memory(