forked from cwtch.im/cwtch-ui
new message marker moved from id to index and now works on old messages
This commit is contained in:
parent
0647a2d98d
commit
ffa51e83a1
|
@ -42,7 +42,7 @@ class ContactInfoState extends ChangeNotifier {
|
||||||
late int _totalMessages = 0;
|
late int _totalMessages = 0;
|
||||||
late DateTime _lastMessageTime;
|
late DateTime _lastMessageTime;
|
||||||
late Map<String, GlobalKey<MessageRowState>> keys;
|
late Map<String, GlobalKey<MessageRowState>> keys;
|
||||||
int _newMarkerMsgId = -1;
|
int _newMarkerMsgIndex = -1;
|
||||||
late MessageCache messageCache;
|
late MessageCache messageCache;
|
||||||
|
|
||||||
// todo: a nicer way to model contacts, groups and other "entities"
|
// todo: a nicer way to model contacts, groups and other "entities"
|
||||||
|
@ -145,11 +145,12 @@ class ContactInfoState extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
void selected() {
|
void selected() {
|
||||||
|
this._newMarkerMsgIndex = this._unreadMessages-1;
|
||||||
this._unreadMessages = 0;
|
this._unreadMessages = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unselected() {
|
void unselected() {
|
||||||
this._newMarkerMsgId = -1;
|
this._newMarkerMsgIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get unreadMessages => this._unreadMessages;
|
int get unreadMessages => this._unreadMessages;
|
||||||
|
@ -159,8 +160,8 @@ class ContactInfoState extends ChangeNotifier {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
int get newMarkerMsgId {
|
int get newMarkerMsgIndex {
|
||||||
return this._newMarkerMsgId;
|
return this._newMarkerMsgIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get totalMessages => this._totalMessages;
|
int get totalMessages => this._totalMessages;
|
||||||
|
@ -240,8 +241,10 @@ class ContactInfoState extends ChangeNotifier {
|
||||||
if (!selectedConversation) {
|
if (!selectedConversation) {
|
||||||
unreadMessages++;
|
unreadMessages++;
|
||||||
}
|
}
|
||||||
if (_newMarkerMsgId == -1) {
|
if (_newMarkerMsgIndex == -1) {
|
||||||
_newMarkerMsgId = messageID;
|
_newMarkerMsgIndex = 0;
|
||||||
|
} else {
|
||||||
|
_newMarkerMsgIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._lastMessageTime = timestamp;
|
this._lastMessageTime = timestamp;
|
||||||
|
|
|
@ -32,33 +32,34 @@ const GroupConversationHandleLength = 32;
|
||||||
abstract class Message {
|
abstract class Message {
|
||||||
MessageMetadata getMetadata();
|
MessageMetadata getMetadata();
|
||||||
|
|
||||||
Widget getWidget(BuildContext context, Key key);
|
Widget getWidget(BuildContext context, Key key, int index);
|
||||||
|
|
||||||
Widget getPreviewWidget(BuildContext context);
|
Widget getPreviewWidget(BuildContext context);
|
||||||
}
|
}
|
||||||
|
|
||||||
Message compileOverlay(MessageMetadata metadata, String messageData) {
|
Message compileOverlay(MessageInfo messageInfo) {
|
||||||
try {
|
|
||||||
dynamic message = jsonDecode(messageData);
|
try {
|
||||||
|
dynamic message = jsonDecode(messageInfo.wrapper);
|
||||||
var content = message['d'] as dynamic;
|
var content = message['d'] as dynamic;
|
||||||
var overlay = int.parse(message['o'].toString());
|
var overlay = int.parse(message['o'].toString());
|
||||||
|
|
||||||
switch (overlay) {
|
switch (overlay) {
|
||||||
case TextMessageOverlay:
|
case TextMessageOverlay:
|
||||||
return TextMessage(metadata, content);
|
return TextMessage(messageInfo.metadata, content);
|
||||||
case SuggestContactOverlay:
|
case SuggestContactOverlay:
|
||||||
case InviteGroupOverlay:
|
case InviteGroupOverlay:
|
||||||
return InviteMessage(overlay, metadata, content);
|
return InviteMessage(overlay, messageInfo.metadata, content);
|
||||||
case QuotedMessageOverlay:
|
case QuotedMessageOverlay:
|
||||||
return QuotedMessage(metadata, content);
|
return QuotedMessage(messageInfo.metadata, content);
|
||||||
case FileShareOverlay:
|
case FileShareOverlay:
|
||||||
return FileMessage(metadata, content);
|
return FileMessage(messageInfo.metadata, content);
|
||||||
default:
|
default:
|
||||||
// Metadata is valid, content is not..
|
// Metadata is valid, content is not..
|
||||||
return MalformedMessage(metadata);
|
return MalformedMessage(messageInfo.metadata);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return MalformedMessage(metadata);
|
return MalformedMessage(messageInfo.metadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +223,7 @@ Future<Message> messageHandler(BuildContext context, String profileOnion, int co
|
||||||
MessageInfo? messageInfo = await cacheHandler.get(cwtch, profileOnion, conversationIdentifier, cache);
|
MessageInfo? messageInfo = await cacheHandler.get(cwtch, profileOnion, conversationIdentifier, cache);
|
||||||
|
|
||||||
if (messageInfo != null) {
|
if (messageInfo != null) {
|
||||||
return compileOverlay(messageInfo.metadata, messageInfo.wrapper);
|
return compileOverlay(messageInfo);
|
||||||
} else {
|
} else {
|
||||||
return MalformedMessage(malformedMetadata);
|
return MalformedMessage(malformedMetadata);
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,13 +105,6 @@ class MessageCache extends ChangeNotifier {
|
||||||
|
|
||||||
int get indexUnsynced => _indexUnsynced;
|
int get indexUnsynced => _indexUnsynced;
|
||||||
|
|
||||||
// TODO: unused? delete?
|
|
||||||
void resetIndexCache() {
|
|
||||||
this._indexUnsynced = 0;
|
|
||||||
cacheByIndex = List.empty(growable: true);
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageInfo? getById(int id) => cache[id];
|
MessageInfo? getById(int id) => cache[id];
|
||||||
|
|
||||||
Future<MessageInfo?> getByIndex(int index) async {
|
Future<MessageInfo?> getByIndex(int index) async {
|
||||||
|
|
|
@ -18,13 +18,13 @@ class FileMessage extends Message {
|
||||||
FileMessage(this.metadata, this.content);
|
FileMessage(this.metadata, this.content);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget getWidget(BuildContext context, Key key) {
|
Widget getWidget(BuildContext context, Key key, int index) {
|
||||||
return ChangeNotifierProvider.value(
|
return ChangeNotifierProvider.value(
|
||||||
value: this.metadata,
|
value: this.metadata,
|
||||||
builder: (bcontext, child) {
|
builder: (bcontext, child) {
|
||||||
dynamic shareObj = jsonDecode(this.content);
|
dynamic shareObj = jsonDecode(this.content);
|
||||||
if (shareObj == null) {
|
if (shareObj == null) {
|
||||||
return MessageRow(MalformedBubble());
|
return MessageRow(MalformedBubble(), index);
|
||||||
}
|
}
|
||||||
String nameSuggestion = shareObj['f'] as String;
|
String nameSuggestion = shareObj['f'] as String;
|
||||||
String rootHash = shareObj['h'] as String;
|
String rootHash = shareObj['h'] as String;
|
||||||
|
@ -39,10 +39,10 @@ class FileMessage extends Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validHash(rootHash, nonce)) {
|
if (!validHash(rootHash, nonce)) {
|
||||||
return MessageRow(MalformedBubble());
|
return MessageRow(MalformedBubble(), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MessageRow(FileBubble(nameSuggestion, rootHash, nonce, fileSize, isAuto: metadata.isAuto), key: key);
|
return MessageRow(FileBubble(nameSuggestion, rootHash, nonce, fileSize, isAuto: metadata.isAuto), index, key: key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,14 +53,14 @@ class FileMessage extends Message {
|
||||||
builder: (bcontext, child) {
|
builder: (bcontext, child) {
|
||||||
dynamic shareObj = jsonDecode(this.content);
|
dynamic shareObj = jsonDecode(this.content);
|
||||||
if (shareObj == null) {
|
if (shareObj == null) {
|
||||||
return MessageRow(MalformedBubble());
|
return MessageRow(MalformedBubble(), 0);
|
||||||
}
|
}
|
||||||
String nameSuggestion = shareObj['n'] as String;
|
String nameSuggestion = shareObj['n'] as String;
|
||||||
String rootHash = shareObj['h'] as String;
|
String rootHash = shareObj['h'] as String;
|
||||||
String nonce = shareObj['n'] as String;
|
String nonce = shareObj['n'] as String;
|
||||||
int fileSize = shareObj['s'] as int;
|
int fileSize = shareObj['s'] as int;
|
||||||
if (!validHash(rootHash, nonce)) {
|
if (!validHash(rootHash, nonce)) {
|
||||||
return MessageRow(MalformedBubble());
|
return MessageRow(MalformedBubble(), 0);
|
||||||
}
|
}
|
||||||
return Container(
|
return Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
|
|
|
@ -17,7 +17,7 @@ class InviteMessage extends Message {
|
||||||
InviteMessage(this.overlay, this.metadata, this.content);
|
InviteMessage(this.overlay, this.metadata, this.content);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget getWidget(BuildContext context, Key key) {
|
Widget getWidget(BuildContext context, Key key, int index) {
|
||||||
return ChangeNotifierProvider.value(
|
return ChangeNotifierProvider.value(
|
||||||
value: this.metadata,
|
value: this.metadata,
|
||||||
builder: (bcontext, child) {
|
builder: (bcontext, child) {
|
||||||
|
@ -36,10 +36,10 @@ class InviteMessage extends Message {
|
||||||
inviteTarget = jsonObj['GroupID'];
|
inviteTarget = jsonObj['GroupID'];
|
||||||
inviteNick = jsonObj['GroupName'];
|
inviteNick = jsonObj['GroupName'];
|
||||||
} else {
|
} else {
|
||||||
return MessageRow(MalformedBubble());
|
return MessageRow(MalformedBubble(), index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MessageRow(InvitationBubble(overlay, inviteTarget, inviteNick, invite), key: key);
|
return MessageRow(InvitationBubble(overlay, inviteTarget, inviteNick, invite), index, key: key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,11 @@ class MalformedMessage extends Message {
|
||||||
MalformedMessage(this.metadata);
|
MalformedMessage(this.metadata);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget getWidget(BuildContext context, Key key) {
|
Widget getWidget(BuildContext context, Key key, int index) {
|
||||||
return ChangeNotifierProvider.value(
|
return ChangeNotifierProvider.value(
|
||||||
value: this.metadata,
|
value: this.metadata,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
return MessageRow(MalformedBubble(), key: key);
|
return MessageRow(MalformedBubble(), index, key: key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ class QuotedMessage extends Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget getWidget(BuildContext context, Key key) {
|
Widget getWidget(BuildContext context, Key key, int index) {
|
||||||
try {
|
try {
|
||||||
dynamic message = jsonDecode(this.content);
|
dynamic message = jsonDecode(this.content);
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ class QuotedMessage extends Message {
|
||||||
return ChangeNotifierProvider.value(
|
return ChangeNotifierProvider.value(
|
||||||
value: this.metadata,
|
value: this.metadata,
|
||||||
builder: (bcontext, child) {
|
builder: (bcontext, child) {
|
||||||
return MessageRow(QuotedMessageBubble(message["body"], messageHandler(bcontext, metadata.profileOnion, metadata.conversationIdentifier, ByContentHash(message["quotedHash"]))), key: key);
|
return MessageRow(QuotedMessageBubble(message["body"], messageHandler(bcontext, metadata.profileOnion, metadata.conversationIdentifier, ByContentHash(message["quotedHash"]))), index, key: key);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return MalformedBubble();
|
return MalformedBubble();
|
||||||
|
|
|
@ -29,12 +29,12 @@ class TextMessage extends Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget getWidget(BuildContext context, Key key) {
|
Widget getWidget(BuildContext context, Key key, int index) {
|
||||||
return ChangeNotifierProvider.value(
|
return ChangeNotifierProvider.value(
|
||||||
value: this.metadata,
|
value: this.metadata,
|
||||||
builder: (bcontext, child) {
|
builder: (bcontext, child) {
|
||||||
return MessageRow(
|
return MessageRow(
|
||||||
MessageBubble(this.content),
|
MessageBubble(this.content), index,
|
||||||
key: key,
|
key: key,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -100,7 +100,7 @@ class _MessageListState extends State<MessageList> {
|
||||||
// reliably use this without running into duplicate keys...it isn't ideal as it means keys need to be re-built
|
// reliably use this without running into duplicate keys...it isn't ideal as it means keys need to be re-built
|
||||||
// when new messages are added...however it is better than the alternative of not having widget keys at all.
|
// when new messages are added...however it is better than the alternative of not having widget keys at all.
|
||||||
var key = Provider.of<ContactInfoState>(outerContext, listen: false).getMessageKey(contactHandle, messageIndex);
|
var key = Provider.of<ContactInfoState>(outerContext, listen: false).getMessageKey(contactHandle, messageIndex);
|
||||||
return message.getWidget(context, key);
|
return message.getWidget(context, key, messageIndex);
|
||||||
} else {
|
} else {
|
||||||
return MessageLoadingBubble();
|
return MessageLoadingBubble();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,9 @@ import '../settings.dart';
|
||||||
|
|
||||||
class MessageRow extends StatefulWidget {
|
class MessageRow extends StatefulWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
final int index;
|
||||||
|
|
||||||
MessageRow(this.child, {Key? key}) : super(key: key);
|
MessageRow(this.child, this.index, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MessageRowState createState() => MessageRowState();
|
MessageRowState createState() => MessageRowState();
|
||||||
|
@ -32,12 +33,9 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
|
||||||
late Alignment _dragAlignment = Alignment.center;
|
late Alignment _dragAlignment = Alignment.center;
|
||||||
Alignment _dragAffinity = Alignment.center;
|
Alignment _dragAffinity = Alignment.center;
|
||||||
|
|
||||||
late int index;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
index = Provider.of<MessageMetadata>(context, listen: false).messageID;
|
|
||||||
_controller = AnimationController(vsync: this);
|
_controller = AnimationController(vsync: this);
|
||||||
_controller.addListener(() {
|
_controller.addListener(() {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -224,8 +222,7 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
|
||||||
children: widgetRow,
|
children: widgetRow,
|
||||||
)))));
|
)))));
|
||||||
|
|
||||||
var markMsgId = Provider.of<ContactInfoState>(context).newMarkerMsgId;
|
if (Provider.of<ContactInfoState>(context).newMarkerMsgIndex == widget.index) {
|
||||||
if (markMsgId == Provider.of<MessageMetadata>(context).messageID) {
|
|
||||||
return Column(crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [Align(alignment: Alignment.center, child: _bubbleNew()), mr]);
|
return Column(crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [Align(alignment: Alignment.center, child: _bubbleNew()), mr]);
|
||||||
} else {
|
} else {
|
||||||
return mr;
|
return mr;
|
||||||
|
|
Loading…
Reference in New Issue