Compare commits

...

4 Commits

10 changed files with 137 additions and 17 deletions

View File

@ -37,6 +37,19 @@
"startTlsFailed": "Failed to establish a secure connection",
"noConnection": "Failed to establish a connection",
"unspecified": "Unspecified error"
},
"message": {
"unspecified": "Unknown error",
"fileUploadFailed": "The file upload failed",
"contactDoesntSupportOmemo": "The contact does not support encryption using OMEMO:2",
"fileDownloadFailed": "The file download failed",
"serviceUnavailable": "The message could not be delivered to the contact",
"remoteServerTimeout": "The message could not be delivered to the contact's server",
"remoteServerNotFound": "The message could not be delivered to the contact's server as it cannot be found",
"failedToEncrypt": "The message could not be encrypted",
"failedToEncryptFile": "The file could not be encrypted",
"failedToDecryptFile": "The file could not be decrypted",
"fileNotEncrypted": "The chat is encrypted but the file is not encrypted"
}
},
"warnings": {

View File

@ -37,6 +37,19 @@
"startTlsFailed": "Konnte keine sichere Verbindung zum Server aufbauen",
"noConnection": "Konnte keine Verbindung zum Server aufbauen",
"unspecified": "Unbestimmter Fehler"
},
"message": {
"unspecified": "Unbekannter Fehler",
"fileUploadFailed": "Das Hochladen der Datei ist fehlgeschlagen",
"contactDoesntSupportOmemo": "Der Kontakt unterstützt Verschlüsselung mit OMEMO:2 nicht",
"fileDownloadFailed": "Das Herunterladen der Datei ist fehlgeschlagen",
"serviceUnavailable": "Die Nachricht konnte nicht gesendet werden",
"remoteServerTimeout": "Die Nachricht konnte nicht zugestellt werden",
"remoteServerNotFound": "Die Nachricht konnte nicht gesendet werden, da der Empfängerserver unbekannt ist",
"failedToEncrypt": "Die Nachricht konnte nicht verschlüsselt werden",
"failedToEncryptFile": "Die Datei konnte nicht verschlüsselt werden",
"failedToDecryptFile": "Die Datei konnte nicht entschlüsselt werden",
"fileNotEncrypted": "Der Chat ist verschlüsselt, aber die Datei wurde unverschlüsselt übertragen"
}
},
"warnings": {

View File

@ -776,6 +776,50 @@ class XmppService {
&& await _automaticFileDownloadAllowed()
&& await GetIt.I.get<RosterService>().isInRoster(conversationJid);
}
/// Handles receiving a message stanza of type error.
Future<void> _handleErrorMessage(MessageEvent event) async {
if (event.error == null) {
_log.warning('Received error for message ${event.sid} without an error element');
return;
}
final ms = GetIt.I.get<MessageService>();
final msg = await ms.getMessageByStanzaId(
event.fromJid.toBare().toString(),
event.sid,
);
if (msg == null) {
_log.warning('Received error for message ${event.sid} we cannot find');
return;
}
int error;
switch (event.error!.error) {
case 'service-unavailable':
error = messageServiceUnavailable;
break;
case 'remote-server-timeout':
error = messageRemoteServerTimeout;
break;
case 'remote-server-not-found':
error = messageRemoteServerNotFound;
break;
default:
error = unspecifiedError;
break;
}
final newMsg = await ms.updateMessage(
msg.id,
errorType: error,
);
// TODO(PapaTutuWawa): Show a notification for certain error types, i.e. those
// that mean that the message could not be delivered.
sendEvent(MessageUpdatedEvent(message: newMsg));
}
Future<void> _onMessage(MessageEvent event, { dynamic extra }) async {
// The jid this message event is meant for
@ -783,6 +827,12 @@ class XmppService {
? event.toJid.toBare().toString()
: event.fromJid.toBare().toString();
if (event.type == 'error') {
await _handleErrorMessage(event);
_log.finest('Processed error message. Ending event processing here.');
return;
}
// Process the chat state update. Can also be attached to other messages
if (event.chatState != null) await _onChatState(event.chatState!, conversationJid);

View File

@ -1,6 +1,8 @@
import 'package:moxxmpp/moxxmpp.dart';
import 'package:moxxyv2/i18n/strings.g.dart';
import 'package:omemo_dart/omemo_dart.dart';
const unspecifiedError = -1;
const noError = 0;
const fileUploadFailedError = 1;
const messageNotEncryptedForDevice = 2;
@ -14,6 +16,9 @@ const messageContactDoesNotSupportOmemo = 9;
const messageChatEncryptedButFileNot = 10;
const messageFailedToEncryptFile = 11;
const fileDownloadFailedError = 12;
const messageServiceUnavailable = 13;
const messageRemoteServerTimeout = 14;
const messageRemoteServerNotFound = 15;
int errorTypeFromException(dynamic exception) {
if (exception is NoDecryptionKeyException) {
@ -32,3 +37,24 @@ int errorTypeFromException(dynamic exception) {
return noError;
}
String errorToTranslatableString(int error) {
assert(error != noError, 'Calling errorToTranslatableString with noError makes no sense');
switch (error) {
case fileUploadFailedError: return t.errors.message.fileUploadFailed;
case messageContactDoesNotSupportOmemo: return t.errors.message.contactDoesntSupportOmemo;
case fileDownloadFailedError: return t.errors.message.fileDownloadFailed;
case messageServiceUnavailable: return t.errors.message.serviceUnavailable;
case messageRemoteServerTimeout: return t.errors.message.remoteServerTimeout;
case messageRemoteServerNotFound: return t.errors.message.remoteServerNotFound;
case messageFailedToEncrypt: return t.errors.message.failedToEncrypt;
case messageFailedToDecryptFile: return t.errors.message.failedToDecryptFile;
case messageChatEncryptedButFileNot: return t.errors.message.fileNotEncrypted;
case messageFailedToEncryptFile: return t.errors.message.failedToEncryptFile;
case unspecifiedError: return t.errors.message.unspecified;
}
assert(false, 'Invalid error code $error used');
return '';
}

View File

@ -109,14 +109,10 @@ class Message with _$Message {
}
/// Returns true if the message is an error. If not, then returns false.
bool isError() {
return errorType != null && errorType != noError;
}
bool get hasError => errorType != null && errorType != noError;
/// Returns true if the message is a warning. If not, then returns false.
bool isWarning() {
return warningType != null && warningType != noWarning;
}
bool get hasWarning => warningType != null && warningType != noWarning;
/// Returns a representative emoji for a message. Its primary purpose is
/// to provide a universal fallback for quoted media messages.
@ -125,7 +121,7 @@ class Message with _$Message {
}
/// Returns true if the message can be quoted. False if not.
bool get isQuotable => !isError() && !isRetracted && !isFileUploadNotification && !isUploading && !isDownloading;
bool get isQuotable => !hasError && !isRetracted && !isFileUploadNotification && !isUploading && !isDownloading;
/// Returns true if the message can be retracted. False if not.
/// [sentBySelf] asks whether or not the message was sent by us (the current Jid).
@ -142,4 +138,13 @@ class Message with _$Message {
/// Returns true if the message can open the selection menu by longpressing. False if
/// not.
bool get isLongpressable => !isRetracted;
/// Returns true if the menu item to show the error should be shown in the
/// longpress menu.
bool get errorMenuVisible {
return hasError && (
errorType! < messageNotEncryptedForDevice ||
errorType! > messageInvalidNumber
);
}
}

View File

@ -96,7 +96,7 @@ class MessageBubbleBottomState extends State<MessageBubbleBottom> {
),
),
] : [],
...widget.message.isError() ? [
...widget.message.hasError ? [
const Padding(
padding: EdgeInsets.only(left: 3),
child: Icon(
@ -106,7 +106,7 @@ class MessageBubbleBottomState extends State<MessageBubbleBottom> {
),
),
] : [],
...widget.message.isWarning() ? [
...widget.message.hasWarning ? [
const Padding(
padding: EdgeInsets.only(left: 3),
child: Icon(

View File

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_vibrate/flutter_vibrate.dart';
import 'package:moxxyv2/i18n/strings.g.dart';
//import 'package:moxxyv2/shared/error_types.dart';
import 'package:moxxyv2/shared/error_types.dart';
import 'package:moxxyv2/shared/helpers.dart';
import 'package:moxxyv2/shared/models/message.dart';
import 'package:moxxyv2/shared/warning_types.dart';
@ -323,7 +323,20 @@ class ChatBubbleState extends State<ChatBubble>
},
),
] : [],
...widget.message.isWarning() ? [
...widget.message.errorMenuVisible ? [
_buildMessageOption(
Icons.info_outline,
'Show Error',
() {
showInfoDialog(
'Error',
errorToTranslatableString(widget.message.errorType!),
context,
);
},
),
] : [],
...widget.message.hasWarning ? [
_buildMessageOption(
Icons.warning,
'Show warning',

View File

@ -36,7 +36,7 @@ class TextChatWidget extends StatelessWidget {
final Widget? topWidget;
String getMessageText() {
if (message.isError()) {
if (message.hasError) {
return errorTypeToText(message.errorType!);
}
@ -52,7 +52,7 @@ class TextChatWidget extends StatelessWidget {
final fontsize = EmojiUtil.hasOnlyEmojis(
message.body,
ignoreWhitespace: true,
) && !message.isError() ?
) && !message.hasError ?
fontsizeBodyOnlyEmojis :
fontsizeBody;

View File

@ -753,14 +753,14 @@ packages:
name: moxxmpp
url: "https://git.polynom.me/api/packages/Moxxy/pub/"
source: hosted
version: "0.1.4"
version: "0.1.5"
moxxmpp_socket_tcp:
dependency: "direct main"
description:
name: moxxmpp_socket_tcp
url: "https://git.polynom.me/api/packages/Moxxy/pub/"
source: hosted
version: "0.1.2+6"
version: "0.1.2+7"
moxxyv2_builders:
dependency: "direct main"
description:

View File

@ -60,10 +60,10 @@ dependencies:
version: 0.1.15
moxxmpp:
hosted: https://git.polynom.me/api/packages/Moxxy/pub
version: 0.1.4
version: 0.1.5
moxxmpp_socket_tcp:
hosted: https://git.polynom.me/api/packages/Moxxy/pub
version: 0.1.2+6
version: 0.1.2+7
moxxyv2_builders:
hosted: https://git.polynom.me/api/packages/Moxxy/pub
version: 0.1.0