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,
|
||||
thumbnailUri: imageDigest.dbUri,
|
||||
digests: digests,
|
||||
extraTags: ["image"],
|
||||
);
|
||||
progressCallback?.call(.1);
|
||||
final status = await tryPreprocessRecord(client, record: record);
|
||||
|
@ -151,6 +152,7 @@ class RecordApi {
|
|||
client,
|
||||
assets: digests.where((digest) => toUpload.any((diff) => digest.asset.hash == diff.hash)).toList(),
|
||||
progressCallback: (progress) => progressCallback?.call(.2 + progress * .6));
|
||||
await upsertRecord(client, record: record);
|
||||
progressCallback?.call(1);
|
||||
return record;
|
||||
}
|
||||
|
@ -170,6 +172,7 @@ class RecordApi {
|
|||
filename: filename,
|
||||
thumbnailUri: "",
|
||||
digests: digests,
|
||||
extraTags: ["voice", "message"],
|
||||
);
|
||||
progressCallback?.call(.1);
|
||||
final status = await tryPreprocessRecord(client, record: record);
|
||||
|
@ -180,6 +183,7 @@ class RecordApi {
|
|||
client,
|
||||
assets: digests.where((digest) => toUpload.any((diff) => digest.asset.hash == diff.hash)).toList(),
|
||||
progressCallback: (progress) => progressCallback?.call(.2 + progress * .6));
|
||||
await upsertRecord(client, record: record);
|
||||
progressCallback?.call(1);
|
||||
return record;
|
||||
}
|
||||
|
@ -203,6 +207,7 @@ class RecordApi {
|
|||
filename: fileDigest.name,
|
||||
thumbnailUri: JsonTemplate.thumbUrl,
|
||||
digests: digests,
|
||||
extraTags: ["document"],
|
||||
);
|
||||
progressCallback?.call(.1);
|
||||
final status = await tryPreprocessRecord(client, record: record);
|
||||
|
@ -213,6 +218,7 @@ class RecordApi {
|
|||
client,
|
||||
assets: digests.where((digest) => toUpload.any((diff) => digest.asset.hash == diff.hash)).toList(),
|
||||
progressCallback: (progress) => progressCallback?.call(.2 + progress * .6));
|
||||
await upsertRecord(client, record: record);
|
||||
progressCallback?.call(1);
|
||||
return record;
|
||||
}
|
||||
|
|
|
@ -111,6 +111,7 @@ class Record {
|
|||
required String filename,
|
||||
required String thumbnailUri,
|
||||
required List<AssetDigest> digests,
|
||||
List<String>? extraTags,
|
||||
}) {
|
||||
final combinedRecordId = RecordId(id: Record.generateId(), ownerId: userId, isValid: true);
|
||||
return Record(
|
||||
|
@ -118,11 +119,12 @@ class Record {
|
|||
combinedRecordId: combinedRecordId,
|
||||
assetUri: assetUri,
|
||||
name: filename,
|
||||
tags: [
|
||||
tags: ([
|
||||
filename,
|
||||
"message_item",
|
||||
"message_id:${Message.generateId()}"
|
||||
],
|
||||
"message_id:${Message.generateId()}",
|
||||
"contacts-plus-plus"
|
||||
] + (extraTags ?? [])).unique(),
|
||||
recordType: recordType,
|
||||
thumbnailUri: thumbnailUri,
|
||||
isPublic: false,
|
||||
|
|
|
@ -20,39 +20,46 @@ class MessageAsset extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
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"]);
|
||||
return Container(
|
||||
constraints: const BoxConstraints(maxWidth: 300),
|
||||
child: Column(
|
||||
children: [
|
||||
CachedNetworkImage(
|
||||
imageUrl: Aux.neosDbToHttp(content["thumbnailUri"]),
|
||||
imageBuilder: (context, image) {
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
await Navigator.push(
|
||||
context, MaterialPageRoute(builder: (context) =>
|
||||
PhotoView(
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
imageProvider: photoAsset == null
|
||||
? image
|
||||
: CachedNetworkImageProvider(Aux.neosDbToHttp(photoAsset.imageUri)),
|
||||
heroAttributes: PhotoViewHeroAttributes(tag: message.id),
|
||||
),
|
||||
),);
|
||||
},
|
||||
child: Hero(
|
||||
tag: message.id,
|
||||
child: ClipRRect(borderRadius: BorderRadius.circular(16), child: Image(image: image,)),
|
||||
),
|
||||
);
|
||||
},
|
||||
errorWidget: (context, url, error) => const Icon(Icons.image_not_supported, size: 128,),
|
||||
placeholder: (context, uri) => const CircularProgressIndicator(),
|
||||
SizedBox(
|
||||
height: 256,
|
||||
width: double.infinity,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: Aux.neosDbToHttp(content["thumbnailUri"]),
|
||||
imageBuilder: (context, image) {
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
PhotoAsset? photoAsset;
|
||||
try {
|
||||
photoAsset = PhotoAsset.fromTags((content["tags"] as List).map((e) => "$e").toList());
|
||||
} catch (_) {}
|
||||
await Navigator.push(
|
||||
context, MaterialPageRoute(builder: (context) =>
|
||||
PhotoView(
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
imageProvider: photoAsset == null
|
||||
? image
|
||||
: CachedNetworkImageProvider(Aux.neosDbToHttp(photoAsset.imageUri)),
|
||||
heroAttributes: PhotoViewHeroAttributes(tag: message.id),
|
||||
),
|
||||
),);
|
||||
},
|
||||
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,),
|
||||
Row(
|
||||
|
|
|
@ -45,6 +45,14 @@ class _MessageAudioPlayerState extends State<MessageAudioPlayer> with WidgetsBin
|
|||
.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
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
|
|
|
@ -47,6 +47,13 @@ class _MessageInputBarState extends State<MessageInputBar> {
|
|||
set _isRecording(value) => _recordingStartTime = value ? DateTime.now() : null;
|
||||
bool _recordingCancelled = false;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_recorder.dispose();
|
||||
_messageTextController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> sendTextMessage(ApiClient client, MessagingClient mClient, String content) async {
|
||||
if (content.isEmpty) return;
|
||||
final message = Message(
|
||||
|
@ -160,7 +167,6 @@ class _MessageInputBarState extends State<MessageInputBar> {
|
|||
if (_isRecording) {
|
||||
if (_recordingCancelled) {
|
||||
setState(() {
|
||||
_recordingCancelled = false;
|
||||
_isRecording = false;
|
||||
});
|
||||
final recording = await _recorder.stop();
|
||||
|
@ -319,7 +325,9 @@ class _MessageInputBarState extends State<MessageInputBar> {
|
|||
),
|
||||
child: switch((_attachmentPickerOpen, _isRecording)) {
|
||||
(_, true) => IconButton(
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
|
||||
},
|
||||
icon: Icon(Icons.delete, color: _recordingCancelled ? Theme.of(context).colorScheme.error : null,),
|
||||
),
|
||||
(false, _) => IconButton(
|
||||
|
@ -513,13 +521,25 @@ class _MessageInputBarState extends State<MessageInputBar> {
|
|||
},
|
||||
icon: const Icon(Icons.send),
|
||||
) : GestureDetector(
|
||||
onTapUp: (_) {
|
||||
_recordingCancelled = true;
|
||||
},
|
||||
onTapDown: widget.disabled ? null : (_) async {
|
||||
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();
|
||||
await _recorder.start(
|
||||
path: "${dir.path}/A-${const Uuid().v4()}.ogg",
|
||||
encoder: AudioEncoder.opus,
|
||||
samplingRate: 44100,
|
||||
path: "${dir.path}/A-${const Uuid().v4()}.wav",
|
||||
encoder: AudioEncoder.wav,
|
||||
samplingRate: 44100
|
||||
);
|
||||
setState(() {
|
||||
_isRecording = true;
|
||||
|
@ -527,7 +547,7 @@ class _MessageInputBarState extends State<MessageInputBar> {
|
|||
},
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.mic_outlined),
|
||||
onPressed: () {
|
||||
onPressed: _isSending ? null : () {
|
||||
// Empty onPressed for that sweet sweet ripple effect
|
||||
},
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue