fix: solve small pm chat ui issues
unwrap the pill fix the fetching images in pm not auto download
This commit is contained in:
@@ -133,6 +133,8 @@ When the user navigates to a room, the manager watches the route and decides whi
|
||||
|
||||
The decision lives in `shouldAutoRequestWhenWatched()` which calls `isAttachmentMedia()` and checks against `MAX_AUTO_SAVE_SIZE_BYTES`.
|
||||
|
||||
Direct-message routes (`/dm/:conversationId` and `/pm/:conversationId`) are treated as watched attachment containers named `direct-message:<conversationId>`, so image/video metadata announced for the visible conversation is eligible for the same automatic request path as server-room media.
|
||||
|
||||
Browser chat views render audio/video larger than 50 MB with the same generic file interface as other downloads, even after the bytes are available. Attachments with audio/video MIME types that Chromium reports as unsupported also use the generic file interface instead of a broken native player.
|
||||
|
||||
An optional experimental VLC.js adapter can be enabled from General settings. When enabled, unsupported downloaded audio/video files show a manual Play action that lazy-loads `/vlcjs/metoyou-vlc-player.js`. The runtime is intentionally isolated in the experimental media domain and is not part of the default attachment path.
|
||||
|
||||
@@ -6,8 +6,11 @@ import {
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { RealtimeSessionFacade } from '../../../../core/realtime';
|
||||
import { DatabaseService } from '../../../../infrastructure/persistence';
|
||||
import { ROOM_URL_PATTERN } from '../../../../core/constants';
|
||||
import { shouldAutoRequestWhenWatched } from '../../domain/logic/attachment.logic';
|
||||
import {
|
||||
getWatchedAttachmentRoomIdFromUrl,
|
||||
isDirectMessageAttachmentRoomId,
|
||||
shouldAutoRequestWhenWatched
|
||||
} from '../../domain/logic/attachment.logic';
|
||||
import type { Attachment, AttachmentMeta } from '../../domain/models/attachment.model';
|
||||
import type {
|
||||
FileAnnouncePayload,
|
||||
@@ -182,6 +185,11 @@ export class AttachmentManagerService {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDirectMessageAttachmentRoomId(roomId)) {
|
||||
await this.requestAutoDownloadsForRuntimeRoom(roomId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.database.isReady()) {
|
||||
const messages = await this.database.getMessages(roomId, 500, 0);
|
||||
|
||||
@@ -193,6 +201,10 @@ export class AttachmentManagerService {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.requestAutoDownloadsForRuntimeRoom(roomId);
|
||||
}
|
||||
|
||||
private async requestAutoDownloadsForRuntimeRoom(roomId: string): Promise<void> {
|
||||
for (const [messageId] of this.runtimeStore.getAttachmentEntries()) {
|
||||
const attachmentRoomId = await this.persistence.resolveMessageRoomId(messageId);
|
||||
|
||||
@@ -235,9 +247,7 @@ export class AttachmentManagerService {
|
||||
}
|
||||
|
||||
private extractWatchedRoomId(url: string): string | null {
|
||||
const roomMatch = url.match(ROOM_URL_PATTERN);
|
||||
|
||||
return roomMatch ? roomMatch[1] : null;
|
||||
return getWatchedAttachmentRoomIdFromUrl(url);
|
||||
}
|
||||
|
||||
private isRoomWatched(roomId: string | null | undefined): boolean {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { getWatchedAttachmentRoomIdFromUrl, isDirectMessageAttachmentRoomId } from './attachment.logic';
|
||||
|
||||
describe('attachment logic', () => {
|
||||
it('extracts watched server room ids from room URLs', () => {
|
||||
expect(getWatchedAttachmentRoomIdFromUrl('/room/general')).toBe('general');
|
||||
expect(getWatchedAttachmentRoomIdFromUrl('/room/general/chat')).toBe('general');
|
||||
});
|
||||
|
||||
it('extracts watched direct-message storage ids from DM URLs', () => {
|
||||
expect(getWatchedAttachmentRoomIdFromUrl('/dm/alice%3Abob')).toBe('direct-message:alice:bob');
|
||||
expect(getWatchedAttachmentRoomIdFromUrl('/pm/dm-group-1?tab=chat')).toBe('direct-message:dm-group-1');
|
||||
});
|
||||
|
||||
it('ignores non-message URLs', () => {
|
||||
expect(getWatchedAttachmentRoomIdFromUrl('/settings')).toBeNull();
|
||||
expect(getWatchedAttachmentRoomIdFromUrl('/dm')).toBeNull();
|
||||
});
|
||||
|
||||
it('identifies direct-message attachment storage ids', () => {
|
||||
expect(isDirectMessageAttachmentRoomId('direct-message:alice:bob')).toBe(true);
|
||||
expect(isDirectMessageAttachmentRoomId('room-1')).toBe(false);
|
||||
expect(isDirectMessageAttachmentRoomId(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,10 @@
|
||||
import { MAX_AUTO_SAVE_SIZE_BYTES } from '../constants/attachment.constants';
|
||||
import type { Attachment } from '../models/attachment.model';
|
||||
|
||||
const ROOM_URL_PATTERN = /\/room\/([^/]+)/;
|
||||
const DIRECT_MESSAGE_URL_PATTERN = /^\/(?:dm|pm)\/([^/]+)/;
|
||||
const DIRECT_MESSAGE_ATTACHMENT_STORAGE_PREFIX = 'direct-message:';
|
||||
|
||||
export function isAttachmentMedia(attachment: Pick<Attachment, 'mime'>): boolean {
|
||||
return attachment.mime.startsWith('image/') ||
|
||||
attachment.mime.startsWith('video/') ||
|
||||
@@ -17,3 +21,28 @@ export function shouldPersistDownloadedAttachment(attachment: Pick<Attachment, '
|
||||
attachment.mime.startsWith('video/') ||
|
||||
attachment.mime.startsWith('audio/');
|
||||
}
|
||||
|
||||
export function getWatchedAttachmentRoomIdFromUrl(url: string): string | null {
|
||||
const path = url.split(/[?#]/, 1)[0];
|
||||
const directMessageMatch = path.match(DIRECT_MESSAGE_URL_PATTERN);
|
||||
|
||||
if (directMessageMatch) {
|
||||
return `${DIRECT_MESSAGE_ATTACHMENT_STORAGE_PREFIX}${decodeUrlSegment(directMessageMatch[1])}`;
|
||||
}
|
||||
|
||||
const roomMatch = path.match(ROOM_URL_PATTERN);
|
||||
|
||||
return roomMatch ? decodeUrlSegment(roomMatch[1]) : null;
|
||||
}
|
||||
|
||||
export function isDirectMessageAttachmentRoomId(roomId: string | null | undefined): boolean {
|
||||
return !!roomId && roomId.startsWith(DIRECT_MESSAGE_ATTACHMENT_STORAGE_PREFIX);
|
||||
}
|
||||
|
||||
function decodeUrlSegment(value: string): string {
|
||||
try {
|
||||
return decodeURIComponent(value);
|
||||
} catch {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user