diff --git a/src/components/messages/MessageViewer.vue b/src/components/messages/MessageViewer.vue
index f9e0336..d15865c 100644
--- a/src/components/messages/MessageViewer.vue
+++ b/src/components/messages/MessageViewer.vue
@@ -124,6 +124,7 @@ export default {
data() {
return {
+ isActive: false,
messages: [],
messagesSubscription: null,
@@ -148,10 +149,15 @@ export default {
},
activated() {
+ this.isActive = true;
+
// update read state when coming back to message viewer
- Database.NodeMessagesReadState.touch(this.nodeId);
+ this.updateMessagesLastReadAt();
},
+ deactivated() {
+ this.isActive = false;
+ },
methods: {
async sendMessage() {
@@ -229,7 +235,7 @@ export default {
this.scrollMessagesToBottom();
// update read state since we auto scrolled to bottom of new messages
- Database.NodeMessagesReadState.touch(this.nodeId);
+ this.updateMessagesLastReadAt();
}
@@ -255,7 +261,7 @@ export default {
// update read state since we scrolled to bottom
if(isAtBottom){
- Database.NodeMessagesReadState.touch(this.nodeId);
+ this.updateMessagesLastReadAt();
}
},
@@ -265,6 +271,17 @@ export default {
container.scrollTop = container.scrollHeight;
});
},
+ updateMessagesLastReadAt() {
+
+ // do nothing if route is not active
+ if(!this.isActive){
+ return;
+ }
+
+ // update last read at
+ Database.NodeMessagesReadState.touch(this.nodeId);
+
+ },
},
computed: {
Protobuf() {
diff --git a/src/components/nodes/NodeListItem.vue b/src/components/nodes/NodeListItem.vue
index 15d280b..97921d2 100644
--- a/src/components/nodes/NodeListItem.vue
+++ b/src/components/nodes/NodeListItem.vue
@@ -44,6 +44,14 @@
+
+
@@ -110,6 +118,8 @@ import NodeDropDownMenu from "./NodeDropDownMenu.vue";
import GlobalState from "../../js/GlobalState.js";
import TimeUtils from "../../js/TimeUtils.js";
import moment from "moment";
+import Database from "../../js/Database.js";
+import Connection from "../../js/Connection.js";
export default {
name: 'NodeListItem',
@@ -120,6 +130,22 @@ export default {
props: {
node: Object,
},
+ data() {
+ return {
+ unreadMessagesCount: 0,
+ nodeMessagesReadStateSubscription: null,
+ };
+ },
+ mounted() {
+ Connection.addMessageListener(this.onMessage);
+ this.nodeMessagesReadStateSubscription = Database.NodeMessagesReadState.get(this.node.num).$.subscribe(async (nodeMessagesReadState) => {
+ await this.onNodeMessagesReadStateChange(nodeMessagesReadState);
+ });
+ },
+ unmounted() {
+ Connection.removeMessageListener(this.onMessage);
+ this.nodeMessagesReadStateSubscription?.unsubscribe();
+ },
methods: {
getNodeLongName: (nodeId) => NodeUtils.getNodeLongName(nodeId),
formatUnixSecondsAgo(unixSeconds) {
@@ -132,6 +158,17 @@ export default {
return "Unknown";
},
+ async onMessage() {
+ const nodeMessagesReadState = await Database.NodeMessagesReadState.get(this.node.num).exec();
+ await this.onNodeMessagesReadStateChange(nodeMessagesReadState);
+ },
+ async updateUnreadMessagesCount(lastReadTimestamp) {
+ this.unreadMessagesCount = await Database.Message.getNodeMessagesUnreadCount(this.node.num, lastReadTimestamp).exec();
+ },
+ async onNodeMessagesReadStateChange(nodeMessagesReadState) {
+ const messagesLastReadTimestamp = nodeMessagesReadState?.timestamp ?? 0;
+ await this.updateUnreadMessagesCount(messagesLastReadTimestamp);
+ },
},
computed: {
GlobalState() {
diff --git a/src/js/Connection.js b/src/js/Connection.js
index 3743128..3bf5463 100644
--- a/src/js/Connection.js
+++ b/src/js/Connection.js
@@ -5,6 +5,7 @@ import Database from "./Database.js";
class Connection {
static clientNotificationListeners = [];
+ static messageListeners = [];
static traceRouteListeners = [];
static addClientNotificationListener(listener) {
@@ -17,6 +18,16 @@ class Connection {
});
}
+ static addMessageListener(listener) {
+ this.messageListeners.push(listener);
+ }
+
+ static removeMessageListener(listenerToRemove) {
+ this.messageListeners = this.messageListeners.filter((listener) => {
+ return listener !== listenerToRemove;
+ });
+ }
+
static addTraceRouteListener(listener) {
this.traceRouteListeners.push(listener);
}
@@ -231,6 +242,11 @@ class Connection {
connection.events.onMessagePacket.subscribe(async (data) => {
console.log("onMessagePacket", data);
await Database.Message.insert(data);
+ for(const messageListener of this.messageListeners){
+ try {
+ messageListener(data);
+ } catch(e){}
+ }
});
// listen for device status changes
diff --git a/src/js/Database.js b/src/js/Database.js
index 6aff864..7b83ba8 100644
--- a/src/js/Database.js
+++ b/src/js/Database.js
@@ -23,6 +23,7 @@ async function initDatabase(nodeId) {
database = await createRxDatabase({
name: `meshtxt_db_node_${nodeId}`,
storage: getRxStorageDexie(),
+ allowSlowCount: true, // fixme: figure out why rxdb complains about indexes when they existed during testing...
});
// add database schemas
@@ -265,6 +266,23 @@ class Message {
});
}
+ // get unread direct messages count for the provided node id
+ static getNodeMessagesUnreadCount(nodeId, messagesLastReadTimestamp) {
+ return database.messages.count({
+ selector: {
+ timestamp: {
+ $gt: messagesLastReadTimestamp,
+ },
+ from: {
+ $eq: nodeId,
+ },
+ to: {
+ $eq: GlobalState.myNodeId,
+ },
+ },
+ });
+ }
+
}
class TraceRoute {
@@ -340,6 +358,17 @@ class NodeMessagesReadState {
});
}
+ // get the read state of messages for the provided node id
+ static get(nodeId) {
+ return database.node_messages_read_state.findOne({
+ selector: {
+ id: {
+ $eq: nodeId.toString(),
+ },
+ },
+ });
+ }
+
}
export default {