mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 16:28:40 +00:00
first poc for #197
This commit is contained in:
parent
d871e04f0e
commit
6677f89a18
7 changed files with 172 additions and 123 deletions
|
|
@ -4,4 +4,6 @@
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
-->
|
-->
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<application android:usesCleartextTraffic="true" >
|
||||||
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,6 @@
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
<string>12.0</string>
|
<string>15.6</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Uncomment this line to define a global platform for your project
|
# Uncomment this line to define a global platform for your project
|
||||||
platform :ios, '13.0'
|
platform :ios, '14.0'
|
||||||
use_frameworks!
|
use_frameworks!
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
PODS:
|
PODS:
|
||||||
|
- background_downloader (0.0.1):
|
||||||
|
- Flutter
|
||||||
- camera_avfoundation (0.0.1):
|
- camera_avfoundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- connectivity_plus (0.0.1):
|
- connectivity_plus (0.0.1):
|
||||||
|
|
@ -223,6 +225,7 @@ PODS:
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
|
- background_downloader (from `.symlinks/plugins/background_downloader/ios`)
|
||||||
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
|
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
|
||||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||||
- Firebase
|
- Firebase
|
||||||
|
|
@ -275,6 +278,8 @@ SPEC REPOS:
|
||||||
- sqlite3
|
- sqlite3
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
|
background_downloader:
|
||||||
|
:path: ".symlinks/plugins/background_downloader/ios"
|
||||||
camera_avfoundation:
|
camera_avfoundation:
|
||||||
:path: ".symlinks/plugins/camera_avfoundation/ios"
|
:path: ".symlinks/plugins/camera_avfoundation/ios"
|
||||||
connectivity_plus:
|
connectivity_plus:
|
||||||
|
|
@ -327,6 +332,7 @@ EXTERNAL SOURCES:
|
||||||
:path: ".symlinks/plugins/video_player_avfoundation/darwin"
|
:path: ".symlinks/plugins/video_player_avfoundation/darwin"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
|
background_downloader: 50e91d979067b82081aba359d7d916b3ba5fadad
|
||||||
camera_avfoundation: be3be85408cd4126f250386828e9b1dfa40ab436
|
camera_avfoundation: be3be85408cd4126f250386828e9b1dfa40ab436
|
||||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||||
Firebase: 1fe1c0a7d9aaea32efe01fbea5f0ebd8d70e53a2
|
Firebase: 1fe1c0a7d9aaea32efe01fbea5f0ebd8d70e53a2
|
||||||
|
|
@ -370,6 +376,6 @@ SPEC CHECKSUMS:
|
||||||
video_compress: f2133a07762889d67f0711ac831faa26f956980e
|
video_compress: f2133a07762889d67f0711ac831faa26f956980e
|
||||||
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
|
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
|
||||||
|
|
||||||
PODFILE CHECKSUM: a6fb5a4d094eb37ff57a33aa854ee613ab378080
|
PODFILE CHECKSUM: 3e94c12f4f6904137d1449e3b100fda499ccd32d
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|
|
||||||
|
|
@ -632,7 +632,7 @@
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = twonly;
|
INFOPLIST_KEY_CFBundleDisplayName = twonly;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
|
|
@ -830,7 +830,7 @@
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = twonly;
|
INFOPLIST_KEY_CFBundleDisplayName = twonly;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
|
|
@ -864,7 +864,7 @@
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = twonly;
|
INFOPLIST_KEY_CFBundleDisplayName = twonly;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import 'dart:isolate';
|
import 'dart:isolate';
|
||||||
|
|
||||||
import 'package:camera/camera.dart';
|
import 'package:camera/camera.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
@ -52,6 +51,8 @@ void main() async {
|
||||||
purgeSendMediaFiles();
|
purgeSendMediaFiles();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await initMediaUploader();
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:isolate';
|
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
import 'package:fixnum/fixnum.dart';
|
import 'package:fixnum/fixnum.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
|
||||||
import 'package:cryptography_plus/cryptography_plus.dart';
|
import 'package:cryptography_plus/cryptography_plus.dart';
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
||||||
|
|
@ -54,6 +52,81 @@ Future<ErrorCode?> isAllowedToSend() async {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future initMediaUploader() async {
|
||||||
|
FileDownloader().updates.listen((update) async {
|
||||||
|
switch (update) {
|
||||||
|
case TaskStatusUpdate():
|
||||||
|
if (update.status == TaskStatus.complete) {
|
||||||
|
int mediaUploadId = int.parse(update.task.taskId);
|
||||||
|
MediaUpload? media = await twonlyDB.mediaUploadsDao
|
||||||
|
.getMediaUploadById(mediaUploadId)
|
||||||
|
.getSingleOrNull();
|
||||||
|
if (media == null) {
|
||||||
|
Log.error(
|
||||||
|
"Got an upload task but no upload media in the mediaupload atabase");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (update.responseStatusCode == 200) {
|
||||||
|
Log.info("Upload was success!");
|
||||||
|
|
||||||
|
await twonlyDB.mediaUploadsDao.updateMediaUpload(
|
||||||
|
mediaUploadId,
|
||||||
|
MediaUploadsCompanion(
|
||||||
|
state: Value(UploadState.receiverNotified),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (final messageId in media.messageIds!) {
|
||||||
|
await twonlyDB.messagesDao.updateMessageByMessageId(
|
||||||
|
messageId,
|
||||||
|
MessagesCompanion(
|
||||||
|
acknowledgeByServer: Value(true),
|
||||||
|
errorWhileSending: Value(false),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (update.responseStatusCode != null) {
|
||||||
|
if (update.responseStatusCode! >= 400 &&
|
||||||
|
update.responseStatusCode! < 500) {
|
||||||
|
for (final messageId in media.messageIds!) {
|
||||||
|
await twonlyDB.messagesDao.updateMessageByMessageId(
|
||||||
|
messageId,
|
||||||
|
MessagesCompanion(
|
||||||
|
acknowledgeByServer: Value(true),
|
||||||
|
errorWhileSending: Value(true),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.error(
|
||||||
|
"Got error while uploading: ${update.responseStatusCode}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print('Status update for ${update.task} with status ${update.status}');
|
||||||
|
case TaskProgressUpdate():
|
||||||
|
print(
|
||||||
|
'Progress update for ${update.task} with progress ${update.progress}');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await FileDownloader().start();
|
||||||
|
|
||||||
|
FileDownloader().configure(androidConfig: [
|
||||||
|
(Config.bypassTLSCertificateValidation, kDebugMode),
|
||||||
|
]);
|
||||||
|
|
||||||
|
FileDownloader().configureNotification(
|
||||||
|
running: TaskNotification(
|
||||||
|
'Uploading',
|
||||||
|
'Uploading your {filename} ({progress}).',
|
||||||
|
),
|
||||||
|
complete: null,
|
||||||
|
progressBar: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// States:
|
/// States:
|
||||||
/// when user recorded an video
|
/// when user recorded an video
|
||||||
/// 1. Compress video
|
/// 1. Compress video
|
||||||
|
|
@ -172,11 +245,11 @@ Future<Uint8List> addOrModifyImageToUpload(
|
||||||
quality: 60,
|
quality: 60,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await writeMediaFile(mediaUploadId, "png", imageBytesCompressed);
|
await writeSendMediaFile(mediaUploadId, "png", imageBytesCompressed);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error("$e");
|
Log.error("$e");
|
||||||
// as a fall back use the original image
|
// as a fall back use the original image
|
||||||
await writeMediaFile(mediaUploadId, "png", imageBytes);
|
await writeSendMediaFile(mediaUploadId, "png", imageBytes);
|
||||||
imageBytesCompressed = imageBytes;
|
imageBytesCompressed = imageBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,7 +266,7 @@ Future<Uint8List> addOrModifyImageToUpload(
|
||||||
|
|
||||||
Future handlePreProcessingState(MediaUpload media) async {
|
Future handlePreProcessingState(MediaUpload media) async {
|
||||||
try {
|
try {
|
||||||
final imageHandler = readMediaFile(media.mediaUploadId, "png");
|
final imageHandler = readSendMediaFile(media.mediaUploadId, "png");
|
||||||
final videoHandler = compressVideoIfExists(media.mediaUploadId);
|
final videoHandler = compressVideoIfExists(media.mediaUploadId);
|
||||||
await encryptMediaFiles(
|
await encryptMediaFiles(
|
||||||
media.mediaUploadId,
|
media.mediaUploadId,
|
||||||
|
|
@ -217,7 +290,7 @@ Future encryptMediaFiles(
|
||||||
/// if there is a video wait until it is finished with compression
|
/// if there is a video wait until it is finished with compression
|
||||||
if (videoHandler != null) {
|
if (videoHandler != null) {
|
||||||
if (await videoHandler) {
|
if (await videoHandler) {
|
||||||
Uint8List compressedVideo = await readMediaFile(mediaUploadId, "mp4");
|
Uint8List compressedVideo = await readSendMediaFile(mediaUploadId, "mp4");
|
||||||
dataToEncrypt = combineUint8Lists(dataToEncrypt, compressedVideo);
|
dataToEncrypt = combineUint8Lists(dataToEncrypt, compressedVideo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -230,12 +303,10 @@ Future encryptMediaFiles(
|
||||||
state.encryptionKey = secretKey.bytes;
|
state.encryptionKey = secretKey.bytes;
|
||||||
state.encryptionNonce = xchacha20.newNonce();
|
state.encryptionNonce = xchacha20.newNonce();
|
||||||
|
|
||||||
final secretBox = await Isolate.run(
|
final secretBox = await xchacha20.encrypt(
|
||||||
() => xchacha20.encrypt(
|
|
||||||
dataToEncrypt,
|
dataToEncrypt,
|
||||||
secretKey: secretKey,
|
secretKey: secretKey,
|
||||||
nonce: state.encryptionNonce,
|
nonce: state.encryptionNonce,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
state.encryptionMac = secretBox.mac.bytes;
|
state.encryptionMac = secretBox.mac.bytes;
|
||||||
|
|
@ -244,7 +315,7 @@ Future encryptMediaFiles(
|
||||||
state.sha2Hash = (await algorithm.hash(secretBox.cipherText)).bytes;
|
state.sha2Hash = (await algorithm.hash(secretBox.cipherText)).bytes;
|
||||||
|
|
||||||
final encryptedBytes = Uint8List.fromList(secretBox.cipherText);
|
final encryptedBytes = Uint8List.fromList(secretBox.cipherText);
|
||||||
await writeMediaFile(
|
await writeSendMediaFile(
|
||||||
mediaUploadId,
|
mediaUploadId,
|
||||||
"encrypted",
|
"encrypted",
|
||||||
encryptedBytes,
|
encryptedBytes,
|
||||||
|
|
@ -376,7 +447,7 @@ Future handleUploadError(MediaUpload mediaUpload) async {
|
||||||
|
|
||||||
Future<bool> handleMediaUpload(MediaUpload media) async {
|
Future<bool> handleMediaUpload(MediaUpload media) async {
|
||||||
Uint8List bytesToUpload =
|
Uint8List bytesToUpload =
|
||||||
await readMediaFile(media.mediaUploadId, "encrypted");
|
await readSendMediaFile(media.mediaUploadId, "encrypted");
|
||||||
|
|
||||||
if (media.messageIds == null) return false;
|
if (media.messageIds == null) return false;
|
||||||
|
|
||||||
|
|
@ -456,63 +527,33 @@ Future<bool> handleMediaUpload(MediaUpload media) async {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File uploadRequestFile = await writeSendMediaFile(
|
||||||
|
media.mediaUploadId,
|
||||||
|
"upload",
|
||||||
|
uploadRequestBytes,
|
||||||
|
);
|
||||||
|
|
||||||
String apiUrl =
|
String apiUrl =
|
||||||
"http${apiService.apiSecure}://${apiService.apiHost}/api/upload";
|
"http${apiService.apiSecure}://${apiService.apiHost}/api/upload";
|
||||||
|
|
||||||
var requestMultipart = http.MultipartRequest(
|
try {
|
||||||
"POST",
|
final task = UploadTask.fromFile(
|
||||||
Uri.parse(apiUrl),
|
taskId: "${media.mediaUploadId}",
|
||||||
|
displayName: (media.metadata?.isVideo ?? false) ? "image" : "video",
|
||||||
|
file: uploadRequestFile,
|
||||||
|
url: apiUrl,
|
||||||
|
priority: 0,
|
||||||
|
retries: 10,
|
||||||
|
headers: {
|
||||||
|
'x-twonly-auth-token': uint8ListToHex(base64Decode(apiAuthToken))
|
||||||
|
},
|
||||||
);
|
);
|
||||||
requestMultipart.headers['x-twonly-auth-token'] =
|
|
||||||
uint8ListToHex(base64Decode(apiAuthToken));
|
|
||||||
|
|
||||||
requestMultipart.files.add(http.MultipartFile.fromBytes(
|
|
||||||
"file",
|
|
||||||
uploadRequestBytes,
|
|
||||||
filename: "upload",
|
|
||||||
));
|
|
||||||
|
|
||||||
Log.info("Starting upload from ${media.mediaUploadId}");
|
Log.info("Starting upload from ${media.mediaUploadId}");
|
||||||
|
|
||||||
try {
|
final result = await FileDownloader().enqueue(task);
|
||||||
var streamedResponse = await requestMultipart.send();
|
|
||||||
|
|
||||||
final response = await http.Response.fromStream(streamedResponse);
|
return result;
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
Log.info("Upload was success!");
|
|
||||||
|
|
||||||
await twonlyDB.mediaUploadsDao.updateMediaUpload(
|
|
||||||
media.mediaUploadId,
|
|
||||||
MediaUploadsCompanion(
|
|
||||||
state: Value(UploadState.receiverNotified),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
for (final messageId in media.messageIds!) {
|
|
||||||
await twonlyDB.messagesDao.updateMessageByMessageId(
|
|
||||||
messageId,
|
|
||||||
MessagesCompanion(
|
|
||||||
acknowledgeByServer: Value(true),
|
|
||||||
errorWhileSending: Value(false),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
if (response.statusCode >= 400 && response.statusCode < 500) {
|
|
||||||
for (final messageId in media.messageIds!) {
|
|
||||||
await twonlyDB.messagesDao.updateMessageByMessageId(
|
|
||||||
messageId,
|
|
||||||
MessagesCompanion(
|
|
||||||
acknowledgeByServer: Value(true),
|
|
||||||
errorWhileSending: Value(true),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.error("Got error while uploading: ${response.statusCode}");
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error("Exception during upload: $e");
|
Log.error("Exception during upload: $e");
|
||||||
}
|
}
|
||||||
|
|
@ -534,7 +575,6 @@ Future<bool> compressVideoIfExists(int mediaUploadId) async {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await Isolate.run(() async {
|
|
||||||
MediaInfo? mediaInfo;
|
MediaInfo? mediaInfo;
|
||||||
try {
|
try {
|
||||||
mediaInfo = await VideoCompress.compressVideo(
|
mediaInfo = await VideoCompress.compressVideo(
|
||||||
|
|
@ -568,12 +608,11 @@ Future<bool> compressVideoIfExists(int mediaUploadId) async {
|
||||||
await mediaInfo.file!.delete();
|
await mediaInfo.file!.delete();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// --- helper functions ---
|
/// --- helper functions ---
|
||||||
|
|
||||||
Future<Uint8List> readMediaFile(int mediaUploadId, String type) async {
|
Future<Uint8List> readSendMediaFile(int mediaUploadId, String type) async {
|
||||||
String basePath = await getMediaFilePath(mediaUploadId, "send");
|
String basePath = await getMediaFilePath(mediaUploadId, "send");
|
||||||
File file = File("$basePath.$type");
|
File file = File("$basePath.$type");
|
||||||
if (!await file.exists()) {
|
if (!await file.exists()) {
|
||||||
|
|
@ -582,14 +621,15 @@ Future<Uint8List> readMediaFile(int mediaUploadId, String type) async {
|
||||||
return await file.readAsBytes();
|
return await file.readAsBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> writeMediaFile(
|
Future<File> writeSendMediaFile(
|
||||||
int mediaUploadId, String type, Uint8List data) async {
|
int mediaUploadId, String type, Uint8List data) async {
|
||||||
String basePath = await getMediaFilePath(mediaUploadId, "send");
|
String basePath = await getMediaFilePath(mediaUploadId, "send");
|
||||||
File file = File("$basePath.$type");
|
File file = File("$basePath.$type");
|
||||||
await file.writeAsBytes(data);
|
await file.writeAsBytes(data);
|
||||||
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteMediaFile(int mediaUploadId, String type) async {
|
Future<void> deleteSendMediaFile(int mediaUploadId, String type) async {
|
||||||
String basePath = await getMediaFilePath(mediaUploadId, "send");
|
String basePath = await getMediaFilePath(mediaUploadId, "send");
|
||||||
File file = File("$basePath.$type");
|
File file = File("$basePath.$type");
|
||||||
if (await file.exists()) {
|
if (await file.exists()) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue