class Message { final String id; final String text; final int time; final int senderId; final String? status; // EDITED, DELETED, etc. final int? updateTime; // Время последнего редактирования final List> attaches; final int? cid; // клиентский id (timestamp) final Map? reactionInfo; // Информация о реакциях final Map? link; // Информация об ответе на сообщение final List> elements; // Форматирование текста Message({ required this.id, required this.text, required this.time, required this.senderId, this.status, this.updateTime, this.attaches = const [], this.cid, this.reactionInfo, this.link, this.elements = const [], }); factory Message.fromJson(Map json) { int senderId; if (json['sender'] is int) { senderId = json['sender']; } else { senderId = 0; } int time; if (json['time'] is int) { time = json['time']; } else { time = 0; } return Message( id: json['id']?.toString() ?? 'local_${DateTime.now().millisecondsSinceEpoch}', text: json['text'] ?? '', time: time, senderId: senderId, // Use the new safe logic status: json['status'], updateTime: json['updateTime'], attaches: (json['attaches'] as List?) ?.map((e) => (e as Map).cast()) .toList() ?? const [], cid: json['cid'], reactionInfo: json['reactionInfo'], link: json['link'], elements: (json['elements'] as List?) ?.map((e) => (e as Map).cast()) .toList() ?? const [], ); } Message copyWith({ String? id, String? text, int? time, int? senderId, String? status, int? updateTime, List>? attaches, int? cid, Map? reactionInfo, Map? link, List>? elements, }) { return Message( id: id ?? this.id, text: text ?? this.text, time: time ?? this.time, senderId: senderId ?? this.senderId, status: status ?? this.status, updateTime: updateTime ?? this.updateTime, attaches: attaches ?? this.attaches, cid: cid ?? this.cid, reactionInfo: reactionInfo ?? this.reactionInfo, link: link ?? this.link, elements: elements ?? this.elements, ); } bool get isEdited => status == 'EDITED'; bool get isDeleted => status == 'DELETED'; bool get isReply => link != null && link!['type'] == 'REPLY'; bool get isForwarded => link != null && link!['type'] == 'FORWARD'; bool get hasFileAttach => attaches.any((a) => (a['_type'] ?? a['type']) == 'FILE'); bool canEdit(int currentUserId) { if (isDeleted) return false; if (senderId != currentUserId) return false; if (attaches.isNotEmpty) { return false; // Нельзя редактировать сообщения с вложениями } final now = DateTime.now().millisecondsSinceEpoch; final messageTime = time; final hoursSinceCreation = (now - messageTime) / (1000 * 60 * 60); return hoursSinceCreation <= 24; } Map toJson() { return { 'id': id, 'text': text, 'time': time, 'sender': senderId, 'status': status, 'updateTime': updateTime, 'cid': cid, 'attaches': attaches, 'link': link, 'reactionInfo': reactionInfo, 'elements': elements, }; } }