Files
Client/lib/push/push_subject.dart
T

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 [],
);
}
}