diff --git a/apps/matrix/apps/web/src/lib/components/call/CallView.svelte b/apps/matrix/apps/web/src/lib/components/call/CallView.svelte index c23e14ab9..c1247ea10 100644 --- a/apps/matrix/apps/web/src/lib/components/call/CallView.svelte +++ b/apps/matrix/apps/web/src/lib/components/call/CallView.svelte @@ -6,6 +6,7 @@ MicrophoneSlash, VideoCamera, VideoCameraSlash, + Screencast, User, } from '@manacore/shared-icons'; import { onDestroy } from 'svelte'; @@ -66,6 +67,10 @@ matrixStore.toggleCameraMute(); } + async function handleScreenShare() { + await matrixStore.toggleScreenShare(); + } + function handleHangup() { matrixStore.hangupCall(); onHangup?.(); @@ -108,8 +113,14 @@ {/if}

{call.opponentName || 'Unbekannt'}

-

- {call.type === 'video' ? 'Videoanruf' : 'Sprachanruf'} ยท {getStateText(call.state)} +

+ {call.type === 'video' ? 'Videoanruf' : 'Sprachanruf'} ยท {getStateText(call.state)} + {#if call.isScreenSharing} + + + Bildschirmfreigabe + + {/if}

@@ -189,6 +200,16 @@ {/if} + + + {/if} diff --git a/apps/matrix/apps/web/src/lib/components/chat/Message.svelte b/apps/matrix/apps/web/src/lib/components/chat/Message.svelte index 312cdc44c..e83b59b38 100644 --- a/apps/matrix/apps/web/src/lib/components/chat/Message.svelte +++ b/apps/matrix/apps/web/src/lib/components/chat/Message.svelte @@ -48,9 +48,22 @@ let imageLoading = $state(true); let imageError = $state(false); - // Quick reaction emojis + // Quick reaction emojis (always visible) const quickEmojis = ['๐Ÿ‘', 'โค๏ธ', '๐Ÿ˜‚', '๐Ÿ˜ฎ', '๐Ÿ˜ข', '๐ŸŽ‰']; + // Extended emoji categories for full picker + const emojiCategories = [ + { name: 'Hรคufig', emojis: ['๐Ÿ‘', '๐Ÿ‘Ž', 'โค๏ธ', '๐Ÿ˜‚', '๐Ÿ˜ฎ', '๐Ÿ˜ข', '๐ŸŽ‰', '๐Ÿ”ฅ', '๐Ÿ’ฏ', 'โœจ'] }, + { name: 'Smileys', emojis: ['๐Ÿ˜€', '๐Ÿ˜ƒ', '๐Ÿ˜„', '๐Ÿ˜', '๐Ÿ˜†', '๐Ÿฅน', '๐Ÿ˜…', '๐Ÿคฃ', '๐Ÿ˜Š', '๐Ÿ˜‡', '๐Ÿ™‚', '๐Ÿ˜‰', '๐Ÿ˜Œ', '๐Ÿ˜', '๐Ÿฅฐ', '๐Ÿ˜˜'] }, + { name: 'Gesten', emojis: ['๐Ÿ‘', '๐Ÿ™Œ', '๐Ÿ‘', '๐Ÿค', '๐Ÿ™', 'โœŒ๏ธ', '๐Ÿคž', '๐ŸคŸ', '๐Ÿค˜', '๐Ÿ‘Œ', '๐ŸคŒ', '๐Ÿ‘‹', '๐Ÿ’ช', '๐Ÿ‘€'] }, + { name: 'Symbole', emojis: ['โœ…', 'โŒ', 'โญ', '๐Ÿ’ซ', '๐ŸŒŸ', '๐Ÿ’ก', '๐ŸŽฏ', '๐Ÿš€', '๐Ÿ’Ž', '๐Ÿ†', '๐Ÿ”‘', '๐Ÿ“Œ', '๐Ÿ””', '๐Ÿ’ฌ'] }, + { name: 'Tiere', emojis: ['๐Ÿฑ', '๐Ÿถ', '๐Ÿป', '๐ŸฆŠ', '๐Ÿผ', '๐Ÿจ', '๐Ÿฆ', '๐Ÿธ', '๐Ÿต', '๐Ÿฆ„', '๐Ÿ', '๐Ÿฆ‹'] }, + { name: 'Essen', emojis: ['๐Ÿ•', '๐Ÿ”', '๐ŸŸ', '๐ŸŒฎ', '๐Ÿœ', '๐Ÿฃ', '๐Ÿฆ', '๐Ÿฉ', '๐Ÿช', 'โ˜•', '๐Ÿบ', '๐Ÿท'] }, + ]; + + let showFullPicker = $state(false); + let selectedCategory = $state(0); + async function handleReaction(emoji: string) { showEmojiPicker = false; await matrixStore.reactToMessage(message.id, emoji); @@ -539,23 +552,67 @@
- {#each quickEmojis as emoji} - - {/each} + {#if showFullPicker} + +
+ +
+ {#each emojiCategories as category, i} + + {/each} +
+ +
+ {#each emojiCategories[selectedCategory].emojis as emoji} + + {/each} +
+
+ {:else} + +
+ {#each quickEmojis as emoji} + + {/each} + + +
+ {/if}
{/if} diff --git a/apps/matrix/apps/web/src/lib/components/chat/RoomHeader.svelte b/apps/matrix/apps/web/src/lib/components/chat/RoomHeader.svelte index d97ff5e83..f25714f9d 100644 --- a/apps/matrix/apps/web/src/lib/components/chat/RoomHeader.svelte +++ b/apps/matrix/apps/web/src/lib/components/chat/RoomHeader.svelte @@ -45,6 +45,23 @@ }); } }); + + // Presence for DMs + let isOnline = $derived(room?.isDirect && room?.presence === 'online'); + + // Format last active time + let presenceText = $derived(() => { + if (!room?.isDirect) return ''; + if (room.presence === 'online') return 'Online'; + if (!room.lastActiveAgo) return 'Offline'; + const minutes = Math.floor(room.lastActiveAgo / 60000); + if (minutes < 1) return 'Gerade aktiv'; + if (minutes < 60) return `Vor ${minutes} Min. aktiv`; + const hours = Math.floor(minutes / 60); + if (hours < 24) return `Vor ${hours} Std. aktiv`; + const days = Math.floor(hours / 24); + return `Vor ${days} Tag${days > 1 ? 'en' : ''} aktiv`; + }); {#if room} @@ -59,15 +76,25 @@ - -
- {#if room.avatar} - {room.name} - {:else} - {room.name.charAt(0).toUpperCase()} + +
+
+ {#if room.avatar} + {room.name} + {:else} + {room.name.charAt(0).toUpperCase()} + {/if} +
+ + {#if room.isDirect} +
{/if}
@@ -94,11 +121,19 @@
{/if} -

+

{#if room.topic} {room.topic} {:else if room.isDirect} - Direktnachricht + + {#if isOnline} + + Online + {:else} + + {presenceText() || 'Offline'} + {/if} + {:else} {room.memberCount} Mitglieder diff --git a/apps/matrix/apps/web/src/lib/matrix/store.svelte.ts b/apps/matrix/apps/web/src/lib/matrix/store.svelte.ts index b88561639..150795d6c 100644 --- a/apps/matrix/apps/web/src/lib/matrix/store.svelte.ts +++ b/apps/matrix/apps/web/src/lib/matrix/store.svelte.ts @@ -1485,6 +1485,39 @@ class MatrixStore { } } + /** + * Toggle screen sharing + */ + async toggleScreenShare(): Promise { + if (!this._matrixCall || !this._activeCall) return false; + + try { + const isSharing = this._activeCall.isScreenSharing; + + if (isSharing) { + // Stop screen sharing - switch back to camera + await this._matrixCall.setScreensharingEnabled(false); + this._activeCall = { ...this._activeCall, isScreenSharing: false }; + } else { + // Start screen sharing + const success = await this._matrixCall.setScreensharingEnabled(true, { + audio: true, // Include system audio if available + }); + if (success) { + this._activeCall = { ...this._activeCall, isScreenSharing: true }; + } else { + console.warn('Screen sharing was denied or failed'); + return false; + } + } + return true; + } catch (err) { + console.error('Error toggling screen share:', err); + this._error = 'Bildschirmfreigabe fehlgeschlagen'; + return false; + } + } + /** * Set up call event handlers */