diff --git a/core/templates/partials/compose-panel.html b/core/templates/partials/compose-panel.html
index ef56c70..b7eaeee 100644
--- a/core/templates/partials/compose-panel.html
+++ b/core/templates/partials/compose-panel.html
@@ -257,6 +257,14 @@
{{ msg.source_label }}
+ {% if msg.block_gap_display %}
+
+
+ {{ msg.block_gap_display }}
+
+ {% endif %}
{% if msg.image_urls %}
{% for image_url in msg.image_urls %}
@@ -462,6 +470,20 @@
justify-content: flex-start;
margin-bottom: 0.36rem;
}
+ #{{ panel_id }} .compose-block-gap {
+ margin: -0.12rem 0 0.26rem;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.22rem;
+ font-size: 0.64rem;
+ line-height: 1.1;
+ color: #5f6c7d;
+ opacity: 0.95;
+ }
+ #{{ panel_id }} .compose-block-gap-val {
+ font-weight: 700;
+ letter-spacing: 0.01em;
+ }
#{{ panel_id }} .compose-source-badge {
font-size: 0.84rem;
padding: 0.12rem 0.5rem;
@@ -1815,6 +1837,22 @@
badgeWrap.appendChild(badge);
bubble.appendChild(badgeWrap);
}
+ if (msg.block_gap_display) {
+ const blockGap = document.createElement("p");
+ blockGap.className = "compose-block-gap";
+ blockGap.title = "Time since previous message in this sender block";
+ const icon = document.createElement("span");
+ icon.className = "icon is-small";
+ const i = document.createElement("i");
+ i.className = "fa-regular fa-hourglass-half";
+ icon.appendChild(i);
+ const value = document.createElement("span");
+ value.className = "compose-block-gap-val";
+ value.textContent = String(msg.block_gap_display || "");
+ blockGap.appendChild(icon);
+ blockGap.appendChild(value);
+ bubble.appendChild(blockGap);
+ }
const imageCandidatesFromPayload = Array.isArray(msg.image_urls) && msg.image_urls.length
? msg.image_urls
: (msg.image_url ? [msg.image_url] : []);
@@ -1858,7 +1896,7 @@
icon.appendChild(i);
const timeSpan = document.createElement("span");
timeSpan.className = "compose-tick-time";
- timeSpan.textContent = String(msg.read_display || "");
+ timeSpan.textContent = String(msg.read_delta_display || "");
tickWrap.appendChild(icon);
tickWrap.appendChild(timeSpan);
meta.appendChild(document.createTextNode(" "));
@@ -1874,7 +1912,7 @@
icon.appendChild(i);
const timeSpan = document.createElement("span");
timeSpan.className = "compose-tick-time";
- timeSpan.textContent = String(msg.delivered_display || "");
+ timeSpan.textContent = String(msg.delivered_delta_display || "");
tickWrap.appendChild(icon);
tickWrap.appendChild(timeSpan);
meta.appendChild(document.createTextNode(" "));
diff --git a/core/views/compose.py b/core/views/compose.py
index 60cb3d6..b5e00b2 100644
--- a/core/views/compose.py
+++ b/core/views/compose.py
@@ -730,6 +730,8 @@ def _serialize_messages_with_artifacts(
for item in serialized:
item["gap_fragments"] = []
item["metric_fragments"] = []
+ item["block_gap_ms"] = None
+ item["block_gap_display"] = ""
counterpart_identifiers = set(counterpart_identifiers or [])
snapshot = (
@@ -749,6 +751,17 @@ def _serialize_messages_with_artifacts(
current_outgoing = _message_is_outgoing_for_analysis(
msg, counterpart_identifiers
)
+ if (
+ prev_msg is not None
+ and prev_ts is not None
+ and prev_outgoing is not None
+ and current_outgoing == prev_outgoing
+ and current_ts >= prev_ts
+ ):
+ block_gap_ms = current_ts - prev_ts
+ serialized[idx]["block_gap_ms"] = int(block_gap_ms)
+ serialized[idx]["block_gap_display"] = _format_gap_duration(block_gap_ms)
+
if (
prev_msg is not None
and prev_ts is not None