Fix uploaded assets getting deleted and fix new audio messages loading wrong file
This commit is contained in:
parent
c368fb6fe5
commit
9ab4774f34
5 changed files with 80 additions and 37 deletions
|
@ -141,6 +141,7 @@ class RecordApi {
|
||||||
filename: filename,
|
filename: filename,
|
||||||
thumbnailUri: imageDigest.dbUri,
|
thumbnailUri: imageDigest.dbUri,
|
||||||
digests: digests,
|
digests: digests,
|
||||||
|
extraTags: ["image"],
|
||||||
);
|
);
|
||||||
progressCallback?.call(.1);
|
progressCallback?.call(.1);
|
||||||
final status = await tryPreprocessRecord(client, record: record);
|
final status = await tryPreprocessRecord(client, record: record);
|
||||||
|
@ -151,6 +152,7 @@ class RecordApi {
|
||||||
client,
|
client,
|
||||||
assets: digests.where((digest) => toUpload.any((diff) => digest.asset.hash == diff.hash)).toList(),
|
assets: digests.where((digest) => toUpload.any((diff) => digest.asset.hash == diff.hash)).toList(),
|
||||||
progressCallback: (progress) => progressCallback?.call(.2 + progress * .6));
|
progressCallback: (progress) => progressCallback?.call(.2 + progress * .6));
|
||||||
|
await upsertRecord(client, record: record);
|
||||||
progressCallback?.call(1);
|
progressCallback?.call(1);
|
||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
@ -170,6 +172,7 @@ class RecordApi {
|
||||||
filename: filename,
|
filename: filename,
|
||||||
thumbnailUri: "",
|
thumbnailUri: "",
|
||||||
digests: digests,
|
digests: digests,
|
||||||
|
extraTags: ["voice", "message"],
|
||||||
);
|
);
|
||||||
progressCallback?.call(.1);
|
progressCallback?.call(.1);
|
||||||
final status = await tryPreprocessRecord(client, record: record);
|
final status = await tryPreprocessRecord(client, record: record);
|
||||||
|
@ -180,6 +183,7 @@ class RecordApi {
|
||||||
client,
|
client,
|
||||||
assets: digests.where((digest) => toUpload.any((diff) => digest.asset.hash == diff.hash)).toList(),
|
assets: digests.where((digest) => toUpload.any((diff) => digest.asset.hash == diff.hash)).toList(),
|
||||||
progressCallback: (progress) => progressCallback?.call(.2 + progress * .6));
|
progressCallback: (progress) => progressCallback?.call(.2 + progress * .6));
|
||||||
|
await upsertRecord(client, record: record);
|
||||||
progressCallback?.call(1);
|
progressCallback?.call(1);
|
||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
@ -203,6 +207,7 @@ class RecordApi {
|
||||||
filename: fileDigest.name,
|
filename: fileDigest.name,
|
||||||
thumbnailUri: JsonTemplate.thumbUrl,
|
thumbnailUri: JsonTemplate.thumbUrl,
|
||||||
digests: digests,
|
digests: digests,
|
||||||
|
extraTags: ["document"],
|
||||||
);
|
);
|
||||||
progressCallback?.call(.1);
|
progressCallback?.call(.1);
|
||||||
final status = await tryPreprocessRecord(client, record: record);
|
final status = await tryPreprocessRecord(client, record: record);
|
||||||
|
@ -213,6 +218,7 @@ class RecordApi {
|
||||||
client,
|
client,
|
||||||
assets: digests.where((digest) => toUpload.any((diff) => digest.asset.hash == diff.hash)).toList(),
|
assets: digests.where((digest) => toUpload.any((diff) => digest.asset.hash == diff.hash)).toList(),
|
||||||
progressCallback: (progress) => progressCallback?.call(.2 + progress * .6));
|
progressCallback: (progress) => progressCallback?.call(.2 + progress * .6));
|
||||||
|
await upsertRecord(client, record: record);
|
||||||
progressCallback?.call(1);
|
progressCallback?.call(1);
|
||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@ class Record {
|
||||||
required String filename,
|
required String filename,
|
||||||
required String thumbnailUri,
|
required String thumbnailUri,
|
||||||
required List<AssetDigest> digests,
|
required List<AssetDigest> digests,
|
||||||
|
List<String>? extraTags,
|
||||||
}) {
|
}) {
|
||||||
final combinedRecordId = RecordId(id: Record.generateId(), ownerId: userId, isValid: true);
|
final combinedRecordId = RecordId(id: Record.generateId(), ownerId: userId, isValid: true);
|
||||||
return Record(
|
return Record(
|
||||||
|
@ -118,11 +119,12 @@ class Record {
|
||||||
combinedRecordId: combinedRecordId,
|
combinedRecordId: combinedRecordId,
|
||||||
assetUri: assetUri,
|
assetUri: assetUri,
|
||||||
name: filename,
|
name: filename,
|
||||||
tags: [
|
tags: ([
|
||||||
filename,
|
filename,
|
||||||
"message_item",
|
"message_item",
|
||||||
"message_id:${Message.generateId()}"
|
"message_id:${Message.generateId()}",
|
||||||
],
|
"contacts-plus-plus"
|
||||||
|
] + (extraTags ?? [])).unique(),
|
||||||
recordType: recordType,
|
recordType: recordType,
|
||||||
thumbnailUri: thumbnailUri,
|
thumbnailUri: thumbnailUri,
|
||||||
isPublic: false,
|
isPublic: false,
|
||||||
|
|
|
@ -20,39 +20,46 @@ class MessageAsset extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final content = jsonDecode(message.content);
|
final content = jsonDecode(message.content);
|
||||||
PhotoAsset? photoAsset;
|
|
||||||
try {
|
|
||||||
photoAsset = PhotoAsset.fromTags((content["tags"] as List).map((e) => "$e").toList());
|
|
||||||
} catch (_) {}
|
|
||||||
final formattedName = FormatNode.fromText(content["name"]);
|
final formattedName = FormatNode.fromText(content["name"]);
|
||||||
return Container(
|
return Container(
|
||||||
constraints: const BoxConstraints(maxWidth: 300),
|
constraints: const BoxConstraints(maxWidth: 300),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
CachedNetworkImage(
|
SizedBox(
|
||||||
imageUrl: Aux.neosDbToHttp(content["thumbnailUri"]),
|
height: 256,
|
||||||
imageBuilder: (context, image) {
|
width: double.infinity,
|
||||||
return InkWell(
|
child: CachedNetworkImage(
|
||||||
onTap: () async {
|
imageUrl: Aux.neosDbToHttp(content["thumbnailUri"]),
|
||||||
await Navigator.push(
|
imageBuilder: (context, image) {
|
||||||
context, MaterialPageRoute(builder: (context) =>
|
return InkWell(
|
||||||
PhotoView(
|
onTap: () async {
|
||||||
minScale: PhotoViewComputedScale.contained,
|
PhotoAsset? photoAsset;
|
||||||
imageProvider: photoAsset == null
|
try {
|
||||||
? image
|
photoAsset = PhotoAsset.fromTags((content["tags"] as List).map((e) => "$e").toList());
|
||||||
: CachedNetworkImageProvider(Aux.neosDbToHttp(photoAsset.imageUri)),
|
} catch (_) {}
|
||||||
heroAttributes: PhotoViewHeroAttributes(tag: message.id),
|
await Navigator.push(
|
||||||
),
|
context, MaterialPageRoute(builder: (context) =>
|
||||||
),);
|
PhotoView(
|
||||||
},
|
minScale: PhotoViewComputedScale.contained,
|
||||||
child: Hero(
|
imageProvider: photoAsset == null
|
||||||
tag: message.id,
|
? image
|
||||||
child: ClipRRect(borderRadius: BorderRadius.circular(16), child: Image(image: image,)),
|
: CachedNetworkImageProvider(Aux.neosDbToHttp(photoAsset.imageUri)),
|
||||||
),
|
heroAttributes: PhotoViewHeroAttributes(tag: message.id),
|
||||||
);
|
),
|
||||||
},
|
),);
|
||||||
errorWidget: (context, url, error) => const Icon(Icons.image_not_supported, size: 128,),
|
},
|
||||||
placeholder: (context, uri) => const CircularProgressIndicator(),
|
child: Hero(
|
||||||
|
tag: message.id,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
child: Image(image: image, fit: BoxFit.cover,),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
errorWidget: (context, url, error) => const Icon(Icons.broken_image, size: 64,),
|
||||||
|
placeholder: (context, uri) => const Center(child: CircularProgressIndicator()),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8,),
|
const SizedBox(height: 8,),
|
||||||
Row(
|
Row(
|
||||||
|
|
|
@ -45,6 +45,14 @@ class _MessageAudioPlayerState extends State<MessageAudioPlayer> with WidgetsBin
|
||||||
.then((value) => _audioPlayer.setFilePath(value.path)).whenComplete(() => _audioPlayer.setLoopMode(LoopMode.off));
|
.then((value) => _audioPlayer.setFilePath(value.path)).whenComplete(() => _audioPlayer.setLoopMode(LoopMode.off));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(covariant MessageAudioPlayer oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
final audioCache = Provider.of<AudioCacheClient>(context);
|
||||||
|
_audioFileFuture = audioCache.cachedNetworkAudioFile(AudioClipContent.fromMap(jsonDecode(widget.message.content)))
|
||||||
|
.then((value) => _audioPlayer.setFilePath(value.path)).whenComplete(() => _audioPlayer.setLoopMode(LoopMode.off));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
|
|
|
@ -47,6 +47,13 @@ class _MessageInputBarState extends State<MessageInputBar> {
|
||||||
set _isRecording(value) => _recordingStartTime = value ? DateTime.now() : null;
|
set _isRecording(value) => _recordingStartTime = value ? DateTime.now() : null;
|
||||||
bool _recordingCancelled = false;
|
bool _recordingCancelled = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_recorder.dispose();
|
||||||
|
_messageTextController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> sendTextMessage(ApiClient client, MessagingClient mClient, String content) async {
|
Future<void> sendTextMessage(ApiClient client, MessagingClient mClient, String content) async {
|
||||||
if (content.isEmpty) return;
|
if (content.isEmpty) return;
|
||||||
final message = Message(
|
final message = Message(
|
||||||
|
@ -160,7 +167,6 @@ class _MessageInputBarState extends State<MessageInputBar> {
|
||||||
if (_isRecording) {
|
if (_isRecording) {
|
||||||
if (_recordingCancelled) {
|
if (_recordingCancelled) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_recordingCancelled = false;
|
|
||||||
_isRecording = false;
|
_isRecording = false;
|
||||||
});
|
});
|
||||||
final recording = await _recorder.stop();
|
final recording = await _recorder.stop();
|
||||||
|
@ -319,7 +325,9 @@ class _MessageInputBarState extends State<MessageInputBar> {
|
||||||
),
|
),
|
||||||
child: switch((_attachmentPickerOpen, _isRecording)) {
|
child: switch((_attachmentPickerOpen, _isRecording)) {
|
||||||
(_, true) => IconButton(
|
(_, true) => IconButton(
|
||||||
onPressed: () {},
|
onPressed: () {
|
||||||
|
|
||||||
|
},
|
||||||
icon: Icon(Icons.delete, color: _recordingCancelled ? Theme.of(context).colorScheme.error : null,),
|
icon: Icon(Icons.delete, color: _recordingCancelled ? Theme.of(context).colorScheme.error : null,),
|
||||||
),
|
),
|
||||||
(false, _) => IconButton(
|
(false, _) => IconButton(
|
||||||
|
@ -513,13 +521,25 @@ class _MessageInputBarState extends State<MessageInputBar> {
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.send),
|
icon: const Icon(Icons.send),
|
||||||
) : GestureDetector(
|
) : GestureDetector(
|
||||||
|
onTapUp: (_) {
|
||||||
|
_recordingCancelled = true;
|
||||||
|
},
|
||||||
onTapDown: widget.disabled ? null : (_) async {
|
onTapDown: widget.disabled ? null : (_) async {
|
||||||
HapticFeedback.vibrate();
|
HapticFeedback.vibrate();
|
||||||
|
if (!await _recorder.hasPermission()) {
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content: Text("No permission to record audio."),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final dir = await getTemporaryDirectory();
|
final dir = await getTemporaryDirectory();
|
||||||
await _recorder.start(
|
await _recorder.start(
|
||||||
path: "${dir.path}/A-${const Uuid().v4()}.ogg",
|
path: "${dir.path}/A-${const Uuid().v4()}.wav",
|
||||||
encoder: AudioEncoder.opus,
|
encoder: AudioEncoder.wav,
|
||||||
samplingRate: 44100,
|
samplingRate: 44100
|
||||||
);
|
);
|
||||||
setState(() {
|
setState(() {
|
||||||
_isRecording = true;
|
_isRecording = true;
|
||||||
|
@ -527,7 +547,7 @@ class _MessageInputBarState extends State<MessageInputBar> {
|
||||||
},
|
},
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: const Icon(Icons.mic_outlined),
|
icon: const Icon(Icons.mic_outlined),
|
||||||
onPressed: () {
|
onPressed: _isSending ? null : () {
|
||||||
// Empty onPressed for that sweet sweet ripple effect
|
// Empty onPressed for that sweet sweet ripple effect
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue