106 lines
3.4 KiB
Dart
106 lines
3.4 KiB
Dart
/// Parsed parts of a Talk push subject text.
|
|
///
|
|
/// Format verified against nextcloud/spreed `Notifier::parseChatMessage`:
|
|
/// with message preview the parsed subject is `"{user}\n{message}"` for 1:1
|
|
/// chats and `'{user} in {call}' . "\n{message}"` for groups — header and
|
|
/// message are separated by a NEWLINE, and the notifications app forwards the
|
|
/// parsed subject unmodified (only shortened). The German translation of
|
|
/// `{user} in {call}` is identical (`l10n/de.json`), so the ` in ` separator
|
|
/// holds for de_DE. Legacy/other variants using `": "` are kept as fallback;
|
|
/// splitting the header at the LAST ` in ` is robust against sender names
|
|
/// containing "in" (only a display name literally containing ` in ` in a 1:1
|
|
/// chat would still mis-split — accepted heuristic limit).
|
|
({String sender, String? roomName, String text}) parseTalkSubject(String raw) {
|
|
String header;
|
|
String text;
|
|
final newline = raw.indexOf('\n');
|
|
if (newline > 0) {
|
|
header = raw.substring(0, newline).trim();
|
|
text = raw.substring(newline + 1);
|
|
} else {
|
|
final colon = raw.indexOf(': ');
|
|
if (colon > 0 && colon < raw.length - 2) {
|
|
header = raw.substring(0, colon);
|
|
text = raw.substring(colon + 2);
|
|
} else {
|
|
return (sender: 'Talk', roomName: null, text: raw);
|
|
}
|
|
}
|
|
final roomSep = header.lastIndexOf(' in ');
|
|
if (roomSep > 0 && roomSep + 4 < header.length) {
|
|
return (
|
|
sender: header.substring(0, roomSep),
|
|
roomName: header.substring(roomSep + 4),
|
|
text: text,
|
|
);
|
|
}
|
|
return (sender: header, roomName: null, text: text);
|
|
}
|
|
|
|
/// The decrypted `subject` JSON of a Nextcloud push-v2 notification.
|
|
///
|
|
/// Covers the full shape the notifications app emits, including the three
|
|
/// delete variants which the neon `DecryptedSubject` helper only partially
|
|
/// models (it lacks `delete-multiple`/`nids`).
|
|
class PushSubject {
|
|
/// Nextcloud notification id.
|
|
final int? nid;
|
|
|
|
/// App that raised the notification (e.g. `spreed` for Talk).
|
|
final String? app;
|
|
|
|
/// Human-readable subject line.
|
|
final String? subject;
|
|
|
|
/// Notification type (e.g. `chat`, `background`).
|
|
final String? type;
|
|
|
|
/// App-specific object id. For Talk this is the chat/room token.
|
|
final String? id;
|
|
|
|
final bool delete;
|
|
final bool deleteMultiple;
|
|
final bool deleteAll;
|
|
|
|
/// Notification ids to remove for a `delete-multiple` push.
|
|
final List<int> nids;
|
|
|
|
const PushSubject({
|
|
this.nid,
|
|
this.app,
|
|
this.subject,
|
|
this.type,
|
|
this.id,
|
|
this.delete = false,
|
|
this.deleteMultiple = false,
|
|
this.deleteAll = false,
|
|
this.nids = const [],
|
|
});
|
|
|
|
bool get isAnyDelete => delete || deleteMultiple || deleteAll;
|
|
|
|
/// True when this notification originates from Nextcloud Talk.
|
|
bool get isTalk => app == 'spreed';
|
|
|
|
factory PushSubject.fromJson(Map<String, dynamic> json) {
|
|
final rawNids = json['nids'];
|
|
return PushSubject(
|
|
nid: (json['nid'] as num?)?.toInt(),
|
|
app: json['app'] as String?,
|
|
subject: json['subject'] as String?,
|
|
type: json['type'] as String?,
|
|
id: json['id'] as String?,
|
|
delete: json['delete'] == true,
|
|
deleteMultiple: json['delete-multiple'] == true,
|
|
deleteAll: json['delete-all'] == true,
|
|
nids: rawNids is List
|
|
? rawNids
|
|
.whereType<Object>()
|
|
.map((e) => e is num ? e.toInt() : int.tryParse('$e'))
|
|
.whereType<int>()
|
|
.toList()
|
|
: const [],
|
|
);
|
|
}
|
|
}
|