mirror of
https://git.quad4.io/RNS-Things/MeshChatX.git
synced 2026-10-23 03:31:12 +00:00
feat(conversation): improve ConversationDropDownMenu and ConversationViewer with responsive actions and improved GlobalState handling
This commit is contained in:
3 files changed
+94
-18
No files matched your search
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<DropDownMenu>
|
||||
<DropDownMenu v-if="compact">
|
||||
<template #button>
|
||||
<IconButton>
|
||||
<MaterialDesignIcon icon-name="dots-vertical" class="size-7" />
|
||||
@@ -64,7 +64,7 @@
|
||||
</div>
|
||||
|
||||
<!-- telemetry trust toggle -->
|
||||
<div v-if="GlobalState.config?.telemetry_enabled" class="border-t">
|
||||
<div v-if="GlobalState?.config?.telemetry_enabled" class="border-t">
|
||||
<DropDownMenuItem @click="onToggleTelemetryTrust">
|
||||
<MaterialDesignIcon
|
||||
:icon-name="contact?.is_telemetry_trusted ? 'shield-check' : 'shield-outline'"
|
||||
@@ -80,6 +80,55 @@
|
||||
</div>
|
||||
</template>
|
||||
</DropDownMenu>
|
||||
<div v-else class="flex items-center gap-0.5 sm:gap-1 flex-wrap justify-end max-w-[min(100%,52vw)] sm:max-w-none">
|
||||
<IconButton
|
||||
v-if="hasFailedMessages"
|
||||
:title="$t('messages.retry_failed')"
|
||||
class="shrink-0"
|
||||
@click="$emit('retry-failed')"
|
||||
>
|
||||
<MaterialDesignIcon icon-name="refresh" class="size-5 text-red-500" />
|
||||
</IconButton>
|
||||
<IconButton :title="$t('messages.telemetry_history')" class="shrink-0" @click="$emit('open-telemetry-history')">
|
||||
<MaterialDesignIcon icon-name="satellite-variant" class="size-5" />
|
||||
</IconButton>
|
||||
<IconButton :title="$t('messages.start_call')" class="shrink-0" @click="$emit('start-call')">
|
||||
<MaterialDesignIcon icon-name="phone" class="size-5" />
|
||||
</IconButton>
|
||||
<IconButton :title="$t('messages.share_contact')" class="shrink-0" @click="$emit('share-contact')">
|
||||
<MaterialDesignIcon icon-name="notebook-outline" class="size-5" />
|
||||
</IconButton>
|
||||
<IconButton :title="$t('messages.pop_out_chat')" class="shrink-0" @click="$emit('popout')">
|
||||
<MaterialDesignIcon icon-name="open-in-new" class="size-5" />
|
||||
</IconButton>
|
||||
<IconButton title="Ping Destination" class="shrink-0" @click="onPingDestination">
|
||||
<MaterialDesignIcon icon-name="flash" class="size-5" />
|
||||
</IconButton>
|
||||
<IconButton :title="$t('messages.custom_display_name')" class="shrink-0" @click="onSetCustomDisplayName">
|
||||
<MaterialDesignIcon icon-name="account-edit" class="size-5" />
|
||||
</IconButton>
|
||||
<IconButton v-if="!isBlocked" title="Banish User" class="shrink-0" @click="onBlockDestination">
|
||||
<MaterialDesignIcon icon-name="gavel" class="size-5 text-red-500" />
|
||||
</IconButton>
|
||||
<IconButton v-else title="Lift Banishment" class="shrink-0" @click="onUnblockDestination">
|
||||
<MaterialDesignIcon icon-name="check-circle" class="size-5 text-green-500" />
|
||||
</IconButton>
|
||||
<IconButton title="Delete Message History" class="shrink-0" @click="onDeleteMessageHistory">
|
||||
<MaterialDesignIcon icon-name="delete" class="size-5 text-red-500" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
v-if="GlobalState?.config?.telemetry_enabled"
|
||||
:title="contact?.is_telemetry_trusted ? $t('app.telemetry_trust_revoke') : $t('app.telemetry_trust_grant')"
|
||||
class="shrink-0"
|
||||
@click="onToggleTelemetryTrust"
|
||||
>
|
||||
<MaterialDesignIcon
|
||||
:icon-name="contact?.is_telemetry_trusted ? 'shield-check' : 'shield-outline'"
|
||||
:class="contact?.is_telemetry_trusted ? 'text-blue-500' : 'text-gray-500'"
|
||||
class="size-5"
|
||||
/>
|
||||
</IconButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -108,6 +157,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
compact: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
emits: [
|
||||
"conversation-deleted",
|
||||
@@ -123,6 +176,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
contact: null,
|
||||
GlobalState,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -6,23 +6,23 @@
|
||||
>
|
||||
<!-- banished overlay -->
|
||||
<div
|
||||
v-if="GlobalState.config.banished_effect_enabled && isSelectedPeerBlocked"
|
||||
v-if="GlobalState?.config?.banished_effect_enabled && isSelectedPeerBlocked"
|
||||
class="banished-overlay"
|
||||
:style="{ background: GlobalState.config.banished_color + '33' }"
|
||||
:style="{ background: (GlobalState?.config?.banished_color || '#dc2626') + '33' }"
|
||||
>
|
||||
<span
|
||||
class="banished-text !opacity-100 !text-white !shadow-lg !bg-red-600 !px-4 !py-2 !rounded-xl !border-2 !tracking-widest"
|
||||
:style="{
|
||||
'background-color': GlobalState.config.banished_color,
|
||||
'border-color': GlobalState.config.banished_color,
|
||||
'background-color': GlobalState?.config?.banished_color || '#dc2626',
|
||||
'border-color': GlobalState?.config?.banished_color || '#dc2626',
|
||||
}"
|
||||
>{{ GlobalState.config.banished_text }}</span
|
||||
>{{ GlobalState?.config?.banished_text || "BANISHED" }}</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- header -->
|
||||
<div
|
||||
class="relative z-20 flex items-center px-4 py-3 border-b border-gray-200/60 dark:border-zinc-800/60 bg-white/80 dark:bg-zinc-900/50 backdrop-blur-sm"
|
||||
class="relative z-20 flex flex-wrap items-center gap-y-2 px-3 sm:px-4 py-3 border-b border-gray-200/60 dark:border-zinc-800/60 bg-white/80 dark:bg-zinc-900/50 backdrop-blur-sm"
|
||||
>
|
||||
<!-- peer icon -->
|
||||
<div class="flex-shrink-0 mr-3">
|
||||
@@ -127,6 +127,7 @@
|
||||
<ConversationDropDownMenu
|
||||
v-if="selectedPeer"
|
||||
:peer="selectedPeer"
|
||||
:compact="compactPeerActions"
|
||||
:has-failed-messages="hasFailedOrCancelledMessages"
|
||||
@conversation-deleted="onConversationDeleted"
|
||||
@set-custom-display-name="updateCustomDisplayName"
|
||||
@@ -1563,7 +1564,7 @@
|
||||
:is-sending-message="false"
|
||||
:can-send-message="canSendMessage"
|
||||
:delivery-method="newMessageDeliveryMethod"
|
||||
:compact="isMobile"
|
||||
:compact="compactSendLayout"
|
||||
:sending-tooltip="sendMessagePathfindingTooltip"
|
||||
@send="sendMessage"
|
||||
@delivery-method-changed="newMessageDeliveryMethod = $event"
|
||||
@@ -2268,7 +2269,8 @@ export default {
|
||||
},
|
||||
myLxmfAddressHash: {
|
||||
type: String,
|
||||
required: true,
|
||||
required: false,
|
||||
default: "",
|
||||
},
|
||||
selectedPeer: {
|
||||
type: Object,
|
||||
@@ -2363,14 +2365,22 @@ export default {
|
||||
updateTimer: null,
|
||||
sendStatusUiMs: Date.now(),
|
||||
sendStatusTickInterval: null,
|
||||
windowWidth: typeof window !== "undefined" ? window.innerWidth : 1024,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
compactPeerActions() {
|
||||
return this.windowWidth < 640;
|
||||
},
|
||||
compactSendLayout() {
|
||||
return this.windowWidth < 640;
|
||||
},
|
||||
bubbleStyles() {
|
||||
void GlobalState.detailedOutboundSendStatus;
|
||||
void this.sendStatusUiMs;
|
||||
return (chatItem) => {
|
||||
const styles = {};
|
||||
const cfg = GlobalState?.config;
|
||||
const m = chatItem.lxmf_message;
|
||||
const isFailed = ["cancelled", "failed"].includes(m.state);
|
||||
|
||||
@@ -2380,24 +2390,24 @@ export default {
|
||||
styles["color"] = "#ffffff";
|
||||
return styles;
|
||||
}
|
||||
const color = GlobalState.config.message_failed_bubble_color || "#ef4444";
|
||||
const color = cfg?.message_failed_bubble_color || "#ef4444";
|
||||
styles["background-color"] = color;
|
||||
styles["color"] = "#ffffff";
|
||||
} else if (chatItem.is_outbound) {
|
||||
if (chatItem.lxmf_message?._pendingPathfinding) {
|
||||
if (!this.showRichOutboundPendingUi(chatItem)) {
|
||||
const color = GlobalState.config.message_outbound_bubble_color || "#4f46e5";
|
||||
const color = cfg?.message_outbound_bubble_color || "#4f46e5";
|
||||
styles["background-color"] = color;
|
||||
styles["color"] = "#ffffff";
|
||||
return styles;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
const color = GlobalState.config.message_outbound_bubble_color || "#4f46e5";
|
||||
const color = cfg?.message_outbound_bubble_color || "#4f46e5";
|
||||
styles["background-color"] = color;
|
||||
styles["color"] = "#ffffff";
|
||||
} else if (GlobalState.config.message_inbound_bubble_color) {
|
||||
styles["background-color"] = GlobalState.config.message_inbound_bubble_color;
|
||||
} else if (cfg?.message_inbound_bubble_color) {
|
||||
styles["background-color"] = cfg.message_inbound_bubble_color;
|
||||
}
|
||||
|
||||
return styles;
|
||||
@@ -2701,8 +2711,16 @@ export default {
|
||||
}, 2000);
|
||||
|
||||
this._scheduleOutboundSendStatusTick();
|
||||
|
||||
this._onWindowResize = () => {
|
||||
this.windowWidth = window.innerWidth;
|
||||
};
|
||||
window.addEventListener("resize", this._onWindowResize);
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this._onWindowResize) {
|
||||
window.removeEventListener("resize", this._onWindowResize);
|
||||
}
|
||||
if (this.updateTimer) {
|
||||
clearInterval(this.updateTimer);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<ConversationViewer
|
||||
ref="conversation-viewer"
|
||||
:config="config"
|
||||
:my-lxmf-address-hash="config?.lxmf_address_hash"
|
||||
:my-lxmf-address-hash="config?.lxmf_address_hash || ''"
|
||||
:selected-peer="selectedPeer"
|
||||
:conversations="conversations"
|
||||
@update:selected-peer="onPeerClick"
|
||||
@@ -126,6 +126,10 @@ import WebSocketConnection from "../../js/WebSocketConnection";
|
||||
import MessagesSidebar from "./MessagesSidebar.vue";
|
||||
import ConversationViewer from "./ConversationViewer.vue";
|
||||
import GlobalState, { mergeGlobalConfig } from "../../js/GlobalState";
|
||||
|
||||
function snapshotGlobalConfig() {
|
||||
return GlobalState.config && typeof GlobalState.config === "object" ? { ...GlobalState.config } : {};
|
||||
}
|
||||
import DialogUtils from "../../js/DialogUtils";
|
||||
import GlobalEmitter from "../../js/GlobalEmitter";
|
||||
import ToastUtils from "../../js/ToastUtils";
|
||||
@@ -150,7 +154,7 @@ export default {
|
||||
reloadInterval: null,
|
||||
conversationRefreshTimeout: null,
|
||||
|
||||
config: null,
|
||||
config: snapshotGlobalConfig(),
|
||||
hasLoadedConversations: false,
|
||||
peers: {},
|
||||
selectedPeer: null,
|
||||
@@ -283,8 +287,8 @@ export default {
|
||||
this.config = next;
|
||||
}
|
||||
} catch (e) {
|
||||
// do nothing if failed to load config
|
||||
console.log(e);
|
||||
this.config = snapshotGlobalConfig();
|
||||
}
|
||||
},
|
||||
async onWebsocketMessage(message) {
|
||||
|
||||
Reference in new issue
Block a user