mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-17 03:28:40 +00:00
parent
c460befea5
commit
2bfd50ef8d
3 changed files with 136 additions and 106 deletions
|
|
@ -13,6 +13,7 @@ import 'package:twonly/src/database/tables/media_uploads_table.dart';
|
||||||
import 'package:twonly/src/database/tables/messages_table.dart';
|
import 'package:twonly/src/database/tables/messages_table.dart';
|
||||||
import 'package:twonly/src/database/twonly_database.dart';
|
import 'package:twonly/src/database/twonly_database.dart';
|
||||||
import 'package:twonly/src/model/json/message.dart';
|
import 'package:twonly/src/model/json/message.dart';
|
||||||
|
import 'package:twonly/src/model/protobuf/api/error.pb.dart';
|
||||||
import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart';
|
import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart';
|
||||||
import 'package:twonly/src/providers/api/api.dart';
|
import 'package:twonly/src/providers/api/api.dart';
|
||||||
import 'package:twonly/src/providers/api/api_utils.dart';
|
import 'package:twonly/src/providers/api/api_utils.dart';
|
||||||
|
|
@ -49,7 +50,7 @@ Future sendMediaFile(
|
||||||
await File(videoFilePath.path).rename("$basePath.orginal.mp4");
|
await File(videoFilePath.path).rename("$basePath.orginal.mp4");
|
||||||
}
|
}
|
||||||
await writeMediaFile(mediaUploadId, "orginal.png", imageBytes);
|
await writeMediaFile(mediaUploadId, "orginal.png", imageBytes);
|
||||||
await handleSingleMediaFile(mediaUploadId);
|
await handleSingleMediaFile(mediaUploadId, imageBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,14 +58,15 @@ Future retryMediaUpload() async {
|
||||||
final mediaFiles =
|
final mediaFiles =
|
||||||
await twonlyDatabase.mediaUploadsDao.getMediaUploadsForRetry();
|
await twonlyDatabase.mediaUploadsDao.getMediaUploadsForRetry();
|
||||||
for (final mediaFile in mediaFiles) {
|
for (final mediaFile in mediaFiles) {
|
||||||
await handleSingleMediaFile(mediaFile.mediaUploadId);
|
await handleSingleMediaFile(mediaFile.mediaUploadId, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final lockingHandleMediaFile = Mutex();
|
final lockingHandleMediaFile = Mutex();
|
||||||
|
|
||||||
Future handleSingleMediaFile(int mediaUploadId) async {
|
Future handleSingleMediaFile(
|
||||||
await lockingHandleMediaFile.protect(() async {
|
int mediaUploadId, Uint8List? tmpCurrentImageBytes) async {
|
||||||
|
// await lockingHandleMediaFile.protect(() async {
|
||||||
MediaUpload? media = await twonlyDatabase.mediaUploadsDao
|
MediaUpload? media = await twonlyDatabase.mediaUploadsDao
|
||||||
.getMediaUploadById(mediaUploadId)
|
.getMediaUploadById(mediaUploadId)
|
||||||
.getSingleOrNull();
|
.getSingleOrNull();
|
||||||
|
|
@ -76,10 +78,12 @@ Future handleSingleMediaFile(int mediaUploadId) async {
|
||||||
await handleAddToMessageDb(media);
|
await handleAddToMessageDb(media);
|
||||||
break;
|
break;
|
||||||
case UploadState.addedToMessagesDb:
|
case UploadState.addedToMessagesDb:
|
||||||
await handleCompressionState(media);
|
tmpCurrentImageBytes =
|
||||||
|
await handleCompressionState(media, tmpCurrentImageBytes);
|
||||||
break;
|
break;
|
||||||
case UploadState.isCompressed:
|
case UploadState.isCompressed:
|
||||||
await handleEncryptionState(media);
|
tmpCurrentImageBytes =
|
||||||
|
await handleEncryptionState(media, tmpCurrentImageBytes);
|
||||||
break;
|
break;
|
||||||
case UploadState.isEncrypted:
|
case UploadState.isEncrypted:
|
||||||
if (!await handleGetUploadToken(media)) {
|
if (!await handleGetUploadToken(media)) {
|
||||||
|
|
@ -87,7 +91,7 @@ Future handleSingleMediaFile(int mediaUploadId) async {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case UploadState.hasUploadToken:
|
case UploadState.hasUploadToken:
|
||||||
if (!await handleUpload(media)) {
|
if (!await handleUpload(media, tmpCurrentImageBytes)) {
|
||||||
return; // recoverable error. try again when connected again to the server...
|
return; // recoverable error. try again when connected again to the server...
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -95,6 +99,14 @@ Future handleSingleMediaFile(int mediaUploadId) async {
|
||||||
if (!await handleNotifyReceiver(media)) {
|
if (!await handleNotifyReceiver(media)) {
|
||||||
return; // recoverable error. try again when connected again to the server...
|
return; // recoverable error. try again when connected again to the server...
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
// delete non compressed media files
|
||||||
|
await deleteMediaFile(media, "orginal.png");
|
||||||
|
await deleteMediaFile(media, "orginal.mp4");
|
||||||
|
await deleteMediaFile(media, "encrypted");
|
||||||
|
} catch (e) {
|
||||||
|
Logger("media_send.dart").shout("$e");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case UploadState.receiverNotified:
|
case UploadState.receiverNotified:
|
||||||
return;
|
return;
|
||||||
|
|
@ -116,10 +128,10 @@ Future handleSingleMediaFile(int mediaUploadId) async {
|
||||||
.shout("Non recoverable error while sending media file: $e");
|
.shout("Non recoverable error while sending media file: $e");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
// });
|
||||||
// this will be called until there is an recoverable error OR
|
// this will be called until there is an recoverable error OR
|
||||||
// the upload is ready
|
// the upload is ready
|
||||||
await handleSingleMediaFile(mediaUploadId);
|
await handleSingleMediaFile(mediaUploadId, tmpCurrentImageBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future handleAddToMessageDb(MediaUpload media) async {
|
Future handleAddToMessageDb(MediaUpload media) async {
|
||||||
|
|
@ -168,12 +180,17 @@ Future handleAddToMessageDb(MediaUpload media) async {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future handleCompressionState(MediaUpload media) async {
|
Future<Uint8List?> handleCompressionState(
|
||||||
Uint8List imageBytes = await readMediaFile(media, "orginal.png");
|
MediaUpload media,
|
||||||
|
Uint8List? tmpCurrentImageBytes,
|
||||||
|
) async {
|
||||||
|
Uint8List imageBytes = (tmpCurrentImageBytes != null)
|
||||||
|
? tmpCurrentImageBytes
|
||||||
|
: await readMediaFile(media, "orginal.png");
|
||||||
|
|
||||||
|
Uint8List imageBytesCompressed;
|
||||||
try {
|
try {
|
||||||
Uint8List imageBytesCompressed =
|
imageBytesCompressed = await FlutterImageCompress.compressWithList(
|
||||||
await FlutterImageCompress.compressWithList(
|
|
||||||
format: CompressFormat.png,
|
format: CompressFormat.png,
|
||||||
imageBytes,
|
imageBytes,
|
||||||
quality: 90,
|
quality: 90,
|
||||||
|
|
@ -192,6 +209,7 @@ Future handleCompressionState(MediaUpload media) async {
|
||||||
Logger("media_send.dart").shout("$e");
|
Logger("media_send.dart").shout("$e");
|
||||||
// as a fall back use the orginal image
|
// as a fall back use the orginal image
|
||||||
await writeMediaFile(media.mediaUploadId, "png", imageBytes);
|
await writeMediaFile(media.mediaUploadId, "png", imageBytes);
|
||||||
|
imageBytesCompressed = imageBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media.metadata.isVideo) {
|
if (media.metadata.isVideo) {
|
||||||
|
|
@ -234,10 +252,6 @@ Future handleCompressionState(MediaUpload media) async {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete non compressed media files
|
|
||||||
await deleteMediaFile(media, "orginal.png");
|
|
||||||
await deleteMediaFile(media, "orginal.mp4");
|
|
||||||
|
|
||||||
await twonlyDatabase.mediaUploadsDao.updateMediaUpload(
|
await twonlyDatabase.mediaUploadsDao.updateMediaUpload(
|
||||||
media.mediaUploadId,
|
media.mediaUploadId,
|
||||||
MediaUploadsCompanion(
|
MediaUploadsCompanion(
|
||||||
|
|
@ -245,13 +259,16 @@ Future handleCompressionState(MediaUpload media) async {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return imageBytesCompressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future handleEncryptionState(MediaUpload media) async {
|
Future<Uint8List> handleEncryptionState(
|
||||||
|
MediaUpload media, Uint8List? tmpCurrentImageBytes) async {
|
||||||
var state = MediaEncryptionData();
|
var state = MediaEncryptionData();
|
||||||
|
|
||||||
Uint8List dataToEncrypt = await readMediaFile(media, "png");
|
Uint8List dataToEncrypt = (tmpCurrentImageBytes != null)
|
||||||
|
? tmpCurrentImageBytes
|
||||||
|
: await readMediaFile(media, "png");
|
||||||
|
|
||||||
if (media.metadata.isVideo) {
|
if (media.metadata.isVideo) {
|
||||||
Uint8List compressedVideo = await readMediaFile(media, "mp4");
|
Uint8List compressedVideo = await readMediaFile(media, "mp4");
|
||||||
|
|
@ -275,10 +292,11 @@ Future handleEncryptionState(MediaUpload media) async {
|
||||||
final algorithm = Sha256();
|
final algorithm = Sha256();
|
||||||
state.sha2Hash = (await algorithm.hash(secretBox.cipherText)).bytes;
|
state.sha2Hash = (await algorithm.hash(secretBox.cipherText)).bytes;
|
||||||
|
|
||||||
|
final encryptedBytes = Uint8List.fromList(secretBox.cipherText);
|
||||||
await writeMediaFile(
|
await writeMediaFile(
|
||||||
media.mediaUploadId,
|
media.mediaUploadId,
|
||||||
"encrypted",
|
"encrypted",
|
||||||
Uint8List.fromList(secretBox.cipherText),
|
encryptedBytes,
|
||||||
);
|
);
|
||||||
|
|
||||||
await twonlyDatabase.mediaUploadsDao.updateMediaUpload(
|
await twonlyDatabase.mediaUploadsDao.updateMediaUpload(
|
||||||
|
|
@ -288,6 +306,7 @@ Future handleEncryptionState(MediaUpload media) async {
|
||||||
encryptionData: Value(state),
|
encryptionData: Value(state),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
return encryptedBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> handleGetUploadToken(MediaUpload media) async {
|
Future<bool> handleGetUploadToken(MediaUpload media) async {
|
||||||
|
|
@ -317,8 +336,11 @@ Future<bool> handleGetUploadToken(MediaUpload media) async {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> handleUpload(MediaUpload media) async {
|
Future<bool> handleUpload(
|
||||||
Uint8List bytesToUpload = await readMediaFile(media, "encrypted");
|
MediaUpload media, Uint8List? tmpCurrentImageBytes) async {
|
||||||
|
Uint8List bytesToUpload = (tmpCurrentImageBytes != null)
|
||||||
|
? tmpCurrentImageBytes
|
||||||
|
: await readMediaFile(media, "encrypted");
|
||||||
|
|
||||||
int fragmentedTransportSize = 1000000;
|
int fragmentedTransportSize = 1000000;
|
||||||
|
|
||||||
|
|
@ -345,6 +367,15 @@ Future<bool> handleUpload(MediaUpload media) async {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (wasSend.isError) {
|
if (wasSend.isError) {
|
||||||
|
if (wasSend.error == ErrorCode.InvalidUpdateToken) {
|
||||||
|
await twonlyDatabase.mediaUploadsDao.updateMediaUpload(
|
||||||
|
media.mediaUploadId,
|
||||||
|
MediaUploadsCompanion(
|
||||||
|
state: Value(UploadState.isEncrypted),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return true; // this will trigger a new token request
|
||||||
|
}
|
||||||
Logger("media_send.dart")
|
Logger("media_send.dart")
|
||||||
.shout("error while uploading media: ${wasSend.error}");
|
.shout("error while uploading media: ${wasSend.error}");
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -359,12 +390,6 @@ Future<bool> handleUpload(MediaUpload media) async {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
|
||||||
await deleteMediaFile(media, "encrypted");
|
|
||||||
} catch (e) {
|
|
||||||
Logger("media_send.dart").shout("$e");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,21 +185,21 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
sharePreviewIsShown = true;
|
sharePreviewIsShown = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (useHighQuality && !isFront) {
|
// if (useHighQuality && !isFront) {
|
||||||
if (Platform.isIOS) {
|
// if (Platform.isIOS) {
|
||||||
await controller?.pausePreview();
|
// await controller?.pausePreview();
|
||||||
if (!context.mounted) return;
|
// if (!context.mounted) return;
|
||||||
}
|
// }
|
||||||
try {
|
// try {
|
||||||
// Take the picture
|
// // Take the picture
|
||||||
final XFile? picture = await controller?.takePicture();
|
// final XFile? picture = await controller?.takePicture();
|
||||||
if (picture == null) return;
|
// if (picture == null) return;
|
||||||
imageBytes = loadAndDeletePictureFromFile(picture);
|
// imageBytes = loadAndDeletePictureFromFile(picture);
|
||||||
} catch (e) {
|
// } catch (e) {
|
||||||
_showCameraException(e);
|
// _showCameraException(e);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
if (isFlashOn) {
|
if (isFlashOn) {
|
||||||
if (isFront) {
|
if (isFront) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
@ -216,8 +216,9 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
|
|
||||||
controller?.setFlashMode(isFlashOn ? FlashMode.always : FlashMode.off);
|
controller?.setFlashMode(isFlashOn ? FlashMode.always : FlashMode.off);
|
||||||
imageBytes = screenshotController.capture(
|
imageBytes = screenshotController.capture(
|
||||||
pixelRatio: MediaQuery.of(context).devicePixelRatio);
|
pixelRatio:
|
||||||
}
|
(useHighQuality) ? MediaQuery.of(context).devicePixelRatio : 1);
|
||||||
|
// }
|
||||||
|
|
||||||
if (await pushMediaEditor(imageBytes, null)) {
|
if (await pushMediaEditor(imageBytes, null)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -235,6 +236,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
imageBytes: imageBytes,
|
imageBytes: imageBytes,
|
||||||
sendTo: widget.sendTo,
|
sendTo: widget.sendTo,
|
||||||
mirrorVideo: isFront && Platform.isAndroid,
|
mirrorVideo: isFront && Platform.isAndroid,
|
||||||
|
useHighQuality: useHighQuality,
|
||||||
),
|
),
|
||||||
transitionsBuilder: (context, animation, secondaryAnimation, child) {
|
transitionsBuilder: (context, animation, secondaryAnimation, child) {
|
||||||
return child;
|
return child;
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,13 @@ class ShareImageEditorView extends StatefulWidget {
|
||||||
this.sendTo,
|
this.sendTo,
|
||||||
this.videoFilePath,
|
this.videoFilePath,
|
||||||
required this.mirrorVideo,
|
required this.mirrorVideo,
|
||||||
|
required this.useHighQuality,
|
||||||
});
|
});
|
||||||
final Future<Uint8List?>? imageBytes;
|
final Future<Uint8List?>? imageBytes;
|
||||||
final XFile? videoFilePath;
|
final XFile? videoFilePath;
|
||||||
final Contact? sendTo;
|
final Contact? sendTo;
|
||||||
final bool mirrorVideo;
|
final bool mirrorVideo;
|
||||||
|
final bool useHighQuality;
|
||||||
@override
|
@override
|
||||||
State<ShareImageEditorView> createState() => _ShareImageEditorView();
|
State<ShareImageEditorView> createState() => _ShareImageEditorView();
|
||||||
}
|
}
|
||||||
|
|
@ -318,7 +320,8 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
x.showCustomButtons = false;
|
x.showCustomButtons = false;
|
||||||
}
|
}
|
||||||
setState(() {});
|
setState(() {});
|
||||||
image = await screenshotController.capture(pixelRatio: pixelRatio);
|
image = await screenshotController.capture(
|
||||||
|
pixelRatio: (widget.useHighQuality) ? pixelRatio : 1);
|
||||||
for (var x in layers) {
|
for (var x in layers) {
|
||||||
x.showCustomButtons = true;
|
x.showCustomButtons = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue