Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use element home screen to create new chats by default #38

Closed
wants to merge 39 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
720ec43
merge write into chat-create-messages
Jun 1, 2023
b160178
add missing code for avatar check
Jun 1, 2023
6a9c233
add first basic function to create new rooms
Jun 1, 2023
9ff29df
use element home screen for chat actions
Jun 1, 2023
7c6c4cd
wrap Link content in span
Jun 6, 2023
11a4584
merge main into chat-create-messages
Aug 15, 2023
a6c7a3a
add colour to textbutton
Aug 15, 2023
88484b7
add ability to switch between room view and create room view on mobil…
Aug 15, 2023
fbc677a
add optional onClick function to bypass dropdown
Aug 15, 2023
6aac5f9
remove debuggin code
Aug 15, 2023
ee2705b
add comment, remove unused code
Aug 15, 2023
421c95a
merge main into chat-create-messages
Oct 11, 2023
d3c41ab
chore: remove unused code
Oct 11, 2023
7872233
merge main into chat-create-messages
Nov 22, 2023
019704a
refactor: remove device detection and use breakpoints for mobile view…
Nov 22, 2023
ffb8e46
add breakpoint integers for convenience
Nov 28, 2023
75629fd
refactor: improve logic for switiching between mobile and desktop views
Nov 28, 2023
fa85e91
refactor: make sure loading spinner is displayed before iframe is loa…
aofn Nov 28, 2023
88955e2
merge main into chat-create-messages
aofn Nov 28, 2023
1dc43a5
fix: make service submenu work again if not options are given and onC…
aofn Nov 28, 2023
78f4297
chore: remove logs and unsued code
aofn Nov 28, 2023
c15679f
refactor: improve logic around loading spinner and fix for larger screns
aofn Nov 28, 2023
dce50fb
merge main into chat-create-message
aofn Nov 29, 2023
55f5d1d
refactor: move deleting chat into chat header, swap icon
aofn Nov 29, 2023
43e2574
Merge remote-tracking branch 'origin/main' into chat-create-messages
aofn Nov 29, 2023
f6901b9
fix: css injections
aofn Nov 29, 2023
0443b68
fix: dont render avatar at the moment since its braking the layout atm
aofn Nov 29, 2023
b600cb5
refactor: add optional notification variable to ServiceLink.js
aofn Nov 30, 2023
d7a6fe7
refactor: use ServiceLink component for chat rooms
aofn Nov 30, 2023
27238c9
chore: fix eslint/stylelint formatting issues
andirueckel Nov 30, 2023
327c7f3
chore: remove trailing whitespaces
andirueckel Nov 30, 2023
10e8a7a
chore: fix formatting and comment temporarily unused Avatar
andirueckel Nov 30, 2023
a623c3c
style: improve NotificationBadge styling; needs re-positioning
andirueckel Nov 30, 2023
c01820d
style: refactor ServiceLink for use in `/chat` route
andirueckel Nov 30, 2023
670af5a
refactor: fix table without using grid and use actual notification co…
aofn Nov 30, 2023
6197c18
refactor: make style lint happy
aofn Nov 30, 2023
97e2558
refactor: create component for summary
aofn Nov 30, 2023
58a39a3
chore: improve comment
aofn Nov 30, 2023
7f4e297
Merge branch 'main' into chat-create-messages
fnwbr Dec 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/Matrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,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));
Expand Down
16 changes: 12 additions & 4 deletions lib/auth/MatrixAuthProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,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',
Expand All @@ -130,12 +130,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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between template and application?

At the same time, like I said above: I think we don't actually make use of this new "application" parameter anywhere. So let's remove it again?

version: '0.5',
};
await this.matrixClient.sendStateEvent(room.room_id, 'dev.medienhaus.meta', medienhausMetaEvent);

Expand Down
134 changes: 99 additions & 35 deletions pages/chat/[[...roomId]].js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect, useRef } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
Fixed Show fixed Hide fixed
import styled from 'styled-components';
import _ from 'lodash';
import _, { debounce } from 'lodash';
Fixed Show fixed Hide fixed
import { useTranslation } from 'react-i18next';
import getConfig from 'next/config';
import { useRouter } from 'next/router';
Expand All @@ -9,6 +9,12 @@
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';
import { ServiceTable } from '../../components/UI/ServiceTable';
import Bin from '../../assets/icons/bin.svg';
import TextButton from '../../components/UI/TextButton';
import { breakpoints } from '../../components/_breakpoints';

const sortRooms = function(room) {
Expand Down Expand Up @@ -38,39 +44,53 @@
background: var(--color-foreground);
`;

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 }) {
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 (
<Link href={`/chat/${room.roomId}`} passHref>
<SidebarListEntryWrapper>
{ room.avatar ? (
<ServiceTable.Row>
<ServiceTable.Cell selected={false}>
<Link href={`/chat/${room.roomId}`} passHref>
<span>
{ room.avatar && (
// Render the avatar if we have one
<Avatar src={room.avatar} alt={room.name} />
) }
{ /* { room.avatar ? (
// Render the avatar if we have one
<Avatar src={room.avatar} alt={room.name} />
) : (
<Avatar src={room.avatar} alt={room.name} />
) : (
// Render an empty GIF if we don't have an avatar
<Avatar src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" />
) }
<RoomName>{ room.name }</RoomName>
{ room.notificationCount > 0 && (
<UnreadNotificationBadge>{ room.notificationCount }</UnreadNotificationBadge>
) }
</SidebarListEntryWrapper>
</Link>
<Avatar src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" />
) } */ }
{ room.name }
{ room.notificationCount > 0 && (
<UnreadNotificationBadge>{ room.notificationCount }</UnreadNotificationBadge>
) }
</span>
</Link>
</ServiceTable.Cell>
<ServiceTable.Cell>
<TextButton title={t('Leave room and remove from my library')} onClick={() => handleLeave(room.roomId)}>
{ isLeavingRoom ? <LoadingSpinnerInline /> : <Bin fill="var(--color-foreground)" /> }
</TextButton>
</ServiceTable.Cell>
</ServiceTable.Row>
);
};

Expand Down Expand Up @@ -100,6 +120,13 @@
/* Hide the search bar buttons to only allow searching inside current room */
.mx_SearchBar_buttons { display: none !important }

/* @TODO: This can be improved... and should probably not target mobile viewports. It's to make the */
/* header look like it's on line with our header elements from first & second sidebar. */
.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 }
.mx_RoomHeader {
position: absolute; right: 0; left: 0; z-index: 10;
background: rgba(255, 255, 255, 90%); backdrop-filter: blur(4px);
Expand Down Expand Up @@ -149,10 +176,46 @@
.sortBy(sortRooms)
.value();

const ActionNewRoom = ({ 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);
Fixed Show fixed Hide fixed
await matrix.createRoom(roomName, false, topic, 'invite', 'item', 'chat', getConfig().publicRuntimeConfig.name, 'private', 'shared', encrypted)
.catch((error => console.debug(error)));
// router.push(`/chat/${roomId}`);

callbackDone && callbackDone();
setIsLoading(false);
};

return (
<Form onSubmit={(e) => { e.preventDefault(); createNewRoom(); }}>
<input type="text" placeholder={t('room name')} value={roomName} onChange={(e) => setRoomName(e.target.value)} />
<input type="text" placeholder={t('topic (optional)')} value={topic} onChange={(e) => setTopic(e.target.value)} />
<Checkbox><label htmlFor="encrypted">Encrypted</label><input type="checkbox" name="encrypted" checked={encrypted} onChange={() => setEncrypted(prevState => !prevState)} /></Checkbox>
<button type="submit" disabled={!roomName}>{ isLoading ?<LoadingSpinnerInline inverted /> : t('Create room') }</button>
</Form>
);
};

const submenuItems = _.filter([
{ value: 'newRoom', actionComponentToRender: ActionNewRoom, label: t('New room') },

]);

return (
<>
<IframeLayout.Sidebar>
<h2>/chat</h2>
<ServiceSubmenu
title={<h2>/chat</h2>}
subheadline={t('What would you like to do?')}
items={submenuItems} />
{ matrix.invites.size > 0 && (
<>
<details open>
Expand All @@ -169,15 +232,16 @@
<br />
<details open>
<summary><h3 style={{ display: 'inline-block', marginBottom: '1rem' }}>{ t('Rooms') }</h3></summary>
{ otherRooms && otherRooms.map((room) => <SidebarListEntry key={room.roomId} room={room} />) }
{ otherRooms && otherRooms.map((room) => {
return <ServiceTable><SidebarListEntry key={room.roomId} room={room} /></ServiceTable>;
}) }
</details>
<br />
</IframeLayout.Sidebar>
{ roomId && (
<IframeLayout.IframeWrapper>
<iframe src={`${getConfig().publicRuntimeConfig.chat.pathToElement}/#/room/${roomId}`} ref={iframe} />
</IframeLayout.IframeWrapper>
) }

<IframeLayout.IframeWrapper>
<iframe src={`${getConfig().publicRuntimeConfig.chat.pathToElement}/#/${roomId ? 'room/' + roomId : 'home' }`} ref={iframe} />
</IframeLayout.IframeWrapper>
</>
);
}
Expand Down
Loading