Compare commits
3 Commits
5032cccf38
...
fd272ead37
Author | SHA1 | Date | |
---|---|---|---|
fd272ead37 | |||
6c5377d9fa | |||
ce414d92a2 |
@ -47,6 +47,7 @@
|
|||||||
"compress": "Compress",
|
"compress": "Compress",
|
||||||
"report": "Report",
|
"report": "Report",
|
||||||
"repost": "Repost",
|
"repost": "Repost",
|
||||||
|
"replyPost": "Reply",
|
||||||
"reply": "Reply",
|
"reply": "Reply",
|
||||||
"unset": "Unset",
|
"unset": "Unset",
|
||||||
"untitled": "Untitled",
|
"untitled": "Untitled",
|
||||||
@ -158,5 +159,9 @@
|
|||||||
"realmDeleted": "Realm {} has been deleted.",
|
"realmDeleted": "Realm {} has been deleted.",
|
||||||
"realmDelete": "Delete realm {}",
|
"realmDelete": "Delete realm {}",
|
||||||
"realmDeleteDescription": "Are you sure you want to delete this realm? This operation is irreversible, all resources (posts, chat channels, publishers, etc) belonging to this realm will be permanently deleted. Be careful and think twice!",
|
"realmDeleteDescription": "Are you sure you want to delete this realm? This operation is irreversible, all resources (posts, chat channels, publishers, etc) belonging to this realm will be permanently deleted. Be careful and think twice!",
|
||||||
"fieldChatMessage": "Message in {}"
|
"fieldChatMessage": "Message in {}",
|
||||||
|
"eventResourceTag": "Event {}",
|
||||||
|
"messageDelete": "Delete message {}",
|
||||||
|
"messageDeleteDescription": "Are you sure you want to delete this message? This operation is irreversible. You will leave a record of the deleted message.",
|
||||||
|
"messageDeleted": "Message {} has been deleted"
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,8 @@
|
|||||||
"compress": "压缩",
|
"compress": "压缩",
|
||||||
"report": "检举",
|
"report": "检举",
|
||||||
"repost": "转帖",
|
"repost": "转帖",
|
||||||
"reply": "回贴",
|
"replyPost": "回贴",
|
||||||
|
"reply": "回复",
|
||||||
"unset": "未设置",
|
"unset": "未设置",
|
||||||
"untitled": "无题",
|
"untitled": "无题",
|
||||||
"postDetail": "帖子详情",
|
"postDetail": "帖子详情",
|
||||||
@ -158,5 +159,9 @@
|
|||||||
"realmDeleted": "领域 {} 已被删除" ,
|
"realmDeleted": "领域 {} 已被删除" ,
|
||||||
"realmDelete": "删除领域 {}",
|
"realmDelete": "删除领域 {}",
|
||||||
"realmDeleteDescription": "你确定要删除这个领域吗?该操作不可撤销,其隶属于该领域的所有资源(帖子、聊天频道、发布者、制品等)都将被永久删除。三思而后行!",
|
"realmDeleteDescription": "你确定要删除这个领域吗?该操作不可撤销,其隶属于该领域的所有资源(帖子、聊天频道、发布者、制品等)都将被永久删除。三思而后行!",
|
||||||
"fieldChatMessage": "在 {} 中发消息"
|
"fieldChatMessage": "在 {} 中发消息",
|
||||||
|
"eventResourceTag": "消息 {}",
|
||||||
|
"messageDelete": "删除消息 {}",
|
||||||
|
"messageDeleteDescription": "你确定要删除这个消息吗?该操作不可撤销。同时您将留下一条删除消息的记录。",
|
||||||
|
"messageDeleted": "消息 {} 已被删除"
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ PODS:
|
|||||||
- DKImagePickerController/PhotoGallery
|
- DKImagePickerController/PhotoGallery
|
||||||
- Flutter
|
- Flutter
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_native_splash (0.0.1):
|
- flutter_native_splash (2.4.3):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_secure_storage (6.0.0):
|
- flutter_secure_storage (6.0.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
@ -123,7 +123,7 @@ SPEC CHECKSUMS:
|
|||||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||||
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
flutter_native_splash: e8a1e01082d97a8099d973f919f57904c925008a
|
||||||
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||||
isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
|
isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
@ -120,8 +121,8 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
|
|
||||||
Future<void> _addUnconfirmedMessage(SnChatMessage message) async {
|
Future<void> _addUnconfirmedMessage(SnChatMessage message) async {
|
||||||
SnChatMessage? quoteEvent;
|
SnChatMessage? quoteEvent;
|
||||||
if (message.body['quote_event'] != null) {
|
if (message.quoteEventId != null) {
|
||||||
quoteEvent = await getMessage(message.body['quote_event'] as int);
|
quoteEvent = await getMessage(message.quoteEventId as int);
|
||||||
}
|
}
|
||||||
|
|
||||||
final attachmentRid = List<String>.from(
|
final attachmentRid = List<String>.from(
|
||||||
@ -142,8 +143,8 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
|
|
||||||
Future<void> _addMessage(SnChatMessage message) async {
|
Future<void> _addMessage(SnChatMessage message) async {
|
||||||
SnChatMessage? quoteEvent;
|
SnChatMessage? quoteEvent;
|
||||||
if (message.body['quote_event'] != null) {
|
if (message.quoteEventId != null) {
|
||||||
quoteEvent = await getMessage(message.body['quote_event'] as int);
|
quoteEvent = await getMessage(message.quoteEventId as int);
|
||||||
}
|
}
|
||||||
|
|
||||||
final attachmentRid = List<String>.from(
|
final attachmentRid = List<String>.from(
|
||||||
@ -176,9 +177,9 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
|
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case 'messages.edit':
|
case 'messages.edit':
|
||||||
final body = message.body;
|
if (message.relatedEventId != null) {
|
||||||
if (body['related_event'] != null) {
|
final idx =
|
||||||
final idx = messages.indexWhere((x) => x.id == body['related_event']);
|
messages.indexWhere((x) => x.id == message.relatedEventId);
|
||||||
if (idx != -1) {
|
if (idx != -1) {
|
||||||
final newBody = message.body;
|
final newBody = message.body;
|
||||||
newBody.remove('related_event');
|
newBody.remove('related_event');
|
||||||
@ -186,17 +187,16 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
body: newBody,
|
body: newBody,
|
||||||
updatedAt: message.updatedAt,
|
updatedAt: message.updatedAt,
|
||||||
);
|
);
|
||||||
if (_box!.containsKey(body['related_event'])) {
|
if (_box!.containsKey(message.relatedEventId)) {
|
||||||
await _box!.put(body['related_event'], messages[idx]);
|
await _box!.put(message.relatedEventId, messages[idx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'messages.delete':
|
case 'messages.delete':
|
||||||
final body = message.body;
|
if (message.relatedEventId != null) {
|
||||||
if (body['related_event'] != null) {
|
messages.removeWhere((x) => x.id == message.relatedEventId);
|
||||||
messages.removeWhere((x) => x.id == body['related_event']);
|
if (_box!.containsKey(message.relatedEventId)) {
|
||||||
if (_box!.containsKey(body['related_event'])) {
|
await _box!.delete(message.relatedEventId);
|
||||||
await _box!.delete(body['related_event']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,6 +208,7 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
int? quoteId,
|
int? quoteId,
|
||||||
int? relatedId,
|
int? relatedId,
|
||||||
List<String>? attachments,
|
List<String>? attachments,
|
||||||
|
SnChatMessage? editingMessage,
|
||||||
}) async {
|
}) async {
|
||||||
if (channel == null) return;
|
if (channel == null) return;
|
||||||
const uuid = Uuid();
|
const uuid = Uuid();
|
||||||
@ -216,7 +217,7 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
'text': content,
|
'text': content,
|
||||||
'algorithm': 'plain',
|
'algorithm': 'plain',
|
||||||
if (quoteId != null) 'quote_event': quoteId,
|
if (quoteId != null) 'quote_event': quoteId,
|
||||||
if (relatedId != null) 'quote_event': relatedId,
|
if (relatedId != null) 'related_event': relatedId,
|
||||||
if (attachments != null && attachments.isNotEmpty)
|
if (attachments != null && attachments.isNotEmpty)
|
||||||
'attachments': attachments,
|
'attachments': attachments,
|
||||||
};
|
};
|
||||||
@ -234,21 +235,41 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
channelId: channel!.id,
|
channelId: channel!.id,
|
||||||
sender: profile!,
|
sender: profile!,
|
||||||
senderId: profile!.id,
|
senderId: profile!.id,
|
||||||
|
quoteEventId: quoteId,
|
||||||
|
relatedEventId: relatedId,
|
||||||
);
|
);
|
||||||
_addUnconfirmedMessage(message);
|
_addUnconfirmedMessage(message);
|
||||||
|
|
||||||
// Send to server
|
// Send to server
|
||||||
try {
|
try {
|
||||||
await _sn.client.post(
|
await _sn.client.request(
|
||||||
'/cgi/im/channels/${channel!.keyPath}/messages',
|
editingMessage != null
|
||||||
|
? '/cgi/im/channels/${channel!.keyPath}/messages/${editingMessage.id}'
|
||||||
|
: '/cgi/im/channels/${channel!.keyPath}/messages',
|
||||||
data: {
|
data: {
|
||||||
'type': type,
|
'type': type,
|
||||||
'uuid': nonce,
|
'uuid': nonce,
|
||||||
'body': body,
|
'body': body,
|
||||||
},
|
},
|
||||||
|
options: Options(
|
||||||
|
method: editingMessage != null ? 'PUT' : 'POST',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print(err);
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteMessage(SnChatMessage message) async {
|
||||||
|
if (message.channelId != channel?.id) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await _sn.client.delete(
|
||||||
|
'/cgi/im/channels/${channel!.keyPath}/messages/${message.id}',
|
||||||
|
);
|
||||||
|
messages.removeWhere((x) => x.id == message.id);
|
||||||
|
} catch (err) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,8 +378,8 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
for (var i = 0; i < out.length; i++) {
|
for (var i = 0; i < out.length; i++) {
|
||||||
// Preload related events (quoted)
|
// Preload related events (quoted)
|
||||||
SnChatMessage? quoteEvent;
|
SnChatMessage? quoteEvent;
|
||||||
if (out[i].body['quote_event'] != null) {
|
if (out[i].quoteEventId != null) {
|
||||||
quoteEvent = await getMessage(out[i].body['quote_event'] as int);
|
quoteEvent = await getMessage(out[i].quoteEventId as int);
|
||||||
}
|
}
|
||||||
|
|
||||||
out[i] = out[i].copyWith(
|
out[i] = out[i].copyWith(
|
||||||
@ -375,7 +396,11 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Preload sender accounts
|
// Preload sender accounts
|
||||||
await _ud.listAccount(out.map((ele) => ele.sender.accountId).toSet());
|
final accountId = out
|
||||||
|
.where((ele) => ele.sender.accountId >= 0)
|
||||||
|
.map((ele) => ele.sender.accountId)
|
||||||
|
.toSet();
|
||||||
|
await _ud.listAccount(accountId);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -28,15 +28,15 @@ class SnNetworkProvider {
|
|||||||
SnNetworkProvider() {
|
SnNetworkProvider() {
|
||||||
client = Dio();
|
client = Dio();
|
||||||
|
|
||||||
// client.interceptors.add(RetryInterceptor(
|
client.interceptors.add(RetryInterceptor(
|
||||||
// dio: client,
|
dio: client,
|
||||||
// retries: 3,
|
retries: 3,
|
||||||
// retryDelays: const [
|
retryDelays: const [
|
||||||
// Duration(milliseconds: 300),
|
Duration(milliseconds: 300),
|
||||||
// Duration(milliseconds: 1000),
|
Duration(milliseconds: 1000),
|
||||||
// Duration(milliseconds: 3000),
|
Duration(milliseconds: 3000),
|
||||||
// ],
|
],
|
||||||
// ));
|
));
|
||||||
|
|
||||||
client.interceptors.add(
|
client.interceptors.add(
|
||||||
InterceptorsWrapper(
|
InterceptorsWrapper(
|
||||||
|
@ -118,8 +118,14 @@ class _ChatRoomScreenState extends State<ChatRoomScreen> {
|
|||||||
hasMerged: canMergePrevious,
|
hasMerged: canMergePrevious,
|
||||||
isPending: _messageController.unconfirmedMessages
|
isPending: _messageController.unconfirmedMessages
|
||||||
.contains(message.uuid),
|
.contains(message.uuid),
|
||||||
onReply: () {
|
onReply: (value) {
|
||||||
_inputGlobalKey.currentState?.setReply(message);
|
_inputGlobalKey.currentState?.setReply(value);
|
||||||
|
},
|
||||||
|
onEdit: (value) {
|
||||||
|
_inputGlobalKey.currentState?.setEdit(value);
|
||||||
|
},
|
||||||
|
onDelete: (value) {
|
||||||
|
_inputGlobalKey.currentState?.deleteMessage(value);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -74,12 +74,14 @@ class SnChatMessage with _$SnChatMessage {
|
|||||||
@HiveField(2) required DateTime updatedAt,
|
@HiveField(2) required DateTime updatedAt,
|
||||||
@HiveField(3) required DateTime? deletedAt,
|
@HiveField(3) required DateTime? deletedAt,
|
||||||
@HiveField(4) required String uuid,
|
@HiveField(4) required String uuid,
|
||||||
@HiveField(5) required Map<String, dynamic> body,
|
@HiveField(5) @Default({}) Map<String, dynamic> body,
|
||||||
@HiveField(6) required String type,
|
@HiveField(6) required String type,
|
||||||
@HiveField(7) required SnChannel channel,
|
@HiveField(7) required SnChannel channel,
|
||||||
@HiveField(8) required SnChannelMember sender,
|
@HiveField(8) required SnChannelMember sender,
|
||||||
@HiveField(9) required int channelId,
|
@HiveField(9) required int channelId,
|
||||||
@HiveField(10) required int senderId,
|
@HiveField(10) required int senderId,
|
||||||
|
@HiveField(11) required int? quoteEventId,
|
||||||
|
@HiveField(12) required int? relatedEventId,
|
||||||
SnChatMessagePreload? preload,
|
SnChatMessagePreload? preload,
|
||||||
}) = _SnChatMessage;
|
}) = _SnChatMessage;
|
||||||
|
|
||||||
|
@ -1083,6 +1083,10 @@ mixin _$SnChatMessage {
|
|||||||
int get channelId => throw _privateConstructorUsedError;
|
int get channelId => throw _privateConstructorUsedError;
|
||||||
@HiveField(10)
|
@HiveField(10)
|
||||||
int get senderId => throw _privateConstructorUsedError;
|
int get senderId => throw _privateConstructorUsedError;
|
||||||
|
@HiveField(11)
|
||||||
|
int? get quoteEventId => throw _privateConstructorUsedError;
|
||||||
|
@HiveField(12)
|
||||||
|
int? get relatedEventId => throw _privateConstructorUsedError;
|
||||||
SnChatMessagePreload? get preload => throw _privateConstructorUsedError;
|
SnChatMessagePreload? get preload => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
/// Serializes this SnChatMessage to a JSON map.
|
/// Serializes this SnChatMessage to a JSON map.
|
||||||
@ -1113,6 +1117,8 @@ abstract class $SnChatMessageCopyWith<$Res> {
|
|||||||
@HiveField(8) SnChannelMember sender,
|
@HiveField(8) SnChannelMember sender,
|
||||||
@HiveField(9) int channelId,
|
@HiveField(9) int channelId,
|
||||||
@HiveField(10) int senderId,
|
@HiveField(10) int senderId,
|
||||||
|
@HiveField(11) int? quoteEventId,
|
||||||
|
@HiveField(12) int? relatedEventId,
|
||||||
SnChatMessagePreload? preload});
|
SnChatMessagePreload? preload});
|
||||||
|
|
||||||
$SnChannelCopyWith<$Res> get channel;
|
$SnChannelCopyWith<$Res> get channel;
|
||||||
@ -1146,6 +1152,8 @@ class _$SnChatMessageCopyWithImpl<$Res, $Val extends SnChatMessage>
|
|||||||
Object? sender = null,
|
Object? sender = null,
|
||||||
Object? channelId = null,
|
Object? channelId = null,
|
||||||
Object? senderId = null,
|
Object? senderId = null,
|
||||||
|
Object? quoteEventId = freezed,
|
||||||
|
Object? relatedEventId = freezed,
|
||||||
Object? preload = freezed,
|
Object? preload = freezed,
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
@ -1193,6 +1201,14 @@ class _$SnChatMessageCopyWithImpl<$Res, $Val extends SnChatMessage>
|
|||||||
? _value.senderId
|
? _value.senderId
|
||||||
: senderId // ignore: cast_nullable_to_non_nullable
|
: senderId // ignore: cast_nullable_to_non_nullable
|
||||||
as int,
|
as int,
|
||||||
|
quoteEventId: freezed == quoteEventId
|
||||||
|
? _value.quoteEventId
|
||||||
|
: quoteEventId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,
|
||||||
|
relatedEventId: freezed == relatedEventId
|
||||||
|
? _value.relatedEventId
|
||||||
|
: relatedEventId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,
|
||||||
preload: freezed == preload
|
preload: freezed == preload
|
||||||
? _value.preload
|
? _value.preload
|
||||||
: preload // ignore: cast_nullable_to_non_nullable
|
: preload // ignore: cast_nullable_to_non_nullable
|
||||||
@ -1255,6 +1271,8 @@ abstract class _$$SnChatMessageImplCopyWith<$Res>
|
|||||||
@HiveField(8) SnChannelMember sender,
|
@HiveField(8) SnChannelMember sender,
|
||||||
@HiveField(9) int channelId,
|
@HiveField(9) int channelId,
|
||||||
@HiveField(10) int senderId,
|
@HiveField(10) int senderId,
|
||||||
|
@HiveField(11) int? quoteEventId,
|
||||||
|
@HiveField(12) int? relatedEventId,
|
||||||
SnChatMessagePreload? preload});
|
SnChatMessagePreload? preload});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -1289,6 +1307,8 @@ class __$$SnChatMessageImplCopyWithImpl<$Res>
|
|||||||
Object? sender = null,
|
Object? sender = null,
|
||||||
Object? channelId = null,
|
Object? channelId = null,
|
||||||
Object? senderId = null,
|
Object? senderId = null,
|
||||||
|
Object? quoteEventId = freezed,
|
||||||
|
Object? relatedEventId = freezed,
|
||||||
Object? preload = freezed,
|
Object? preload = freezed,
|
||||||
}) {
|
}) {
|
||||||
return _then(_$SnChatMessageImpl(
|
return _then(_$SnChatMessageImpl(
|
||||||
@ -1336,6 +1356,14 @@ class __$$SnChatMessageImplCopyWithImpl<$Res>
|
|||||||
? _value.senderId
|
? _value.senderId
|
||||||
: senderId // ignore: cast_nullable_to_non_nullable
|
: senderId // ignore: cast_nullable_to_non_nullable
|
||||||
as int,
|
as int,
|
||||||
|
quoteEventId: freezed == quoteEventId
|
||||||
|
? _value.quoteEventId
|
||||||
|
: quoteEventId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,
|
||||||
|
relatedEventId: freezed == relatedEventId
|
||||||
|
? _value.relatedEventId
|
||||||
|
: relatedEventId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,
|
||||||
preload: freezed == preload
|
preload: freezed == preload
|
||||||
? _value.preload
|
? _value.preload
|
||||||
: preload // ignore: cast_nullable_to_non_nullable
|
: preload // ignore: cast_nullable_to_non_nullable
|
||||||
@ -1354,12 +1382,14 @@ class _$SnChatMessageImpl extends _SnChatMessage {
|
|||||||
@HiveField(2) required this.updatedAt,
|
@HiveField(2) required this.updatedAt,
|
||||||
@HiveField(3) required this.deletedAt,
|
@HiveField(3) required this.deletedAt,
|
||||||
@HiveField(4) required this.uuid,
|
@HiveField(4) required this.uuid,
|
||||||
@HiveField(5) required final Map<String, dynamic> body,
|
@HiveField(5) final Map<String, dynamic> body = const {},
|
||||||
@HiveField(6) required this.type,
|
@HiveField(6) required this.type,
|
||||||
@HiveField(7) required this.channel,
|
@HiveField(7) required this.channel,
|
||||||
@HiveField(8) required this.sender,
|
@HiveField(8) required this.sender,
|
||||||
@HiveField(9) required this.channelId,
|
@HiveField(9) required this.channelId,
|
||||||
@HiveField(10) required this.senderId,
|
@HiveField(10) required this.senderId,
|
||||||
|
@HiveField(11) required this.quoteEventId,
|
||||||
|
@HiveField(12) required this.relatedEventId,
|
||||||
this.preload})
|
this.preload})
|
||||||
: _body = body,
|
: _body = body,
|
||||||
super._();
|
super._();
|
||||||
@ -1384,6 +1414,7 @@ class _$SnChatMessageImpl extends _SnChatMessage {
|
|||||||
final String uuid;
|
final String uuid;
|
||||||
final Map<String, dynamic> _body;
|
final Map<String, dynamic> _body;
|
||||||
@override
|
@override
|
||||||
|
@JsonKey()
|
||||||
@HiveField(5)
|
@HiveField(5)
|
||||||
Map<String, dynamic> get body {
|
Map<String, dynamic> get body {
|
||||||
if (_body is EqualUnmodifiableMapView) return _body;
|
if (_body is EqualUnmodifiableMapView) return _body;
|
||||||
@ -1407,11 +1438,17 @@ class _$SnChatMessageImpl extends _SnChatMessage {
|
|||||||
@HiveField(10)
|
@HiveField(10)
|
||||||
final int senderId;
|
final int senderId;
|
||||||
@override
|
@override
|
||||||
|
@HiveField(11)
|
||||||
|
final int? quoteEventId;
|
||||||
|
@override
|
||||||
|
@HiveField(12)
|
||||||
|
final int? relatedEventId;
|
||||||
|
@override
|
||||||
final SnChatMessagePreload? preload;
|
final SnChatMessagePreload? preload;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnChatMessage(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, uuid: $uuid, body: $body, type: $type, channel: $channel, sender: $sender, channelId: $channelId, senderId: $senderId, preload: $preload)';
|
return 'SnChatMessage(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, uuid: $uuid, body: $body, type: $type, channel: $channel, sender: $sender, channelId: $channelId, senderId: $senderId, quoteEventId: $quoteEventId, relatedEventId: $relatedEventId, preload: $preload)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -1435,6 +1472,10 @@ class _$SnChatMessageImpl extends _SnChatMessage {
|
|||||||
other.channelId == channelId) &&
|
other.channelId == channelId) &&
|
||||||
(identical(other.senderId, senderId) ||
|
(identical(other.senderId, senderId) ||
|
||||||
other.senderId == senderId) &&
|
other.senderId == senderId) &&
|
||||||
|
(identical(other.quoteEventId, quoteEventId) ||
|
||||||
|
other.quoteEventId == quoteEventId) &&
|
||||||
|
(identical(other.relatedEventId, relatedEventId) ||
|
||||||
|
other.relatedEventId == relatedEventId) &&
|
||||||
(identical(other.preload, preload) || other.preload == preload));
|
(identical(other.preload, preload) || other.preload == preload));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1453,6 +1494,8 @@ class _$SnChatMessageImpl extends _SnChatMessage {
|
|||||||
sender,
|
sender,
|
||||||
channelId,
|
channelId,
|
||||||
senderId,
|
senderId,
|
||||||
|
quoteEventId,
|
||||||
|
relatedEventId,
|
||||||
preload);
|
preload);
|
||||||
|
|
||||||
/// Create a copy of SnChatMessage
|
/// Create a copy of SnChatMessage
|
||||||
@ -1478,12 +1521,14 @@ abstract class _SnChatMessage extends SnChatMessage {
|
|||||||
@HiveField(2) required final DateTime updatedAt,
|
@HiveField(2) required final DateTime updatedAt,
|
||||||
@HiveField(3) required final DateTime? deletedAt,
|
@HiveField(3) required final DateTime? deletedAt,
|
||||||
@HiveField(4) required final String uuid,
|
@HiveField(4) required final String uuid,
|
||||||
@HiveField(5) required final Map<String, dynamic> body,
|
@HiveField(5) final Map<String, dynamic> body,
|
||||||
@HiveField(6) required final String type,
|
@HiveField(6) required final String type,
|
||||||
@HiveField(7) required final SnChannel channel,
|
@HiveField(7) required final SnChannel channel,
|
||||||
@HiveField(8) required final SnChannelMember sender,
|
@HiveField(8) required final SnChannelMember sender,
|
||||||
@HiveField(9) required final int channelId,
|
@HiveField(9) required final int channelId,
|
||||||
@HiveField(10) required final int senderId,
|
@HiveField(10) required final int senderId,
|
||||||
|
@HiveField(11) required final int? quoteEventId,
|
||||||
|
@HiveField(12) required final int? relatedEventId,
|
||||||
final SnChatMessagePreload? preload}) = _$SnChatMessageImpl;
|
final SnChatMessagePreload? preload}) = _$SnChatMessageImpl;
|
||||||
const _SnChatMessage._() : super._();
|
const _SnChatMessage._() : super._();
|
||||||
|
|
||||||
@ -1524,6 +1569,12 @@ abstract class _SnChatMessage extends SnChatMessage {
|
|||||||
@HiveField(10)
|
@HiveField(10)
|
||||||
int get senderId;
|
int get senderId;
|
||||||
@override
|
@override
|
||||||
|
@HiveField(11)
|
||||||
|
int? get quoteEventId;
|
||||||
|
@override
|
||||||
|
@HiveField(12)
|
||||||
|
int? get relatedEventId;
|
||||||
|
@override
|
||||||
SnChatMessagePreload? get preload;
|
SnChatMessagePreload? get preload;
|
||||||
|
|
||||||
/// Create a copy of SnChatMessage
|
/// Create a copy of SnChatMessage
|
||||||
|
@ -162,13 +162,15 @@ class SnChatMessageImplAdapter extends TypeAdapter<_$SnChatMessageImpl> {
|
|||||||
sender: fields[8] as SnChannelMember,
|
sender: fields[8] as SnChannelMember,
|
||||||
channelId: fields[9] as int,
|
channelId: fields[9] as int,
|
||||||
senderId: fields[10] as int,
|
senderId: fields[10] as int,
|
||||||
|
quoteEventId: fields[11] as int?,
|
||||||
|
relatedEventId: fields[12] as int?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void write(BinaryWriter writer, _$SnChatMessageImpl obj) {
|
void write(BinaryWriter writer, _$SnChatMessageImpl obj) {
|
||||||
writer
|
writer
|
||||||
..writeByte(11)
|
..writeByte(13)
|
||||||
..writeByte(0)
|
..writeByte(0)
|
||||||
..write(obj.id)
|
..write(obj.id)
|
||||||
..writeByte(1)
|
..writeByte(1)
|
||||||
@ -189,6 +191,10 @@ class SnChatMessageImplAdapter extends TypeAdapter<_$SnChatMessageImpl> {
|
|||||||
..write(obj.channelId)
|
..write(obj.channelId)
|
||||||
..writeByte(10)
|
..writeByte(10)
|
||||||
..write(obj.senderId)
|
..write(obj.senderId)
|
||||||
|
..writeByte(11)
|
||||||
|
..write(obj.quoteEventId)
|
||||||
|
..writeByte(12)
|
||||||
|
..write(obj.relatedEventId)
|
||||||
..writeByte(5)
|
..writeByte(5)
|
||||||
..write(obj.body);
|
..write(obj.body);
|
||||||
}
|
}
|
||||||
@ -303,12 +309,14 @@ _$SnChatMessageImpl _$$SnChatMessageImplFromJson(Map<String, dynamic> json) =>
|
|||||||
? null
|
? null
|
||||||
: DateTime.parse(json['deleted_at'] as String),
|
: DateTime.parse(json['deleted_at'] as String),
|
||||||
uuid: json['uuid'] as String,
|
uuid: json['uuid'] as String,
|
||||||
body: json['body'] as Map<String, dynamic>,
|
body: json['body'] as Map<String, dynamic>? ?? const {},
|
||||||
type: json['type'] as String,
|
type: json['type'] as String,
|
||||||
channel: SnChannel.fromJson(json['channel'] as Map<String, dynamic>),
|
channel: SnChannel.fromJson(json['channel'] as Map<String, dynamic>),
|
||||||
sender: SnChannelMember.fromJson(json['sender'] as Map<String, dynamic>),
|
sender: SnChannelMember.fromJson(json['sender'] as Map<String, dynamic>),
|
||||||
channelId: (json['channel_id'] as num).toInt(),
|
channelId: (json['channel_id'] as num).toInt(),
|
||||||
senderId: (json['sender_id'] as num).toInt(),
|
senderId: (json['sender_id'] as num).toInt(),
|
||||||
|
quoteEventId: (json['quote_event_id'] as num?)?.toInt(),
|
||||||
|
relatedEventId: (json['related_event_id'] as num?)?.toInt(),
|
||||||
preload: json['preload'] == null
|
preload: json['preload'] == null
|
||||||
? null
|
? null
|
||||||
: SnChatMessagePreload.fromJson(
|
: SnChatMessagePreload.fromJson(
|
||||||
@ -328,6 +336,8 @@ Map<String, dynamic> _$$SnChatMessageImplToJson(_$SnChatMessageImpl instance) =>
|
|||||||
'sender': instance.sender.toJson(),
|
'sender': instance.sender.toJson(),
|
||||||
'channel_id': instance.channelId,
|
'channel_id': instance.channelId,
|
||||||
'sender_id': instance.senderId,
|
'sender_id': instance.senderId,
|
||||||
|
'quote_event_id': instance.quoteEventId,
|
||||||
|
'related_event_id': instance.relatedEventId,
|
||||||
'preload': instance.preload?.toJson(),
|
'preload': instance.preload?.toJson(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_context_menu/flutter_context_menu.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:surface/providers/user_directory.dart';
|
import 'package:surface/providers/user_directory.dart';
|
||||||
|
import 'package:surface/providers/userinfo.dart';
|
||||||
import 'package:surface/types/chat.dart';
|
import 'package:surface/types/chat.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
import 'package:surface/widgets/attachment/attachment_list.dart';
|
import 'package:surface/widgets/attachment/attachment_list.dart';
|
||||||
@ -17,7 +19,9 @@ class ChatMessage extends StatelessWidget {
|
|||||||
final bool isMerged;
|
final bool isMerged;
|
||||||
final bool hasMerged;
|
final bool hasMerged;
|
||||||
final bool isPending;
|
final bool isPending;
|
||||||
final Function()? onReply;
|
final Function(SnChatMessage)? onReply;
|
||||||
|
final Function(SnChatMessage)? onEdit;
|
||||||
|
final Function(SnChatMessage)? onDelete;
|
||||||
const ChatMessage({
|
const ChatMessage({
|
||||||
super.key,
|
super.key,
|
||||||
required this.data,
|
required this.data,
|
||||||
@ -26,100 +30,151 @@ class ChatMessage extends StatelessWidget {
|
|||||||
this.hasMerged = false,
|
this.hasMerged = false,
|
||||||
this.isPending = false,
|
this.isPending = false,
|
||||||
this.onReply,
|
this.onReply,
|
||||||
|
this.onEdit,
|
||||||
|
this.onDelete,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final ua = context.read<UserProvider>();
|
||||||
final ud = context.read<UserDirectoryProvider>();
|
final ud = context.read<UserDirectoryProvider>();
|
||||||
final user = ud.getAccountFromCache(data.sender.accountId);
|
final user = ud.getAccountFromCache(data.sender.accountId);
|
||||||
|
|
||||||
|
final isOwner = ua.isAuthorized && data.sender.accountId == ua.user!.id;
|
||||||
|
|
||||||
final dateFormatter = DateFormat('MM/dd HH:mm');
|
final dateFormatter = DateFormat('MM/dd HH:mm');
|
||||||
|
|
||||||
return SwipeTo(
|
return SwipeTo(
|
||||||
key: Key('chat-message-${data.id}'),
|
key: Key('chat-message-${data.id}'),
|
||||||
iconOnLeftSwipe: Symbols.reply,
|
iconOnLeftSwipe: Symbols.reply,
|
||||||
swipeSensitivity: 20,
|
swipeSensitivity: 20,
|
||||||
onLeftSwipe: onReply != null ? (_) => onReply!() : null,
|
onLeftSwipe: onReply != null ? (_) => onReply!(data) : null,
|
||||||
child: Column(
|
child: ContextMenuRegion(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
contextMenu: ContextMenu(
|
||||||
children: [
|
entries: [
|
||||||
Row(
|
MenuHeader(text: "eventResourceTag".tr(args: ['#${data.id}'])),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
if (onReply != null)
|
||||||
children: [
|
MenuItem(
|
||||||
if (!isMerged && !isCompact)
|
label: 'reply'.tr(),
|
||||||
AccountImage(
|
icon: Symbols.reply,
|
||||||
content: user?.avatar,
|
onSelected: () {
|
||||||
)
|
onReply!(data);
|
||||||
else if (isMerged)
|
},
|
||||||
const Gap(40),
|
),
|
||||||
const Gap(8),
|
if (isOwner && onEdit != null)
|
||||||
Expanded(
|
MenuItem(
|
||||||
child: Column(
|
label: 'edit'.tr(),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
icon: Symbols.edit,
|
||||||
children: [
|
onSelected: () {
|
||||||
if (!isMerged)
|
onEdit!(data);
|
||||||
Row(
|
},
|
||||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
),
|
||||||
textBaseline: TextBaseline.alphabetic,
|
if (isOwner && onDelete != null)
|
||||||
children: [
|
MenuItem(
|
||||||
if (isCompact)
|
label: 'delete'.tr(),
|
||||||
AccountImage(
|
icon: Symbols.delete,
|
||||||
content: user?.avatar,
|
onSelected: () {
|
||||||
radius: 12,
|
onDelete!(data);
|
||||||
).padding(right: 6),
|
},
|
||||||
Text(
|
),
|
||||||
(data.sender.nick?.isNotEmpty ?? false)
|
],
|
||||||
? data.sender.nick!
|
),
|
||||||
: user!.nick,
|
child: Column(
|
||||||
).bold(),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
const Gap(6),
|
children: [
|
||||||
Text(
|
Row(
|
||||||
dateFormatter.format(data.createdAt.toLocal()),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
).fontSize(13),
|
children: [
|
||||||
],
|
if (!isMerged && !isCompact)
|
||||||
),
|
AccountImage(
|
||||||
if (isCompact) const Gap(4),
|
content: user?.avatar,
|
||||||
if (data.preload?.quoteEvent != null)
|
)
|
||||||
StyledWidget(Container(
|
else if (isMerged)
|
||||||
decoration: BoxDecoration(
|
const Gap(40),
|
||||||
borderRadius:
|
const Gap(8),
|
||||||
const BorderRadius.all(Radius.circular(8)),
|
Expanded(
|
||||||
border: Border.all(
|
child: Column(
|
||||||
color: Theme.of(context).dividerColor,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
width: 1,
|
children: [
|
||||||
|
if (!isMerged)
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||||
|
textBaseline: TextBaseline.alphabetic,
|
||||||
|
children: [
|
||||||
|
if (isCompact)
|
||||||
|
AccountImage(
|
||||||
|
content: user?.avatar,
|
||||||
|
radius: 12,
|
||||||
|
).padding(right: 6),
|
||||||
|
Text(
|
||||||
|
(data.sender.nick?.isNotEmpty ?? false)
|
||||||
|
? data.sender.nick!
|
||||||
|
: user!.nick,
|
||||||
|
).bold(),
|
||||||
|
const Gap(6),
|
||||||
|
Text(
|
||||||
|
dateFormatter.format(data.createdAt.toLocal()),
|
||||||
|
).fontSize(13),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (isCompact) const Gap(4),
|
||||||
|
if (data.preload?.quoteEvent != null)
|
||||||
|
StyledWidget(Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius:
|
||||||
|
const BorderRadius.all(Radius.circular(8)),
|
||||||
|
border: Border.all(
|
||||||
|
color: Theme.of(context).dividerColor,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 4,
|
||||||
|
right: 4,
|
||||||
|
top: 8,
|
||||||
|
bottom: 6,
|
||||||
|
),
|
||||||
|
child: ChatMessage(
|
||||||
|
data: data.preload!.quoteEvent!,
|
||||||
|
isCompact: true,
|
||||||
|
onReply: onReply,
|
||||||
|
onEdit: onEdit,
|
||||||
|
onDelete: onDelete,
|
||||||
|
),
|
||||||
|
)).padding(bottom: 4, top: isMerged ? 4 : 2),
|
||||||
|
if (data.body['text'] != null)
|
||||||
|
MarkdownTextContent(
|
||||||
|
content: data.body['text'],
|
||||||
|
isAutoWarp: true,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.only(
|
if (data.type == 'messages.delete' &&
|
||||||
left: 4,
|
data.relatedEventId != null)
|
||||||
right: 4,
|
Row(
|
||||||
top: 8,
|
children: [
|
||||||
bottom: 6,
|
const Icon(Symbols.delete),
|
||||||
|
const Gap(8),
|
||||||
|
Text(
|
||||||
|
'messageDeleted'
|
||||||
|
.tr(args: ['#${data.relatedEventId}']),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
child: ChatMessage(
|
],
|
||||||
data: data.preload!.quoteEvent!,
|
),
|
||||||
isCompact: true,
|
)
|
||||||
),
|
],
|
||||||
)).padding(bottom: 4, top: isMerged ? 4 : 2),
|
).opacity(isPending ? 0.5 : 1),
|
||||||
if (data.body['text'] != null)
|
if (data.preload?.attachments?.isNotEmpty ?? false)
|
||||||
MarkdownTextContent(
|
AttachmentList(
|
||||||
content: data.body['text'],
|
data: data.preload!.attachments!,
|
||||||
isAutoWarp: true,
|
bordered: true,
|
||||||
),
|
noGrow: true,
|
||||||
],
|
maxHeight: 520,
|
||||||
),
|
listPadding: const EdgeInsets.only(top: 8),
|
||||||
)
|
),
|
||||||
],
|
if (!hasMerged && !isCompact) const Gap(12),
|
||||||
).opacity(isPending ? 0.5 : 1),
|
],
|
||||||
if (data.preload?.attachments?.isNotEmpty ?? false)
|
),
|
||||||
AttachmentList(
|
|
||||||
data: data.preload!.attachments!,
|
|
||||||
bordered: true,
|
|
||||||
noGrow: true,
|
|
||||||
maxHeight: 520,
|
|
||||||
listPadding: const EdgeInsets.only(top: 8),
|
|
||||||
),
|
|
||||||
if (!hasMerged && !isCompact) const Gap(12),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ class ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
bool _isBusy = false;
|
bool _isBusy = false;
|
||||||
double? _progress;
|
double? _progress;
|
||||||
|
|
||||||
SnChatMessage? _replyingMessage;
|
SnChatMessage? _replyingMessage, _editingMessage;
|
||||||
|
|
||||||
final TextEditingController _contentController = TextEditingController();
|
final TextEditingController _contentController = TextEditingController();
|
||||||
final FocusNode _focusNode = FocusNode();
|
final FocusNode _focusNode = FocusNode();
|
||||||
@ -34,6 +34,26 @@ class ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
setState(() => _replyingMessage = value);
|
setState(() => _replyingMessage = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setEdit(SnChatMessage? value) {
|
||||||
|
setState(() => _editingMessage = value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteMessage(SnChatMessage message) async {
|
||||||
|
final confirm = await context.showConfirmDialog(
|
||||||
|
'messageDelete'.tr(args: ['#${message.id}']),
|
||||||
|
'messageDeleteDescription'.tr(),
|
||||||
|
);
|
||||||
|
if (!confirm) return;
|
||||||
|
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() => _isBusy = true);
|
||||||
|
|
||||||
|
await widget.controller.deleteMessage(message);
|
||||||
|
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() => _isBusy = false);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _sendMessage() async {
|
Future<void> _sendMessage() async {
|
||||||
if (_isBusy) return;
|
if (_isBusy) return;
|
||||||
|
|
||||||
@ -89,10 +109,13 @@ class ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
.where((e) => e.attachment != null)
|
.where((e) => e.attachment != null)
|
||||||
.map((e) => e.attachment!.rid)
|
.map((e) => e.attachment!.rid)
|
||||||
.toList(),
|
.toList(),
|
||||||
|
relatedId: _editingMessage?.id,
|
||||||
quoteId: _replyingMessage?.id,
|
quoteId: _replyingMessage?.id,
|
||||||
|
editingMessage: _editingMessage,
|
||||||
);
|
);
|
||||||
_contentController.clear();
|
_contentController.clear();
|
||||||
_attachments.clear();
|
_attachments.clear();
|
||||||
|
_editingMessage = null;
|
||||||
_replyingMessage = null;
|
_replyingMessage = null;
|
||||||
|
|
||||||
setState(() => _isBusy = false);
|
setState(() => _isBusy = false);
|
||||||
@ -184,6 +207,42 @@ class ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
),
|
),
|
||||||
).height(_replyingMessage != null ? 54 + 8 : 0, animate: true).animate(
|
).height(_replyingMessage != null ? 54 + 8 : 0, animate: true).animate(
|
||||||
const Duration(milliseconds: 300), Curves.fastEaseInToSlowEaseOut),
|
const Duration(milliseconds: 300), Curves.fastEaseInToSlowEaseOut),
|
||||||
|
SingleChildScrollView(
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
child: Padding(
|
||||||
|
padding: _editingMessage != null
|
||||||
|
? const EdgeInsets.only(top: 8)
|
||||||
|
: EdgeInsets.zero,
|
||||||
|
child: _editingMessage != null
|
||||||
|
? MaterialBanner(
|
||||||
|
padding: const EdgeInsets.only(left: 16.0),
|
||||||
|
leading: const Icon(Symbols.edit),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (_editingMessage?.body['text'] != null)
|
||||||
|
MarkdownTextContent(
|
||||||
|
content: _editingMessage?.body['text'],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
child: Text('cancel'.tr()),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() => _editingMessage = null);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
),
|
||||||
|
).height(_editingMessage != null ? 54 + 8 : 0, animate: true).animate(
|
||||||
|
const Duration(milliseconds: 300), Curves.fastEaseInToSlowEaseOut),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 56,
|
height: 56,
|
||||||
child: Row(
|
child: Row(
|
||||||
|
@ -248,7 +248,7 @@ class _PostContentHeader extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
const Icon(Symbols.reply),
|
const Icon(Symbols.reply),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
Text('reply').tr(),
|
Text('replyPost').tr(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
@ -76,11 +76,15 @@ class PostMediaPendingListRaw extends StatelessWidget {
|
|||||||
final media = attachments[idx];
|
final media = attachments[idx];
|
||||||
final result = (!kIsWeb && (Platform.isIOS || Platform.isMacOS))
|
final result = (!kIsWeb && (Platform.isIOS || Platform.isMacOS))
|
||||||
? await showCupertinoImageCropper(
|
? await showCupertinoImageCropper(
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
context,
|
context,
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
imageProvider: media.getImageProvider(context)!,
|
imageProvider: media.getImageProvider(context)!,
|
||||||
)
|
)
|
||||||
: await showMaterialImageCropper(
|
: await showMaterialImageCropper(
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
context,
|
context,
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
imageProvider: media.getImageProvider(context)!,
|
imageProvider: media.getImageProvider(context)!,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user