From b160178beb8268c49113ba338351657c6ef6bf96 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 1 Jun 2023 12:41:02 +0200 Subject: [PATCH 01/31] add missing code for avatar check --- lib/Matrix.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/Matrix.js b/lib/Matrix.js index 7a87c023..72ed1f2b 100644 --- a/lib/Matrix.js +++ b/lib/Matrix.js @@ -30,6 +30,12 @@ function useMatrixProvider(activeMatrixAuthenticationProviders) { children.push(child.event.state_key); } } + let avatar; + if (room.getAvatarUrl(matrixClient.getHomeserverUrl(), 100, 100, 'crop')) { + avatar = room.getAvatarUrl(matrixClient.getHomeserverUrl(), 100, 100, 'crop'); + } else if (room.getAvatarFallbackMember() && room.getAvatarFallbackMember().getAvatarUrl(matrixClient.getHomeserverUrl(), 100, 100, 'crop')) { + avatar = room.getAvatarFallbackMember().getAvatarUrl(matrixClient.getHomeserverUrl(), 100, 100, 'crop'); + } return { roomId: roomId, From 6a9c233b465d1e4620ffb8a37eadf80c0bfbb2c3 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 1 Jun 2023 14:26:29 +0200 Subject: [PATCH 02/31] add first basic function to create new rooms --- lib/Matrix.js | 4 +-- lib/auth/MatrixAuthProvider.js | 16 +++++++++--- pages/chat/[[...roomId]].js | 48 +++++++++++++++++++++++++++++++--- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/lib/Matrix.js b/lib/Matrix.js index 72ed1f2b..516a3439 100644 --- a/lib/Matrix.js +++ b/lib/Matrix.js @@ -248,8 +248,8 @@ function useMatrixProvider(activeMatrixAuthenticationProviders) { leaveMatrixRoom.event_id && deleteElement(roomId); }; - const createRoom = async (name, isSpace, topic, joinRule, type, template, application) => { - const room = await authenticationProvider.createRoom(name, isSpace, topic, joinRule, type, template, application); + const createRoom = async (name, isSpace, topic, joinRule, type, template, application, visibility, historyVisible, encrypted) => { + const room = await authenticationProvider.createRoom(name, isSpace, topic, joinRule, type, template, application, visibility, historyVisible, encrypted); if (isSpace) { if (!spaces.has(room.room_id)) { setSpaces(setRoom(room.room_id)); diff --git a/lib/auth/MatrixAuthProvider.js b/lib/auth/MatrixAuthProvider.js index 802807e7..c514657e 100644 --- a/lib/auth/MatrixAuthProvider.js +++ b/lib/auth/MatrixAuthProvider.js @@ -88,19 +88,19 @@ class MatrixAuthProvider { return this.matrixClient.http.authedRequest('GET', `/rooms/${roomId}/messages`, { limit: limit, dir: 'b', filter: JSON.stringify({ types: ['m.room.message'] }) }, undefined, { abortSignal }); } - async createRoom(name, isSpace, topic, joinRule, type, template) { + async createRoom(name, isSpace, topic, joinRule, type, template, application, visibility, historyVisible, encrypted) { const opts = { name: name, room_version: '9', preset: 'private_chat', topic: topic, - visibility: 'private', // by default we want rooms and spaces to be private, this can later be changed either in /content or /moderate + visibility: visibility || 'private', // by default we want rooms and spaces to be private, this can later be changed either in /content or /moderate creation_content: { type: isSpace ? 'm.space' : 'm.room', }, initial_state: [{ type: 'm.room.history_visibility', - content: { history_visibility: 'world_readable' }, // history has to be world_readable so content of the rooms is visible for everyone who joins the room at a later point in time + content: { history_visibility: historyVisible || 'world_readable' }, // history has to be world_readable so content of the rooms is visible for everyone who joins the room at a later point in time }, { type: 'm.room.join_rules', @@ -124,12 +124,20 @@ class MatrixAuthProvider { users_default: 0, }, }; + encrypted && opts.initial_state.push({ + type: 'm.room.encryption', + state_key: '', + content: { + algorithm: 'm.megolm.v1.aes-sha2', + }, + }); const room = await this.matrixClient.createRoom(opts); const medienhausMetaEvent = { type: type, template: template, - version: '0.4', + application: application, + version: '0.5', }; await this.matrixClient.sendStateEvent(room.room_id, 'dev.medienhaus.meta', medienhausMetaEvent); diff --git a/pages/chat/[[...roomId]].js b/pages/chat/[[...roomId]].js index d6aa64bd..95853122 100644 --- a/pages/chat/[[...roomId]].js +++ b/pages/chat/[[...roomId]].js @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; import _ from 'lodash'; import { useTranslation } from 'react-i18next'; @@ -9,6 +9,9 @@ import Link from 'next/link'; import { useAuth } from '../../lib/Auth'; import { useMatrix } from '../../lib/Matrix'; import IframeLayout from '../../components/layouts/iframe'; +import { ServiceSubmenu } from '../../components/UI/ServiceSubmenu'; +import Form from '../../components/UI/Form'; +import LoadingSpinnerInline from '../../components/UI/LoadingSpinnerInline'; const sortRooms = function(room) { return [ @@ -219,14 +222,53 @@ export default function RoomId() { // ... are direct messages, .reject(room => matrix.directMessages.has(room.roomId)) // ... are medienhaus/ CMS related rooms (so if they have a dev.medienhaus.meta event which is NOT "type: chat") - .reject(room => room.events.get('dev.medienhaus.meta') && room.events.get('dev.medienhaus.meta').values().next().value.getContent()?.type !== 'chat') + .reject(room => { + if (!room.events) return; + + return room.events.get('dev.medienhaus.meta') && room.events.get('dev.medienhaus.meta').values().next().value.getContent()?.template !== 'chat'; + }) + .sortBy(sortRooms) .value(); + const ActionNewDirectMessage = ({ callbackDone }) => { + const [roomName, setRoomName] = useState(''); + const [topic, setTopic] = useState(''); + const [encrypted, setEncrypted] = useState(false); + const [isLoading, setIsLoading] = useState(false); + + const createNewRoom = async () => { + setIsLoading(true); + // eslint-disable-next-line no-undef + if (process.env.NODE_ENV === 'development') console.log('creating room for ' + roomName); + const roomId = await matrix.createRoom(roomName, false, topic, 'invite', 'item', 'chat', getConfig().publicRuntimeConfig.name, 'private', 'shared', false) + .catch((error => console.debug(error))); + // router.push(`/chat/${roomId}`); + + callbackDone && callbackDone(); + setIsLoading(false); + }; + + return ( +
{ e.preventDefault(); createNewRoom(); }}> + setRoomName(e.target.value)} /> + setTopic(e.target.value)} /> + setEncrypted(prevState => !prevState)} /> + +
+ ); + }; + const submenuItems = _.filter([ + { value: 'newRoom', actionComponentToRender: ActionNewDirectMessage, label: t('New room') }, + ]); + return ( <> -

/chat

+ /chat} + subheadline={t('What would you like to do?')} + items={submenuItems} /> { matrix.invites.size > 0 && ( <>
From 9ff29dfc784dc2737e99800466873d38eb38269d Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 1 Jun 2023 17:21:33 +0200 Subject: [PATCH 03/31] use element home screen for chat actions --- pages/chat/[[...roomId]].js | 95 ++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 38 deletions(-) diff --git a/pages/chat/[[...roomId]].js b/pages/chat/[[...roomId]].js index 95853122..ff516a6f 100644 --- a/pages/chat/[[...roomId]].js +++ b/pages/chat/[[...roomId]].js @@ -1,6 +1,6 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; -import _ from 'lodash'; +import _, { debounce } from 'lodash'; import { useTranslation } from 'react-i18next'; import getConfig from 'next/config'; import { useRouter } from 'next/router'; @@ -12,6 +12,9 @@ import IframeLayout from '../../components/layouts/iframe'; import { ServiceSubmenu } from '../../components/UI/ServiceSubmenu'; import Form from '../../components/UI/Form'; import LoadingSpinnerInline from '../../components/UI/LoadingSpinnerInline'; +import { ServiceTable } from '../../components/UI/ServiceTable'; +import Bin from '../../assets/icons/bin.svg'; +import TextButton from '../../components/UI/TextButton'; const sortRooms = function(room) { return [ @@ -40,39 +43,50 @@ const Avatar = styled.img` background: black; `; -const SidebarListEntryWrapper = styled.a` +const Checkbox = styled.div` display: flex; - flex-direction: row; - align-items: center; - margin-bottom: 0.3rem; -`; - -const RoomName = styled.span` - flex: 1 0; - height: 2rem; - overflow: hidden; - line-height: 2rem; - text-overflow: ellipsis; - white-space: nowrap; + justify-content: space-between; `; const SidebarListEntry = function({ room, onClick }) { + const [isLeavingRoom, setIsLeavingRoom] = useState(false); + const { t } = useTranslation(); + const auth = useAuth(); + const matrix = useMatrix(auth.getAuthenticationProvider('matrix')); + + const handleLeave = async (roomId) => { + setIsLeavingRoom(true); + await matrix.leaveRoom(roomId) + .catch(error => console.debug(error)); + setIsLeavingRoom(false); + }; + return ( - - - { room.avatar ? ( + + + + { room.avatar && ( + // Render the avatar if we have one + + ) } + { /* { room.avatar ? ( // Render the avatar if we have one - - ) : ( + + ) : ( // Render an empty GIF if we don't have an avatar - - ) } - { room.name } - { room.notificationCount > 0 && ( - { room.notificationCount } - ) } - - + + ) } */ } + { room.name } + { room.notificationCount > 0 && ( + { room.notificationCount } + ) } + + + handleLeave(room.roomId)}> + { isLeavingRoom ? : } + + + ); }; @@ -203,6 +217,8 @@ export default function RoomId() { .mx_RoomHeader_wrapper { height: unset; padding: 0; border-bottom: none } .mx_RoomHeader { flex: unset; -webkit-box-flex: unset; padding: 2.85rem 0 } .mx_RoomHeader_name { font-weight: bold } + .mx_HomePage_default_buttons { display: initial !important } + .mx_HomePage_default_wrapper > div:first-child { display: none } `); styleTag.appendChild(styleContent); iframe.current.contentDocument.getElementsByTagName('html')[0].appendChild(styleTag); @@ -231,7 +247,7 @@ export default function RoomId() { .sortBy(sortRooms) .value(); - const ActionNewDirectMessage = ({ callbackDone }) => { + const ActionNewRoom = ({ callbackDone }) => { const [roomName, setRoomName] = useState(''); const [topic, setTopic] = useState(''); const [encrypted, setEncrypted] = useState(false); @@ -241,7 +257,7 @@ export default function RoomId() { setIsLoading(true); // eslint-disable-next-line no-undef if (process.env.NODE_ENV === 'development') console.log('creating room for ' + roomName); - const roomId = await matrix.createRoom(roomName, false, topic, 'invite', 'item', 'chat', getConfig().publicRuntimeConfig.name, 'private', 'shared', false) + await matrix.createRoom(roomName, false, topic, 'invite', 'item', 'chat', getConfig().publicRuntimeConfig.name, 'private', 'shared', encrypted) .catch((error => console.debug(error))); // router.push(`/chat/${roomId}`); @@ -253,13 +269,15 @@ export default function RoomId() {
{ e.preventDefault(); createNewRoom(); }}> setRoomName(e.target.value)} /> setTopic(e.target.value)} /> - setEncrypted(prevState => !prevState)} /> + setEncrypted(prevState => !prevState)} />
); }; + const submenuItems = _.filter([ - { value: 'newRoom', actionComponentToRender: ActionNewDirectMessage, label: t('New room') }, + { value: 'newRoom', actionComponentToRender: ActionNewRoom, label: t('New room') }, + ]); return ( @@ -285,15 +303,16 @@ export default function RoomId() {

{ t('Rooms') }

- { otherRooms && otherRooms.map((room) => ) } + { otherRooms && otherRooms.map((room) => { + return ; + }) }

- { roomId && ( - -