Add room list avatar option & youtube embed player option
This commit is contained in:
parent
8ea2b0b63b
commit
5c81ba994c
7 changed files with 185 additions and 3 deletions
|
@ -15,6 +15,7 @@ import ExternalSVG from '../../../../public/res/ic/outlined/external.svg';
|
||||||
import PlaySVG from '../../../../public/res/ic/outlined/play.svg';
|
import PlaySVG from '../../../../public/res/ic/outlined/play.svg';
|
||||||
|
|
||||||
import { getBlobSafeMimeType } from '../../../util/mimetypes';
|
import { getBlobSafeMimeType } from '../../../util/mimetypes';
|
||||||
|
import initMatrix from '../../../client/initMatrix';
|
||||||
|
|
||||||
async function getDecryptedBlob(response, type, decryptData) {
|
async function getDecryptedBlob(response, type, decryptData) {
|
||||||
const arrayBuffer = await response.arrayBuffer();
|
const arrayBuffer = await response.arrayBuffer();
|
||||||
|
@ -361,6 +362,83 @@ Video.propTypes = {
|
||||||
blurhash: PropTypes.string,
|
blurhash: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
function YoutubeEmbed({ link }) {
|
||||||
File, Image, Sticker, Audio, Video,
|
const url = new URL(link);
|
||||||
|
|
||||||
|
const [urlPreviewInfo, setUrlPreviewInfo] = useState(null);
|
||||||
|
const [videoStarted, setVideoStarted] = useState(false);
|
||||||
|
|
||||||
|
const mx = initMatrix.matrixClient;
|
||||||
|
|
||||||
|
const handlePlayVideo = () => {
|
||||||
|
setVideoStarted(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let unmounted = false;
|
||||||
|
|
||||||
|
async function getThumbnail() {
|
||||||
|
const info = await mx.getUrlPreview(link, 0);
|
||||||
|
if (unmounted) return;
|
||||||
|
|
||||||
|
setUrlPreviewInfo(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
getThumbnail();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unmounted = true;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let embedURL = `https://www.youtube-nocookie.com/embed/${url.searchParams.get('v')}?autoplay=1`;
|
||||||
|
if (url.searchParams.has('t')) {
|
||||||
|
embedURL += `&start=${url.searchParams.get('t')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="file-container">
|
||||||
|
{urlPreviewInfo !== null && (
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<div className="file-header">
|
||||||
|
<Text className="file-name" variant="b3">{`Youtube - ${urlPreviewInfo['og:title']}`}</Text>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
size="extra-small"
|
||||||
|
tooltip="Open in new tab"
|
||||||
|
src={ExternalSVG}
|
||||||
|
onClick={() => window.open(link)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="video-container"
|
||||||
|
>
|
||||||
|
{!videoStarted && <img src={mx.mxcUrlToHttp(urlPreviewInfo['og:image'])} alt="Youtube thumbnail" />}
|
||||||
|
{!videoStarted && <IconButton onClick={handlePlayVideo} tooltip="Play video" src={PlaySVG} />}
|
||||||
|
|
||||||
|
{videoStarted && (
|
||||||
|
<iframe
|
||||||
|
src={embedURL}
|
||||||
|
title="YouTube video player"
|
||||||
|
frameborder="0"
|
||||||
|
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
||||||
|
allowFullScreen
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
YoutubeEmbed.propTypes = {
|
||||||
|
link: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
File, Image, Sticker, Audio, Video, YoutubeEmbed,
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,6 +29,7 @@ import IconButton from '../../atoms/button/IconButton';
|
||||||
import Time from '../../atoms/time/Time';
|
import Time from '../../atoms/time/Time';
|
||||||
import ContextMenu, { MenuHeader, MenuItem, MenuBorder } from '../../atoms/context-menu/ContextMenu';
|
import ContextMenu, { MenuHeader, MenuItem, MenuBorder } from '../../atoms/context-menu/ContextMenu';
|
||||||
import * as Media from '../media/Media';
|
import * as Media from '../media/Media';
|
||||||
|
import settings from '../../../client/state/settings';
|
||||||
|
|
||||||
import ReplyArrowIC from '../../../../public/res/ic/outlined/reply-arrow.svg';
|
import ReplyArrowIC from '../../../../public/res/ic/outlined/reply-arrow.svg';
|
||||||
import EmojiAddIC from '../../../../public/res/ic/outlined/emoji-add.svg';
|
import EmojiAddIC from '../../../../public/res/ic/outlined/emoji-add.svg';
|
||||||
|
@ -41,6 +42,7 @@ import BinIC from '../../../../public/res/ic/outlined/bin.svg';
|
||||||
import { confirmDialog } from '../confirm-dialog/ConfirmDialog';
|
import { confirmDialog } from '../confirm-dialog/ConfirmDialog';
|
||||||
import { getBlobSafeMimeType } from '../../../util/mimetypes';
|
import { getBlobSafeMimeType } from '../../../util/mimetypes';
|
||||||
import { html, plain } from '../../../util/markdown';
|
import { html, plain } from '../../../util/markdown';
|
||||||
|
import { YoutubeEmbed } from '../media/Media';
|
||||||
|
|
||||||
function PlaceholderMessage() {
|
function PlaceholderMessage() {
|
||||||
return (
|
return (
|
||||||
|
@ -716,6 +718,10 @@ function getEditedBody(editedMEvent) {
|
||||||
return [parsedContent.body, isCustomHTML, newContent.formatted_body ?? null];
|
return [parsedContent.body, isCustomHTML, newContent.formatted_body ?? null];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findYoutubeLinks(body) {
|
||||||
|
return [...new Set(body.match(/https?:\/\/(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)[^ \n]+/g))] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
function Message({
|
function Message({
|
||||||
mEvent, isBodyOnly, roomTimeline,
|
mEvent, isBodyOnly, roomTimeline,
|
||||||
focus, fullTime, isEdit, setEdit, cancelEdit,
|
focus, fullTime, isEdit, setEdit, cancelEdit,
|
||||||
|
@ -801,6 +807,9 @@ function Message({
|
||||||
isEdited={isEdited}
|
isEdited={isEdited}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{settings.showYoutubeEmbedPlayer && findYoutubeLinks(body).map((link) => (
|
||||||
|
<YoutubeEmbed key={link} link={link} />
|
||||||
|
))}
|
||||||
{isEdit && (
|
{isEdit && (
|
||||||
<MessageEdit
|
<MessageEdit
|
||||||
body={(customHTML
|
body={(customHTML
|
||||||
|
|
|
@ -5,10 +5,12 @@ import './RoomSelector.scss';
|
||||||
import { twemojify } from '../../../util/twemojify';
|
import { twemojify } from '../../../util/twemojify';
|
||||||
import colorMXID from '../../../util/colorMXID';
|
import colorMXID from '../../../util/colorMXID';
|
||||||
|
|
||||||
|
import initMatrix from '../../../client/initMatrix';
|
||||||
import Text from '../../atoms/text/Text';
|
import Text from '../../atoms/text/Text';
|
||||||
import Avatar from '../../atoms/avatar/Avatar';
|
import Avatar from '../../atoms/avatar/Avatar';
|
||||||
import NotificationBadge from '../../atoms/badge/NotificationBadge';
|
import NotificationBadge from '../../atoms/badge/NotificationBadge';
|
||||||
import { blurOnBubbling } from '../../atoms/button/script';
|
import { blurOnBubbling } from '../../atoms/button/script';
|
||||||
|
import settings from '../../../client/state/settings';
|
||||||
|
|
||||||
function RoomSelectorWrapper({
|
function RoomSelectorWrapper({
|
||||||
isSelected, isMuted, isUnread, onClick,
|
isSelected, isMuted, isUnread, onClick,
|
||||||
|
@ -54,6 +56,13 @@ function RoomSelector({
|
||||||
isSelected, isMuted, isUnread, notificationCount, isAlert,
|
isSelected, isMuted, isUnread, notificationCount, isAlert,
|
||||||
options, onClick, onContextMenu,
|
options, onClick, onContextMenu,
|
||||||
}) {
|
}) {
|
||||||
|
let avatarSrc;
|
||||||
|
if (settings.showRoomListAvatar) {
|
||||||
|
const mx = initMatrix.matrixClient;
|
||||||
|
const room = mx.getRoom(roomId);
|
||||||
|
avatarSrc = room.getAvatarUrl(mx.baseUrl, 24, 24, 'crop');
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RoomSelectorWrapper
|
<RoomSelectorWrapper
|
||||||
isSelected={isSelected}
|
isSelected={isSelected}
|
||||||
|
@ -61,6 +70,7 @@ function RoomSelector({
|
||||||
isUnread={isUnread}
|
isUnread={isUnread}
|
||||||
content={(
|
content={(
|
||||||
<>
|
<>
|
||||||
|
{!settings.showRoomListAvatar && (
|
||||||
<Avatar
|
<Avatar
|
||||||
text={name}
|
text={name}
|
||||||
bgColor={colorMXID(roomId)}
|
bgColor={colorMXID(roomId)}
|
||||||
|
@ -69,6 +79,15 @@ function RoomSelector({
|
||||||
iconSrc={iconSrc}
|
iconSrc={iconSrc}
|
||||||
size="extra-small"
|
size="extra-small"
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
{settings.showRoomListAvatar && (
|
||||||
|
<Avatar
|
||||||
|
text={name}
|
||||||
|
bgColor={colorMXID(roomId)}
|
||||||
|
imageSrc={avatarSrc}
|
||||||
|
size="extra-small"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Text variant="b1" weight={isUnread ? 'medium' : 'normal'}>
|
<Text variant="b1" weight={isUnread ? 'medium' : 'normal'}>
|
||||||
{twemojify(name)}
|
{twemojify(name)}
|
||||||
{parentName && (
|
{parentName && (
|
||||||
|
|
|
@ -7,7 +7,7 @@ import settings from '../../../client/state/settings';
|
||||||
import navigation from '../../../client/state/navigation';
|
import navigation from '../../../client/state/navigation';
|
||||||
import {
|
import {
|
||||||
toggleSystemTheme, toggleMarkdown, toggleMembershipEvents, toggleNickAvatarEvents,
|
toggleSystemTheme, toggleMarkdown, toggleMembershipEvents, toggleNickAvatarEvents,
|
||||||
toggleNotifications, toggleNotificationSounds,
|
toggleNotifications, toggleNotificationSounds, toggleShowRoomListAvatar, toggleShowYoutubeEmbedPlayer,
|
||||||
} from '../../../client/action/settings';
|
} from '../../../client/action/settings';
|
||||||
import { usePermission } from '../../hooks/usePermission';
|
import { usePermission } from '../../hooks/usePermission';
|
||||||
|
|
||||||
|
@ -80,6 +80,26 @@ function AppearanceSection() {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<SettingTile
|
||||||
|
title="Show room-list avatar"
|
||||||
|
options={(
|
||||||
|
<Toggle
|
||||||
|
isActive={settings.showRoomListAvatar}
|
||||||
|
onToggle={() => { toggleShowRoomListAvatar(); updateState({}); }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
content={<Text variant="b3">Will show room avatars in the room list.</Text>}
|
||||||
|
/>
|
||||||
|
<SettingTile
|
||||||
|
title="Show Youtube embed player"
|
||||||
|
options={(
|
||||||
|
<Toggle
|
||||||
|
isActive={settings.showYoutubeEmbedPlayer}
|
||||||
|
onToggle={() => { toggleShowYoutubeEmbedPlayer(); updateState({}); }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
content={<Text variant="b3">Will show a youtube embed player for youtube links.</Text>}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="settings-appearance__card">
|
<div className="settings-appearance__card">
|
||||||
<MenuHeader>Room messages</MenuHeader>
|
<MenuHeader>Room messages</MenuHeader>
|
||||||
|
|
|
@ -42,3 +42,15 @@ export function toggleNotificationSounds() {
|
||||||
type: cons.actions.settings.TOGGLE_NOTIFICATION_SOUNDS,
|
type: cons.actions.settings.TOGGLE_NOTIFICATION_SOUNDS,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toggleShowRoomListAvatar() {
|
||||||
|
appDispatcher.dispatch({
|
||||||
|
type: cons.actions.settings.TOGGLE_SHOW_ROOM_LIST_AVATAR,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toggleShowYoutubeEmbedPlayer() {
|
||||||
|
appDispatcher.dispatch({
|
||||||
|
type: cons.actions.settings.TOGGLE_SHOW_YOUTUBE_EMBED_PLAYER,
|
||||||
|
})
|
||||||
|
}
|
|
@ -72,6 +72,8 @@ const cons = {
|
||||||
TOGGLE_NICKAVATAR_EVENT: 'TOGGLE_NICKAVATAR_EVENT',
|
TOGGLE_NICKAVATAR_EVENT: 'TOGGLE_NICKAVATAR_EVENT',
|
||||||
TOGGLE_NOTIFICATIONS: 'TOGGLE_NOTIFICATIONS',
|
TOGGLE_NOTIFICATIONS: 'TOGGLE_NOTIFICATIONS',
|
||||||
TOGGLE_NOTIFICATION_SOUNDS: 'TOGGLE_NOTIFICATION_SOUNDS',
|
TOGGLE_NOTIFICATION_SOUNDS: 'TOGGLE_NOTIFICATION_SOUNDS',
|
||||||
|
TOGGLE_SHOW_ROOM_LIST_AVATAR: 'TOGGLE_SHOW_ROOM_LIST_AVATAR',
|
||||||
|
TOGGLE_SHOW_YOUTUBE_EMBED_PLAYER: 'TOGGLE_SHOW_YOUTUBE_EMBED_PLAYER',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
|
@ -144,6 +146,8 @@ const cons = {
|
||||||
NICKAVATAR_EVENTS_TOGGLED: 'NICKAVATAR_EVENTS_TOGGLED',
|
NICKAVATAR_EVENTS_TOGGLED: 'NICKAVATAR_EVENTS_TOGGLED',
|
||||||
NOTIFICATIONS_TOGGLED: 'NOTIFICATIONS_TOGGLED',
|
NOTIFICATIONS_TOGGLED: 'NOTIFICATIONS_TOGGLED',
|
||||||
NOTIFICATION_SOUNDS_TOGGLED: 'NOTIFICATION_SOUNDS_TOGGLED',
|
NOTIFICATION_SOUNDS_TOGGLED: 'NOTIFICATION_SOUNDS_TOGGLED',
|
||||||
|
SHOW_ROOM_LIST_AVATAR_TOGGLED: 'SHOW_ROOM_LIST_AVATAR_TOGGLED',
|
||||||
|
SHOW_YOUTUBE_EMBED_PLAYER_TOGGLED: 'SHOW_YOUTUBE_EMBED_PLAYER_TOGGLED',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,6 +30,8 @@ class Settings extends EventEmitter {
|
||||||
this.hideNickAvatarEvents = this.getHideNickAvatarEvents();
|
this.hideNickAvatarEvents = this.getHideNickAvatarEvents();
|
||||||
this._showNotifications = this.getShowNotifications();
|
this._showNotifications = this.getShowNotifications();
|
||||||
this.isNotificationSounds = this.getIsNotificationSounds();
|
this.isNotificationSounds = this.getIsNotificationSounds();
|
||||||
|
this.showRoomListAvatar = this.getShowRoomListAvatar();
|
||||||
|
this.showYoutubeEmbedPlayer = this.getShowYoutubeEmbedPlayer();
|
||||||
|
|
||||||
this.isTouchScreenDevice = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0);
|
this.isTouchScreenDevice = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0);
|
||||||
}
|
}
|
||||||
|
@ -147,6 +149,38 @@ class Settings extends EventEmitter {
|
||||||
return settings.isNotificationSounds;
|
return settings.isNotificationSounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleShowRoomListAvatar() {
|
||||||
|
this.showRoomListAvatar = !this.showRoomListAvatar;
|
||||||
|
setSettings('showRoomListAvatar', this.showRoomListAvatar);
|
||||||
|
|
||||||
|
this.emit(cons.events.settings.SHOW_ROOM_LIST_AVATAR_TOGGLED, this.showRoomListAvatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
getShowRoomListAvatar() {
|
||||||
|
if (typeof this.showRoomListAvatar === 'boolean') return this.showRoomListAvatar;
|
||||||
|
|
||||||
|
const settings = getSettings();
|
||||||
|
if (settings === null) return false;
|
||||||
|
if (typeof settings.showRoomListAvatar === 'undefined') return false;
|
||||||
|
return settings.showRoomListAvatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleShowYoutubeEmbedPlayer() {
|
||||||
|
this.showYoutubeEmbedPlayer = !this.showYoutubeEmbedPlayer;
|
||||||
|
setSettings('showYoutubeEmbedPlayer', this.showYoutubeEmbedPlayer);
|
||||||
|
|
||||||
|
this.emit(cons.events.settings.SHOW_YOUTUBE_EMBED_PLAYER_TOGGLED, this.showYoutubeEmbedPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
getShowYoutubeEmbedPlayer() {
|
||||||
|
if (typeof this.showYoutubeEmbedPlayer === 'boolean') return this.showYoutubeEmbedPlayer;
|
||||||
|
|
||||||
|
const settings = getSettings();
|
||||||
|
if (settings === null) return false;
|
||||||
|
if (typeof settings.showYoutubeEmbedPlayer === 'undefined') return false;
|
||||||
|
return settings.showYoutubeEmbedPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
setter(action) {
|
setter(action) {
|
||||||
const actions = {
|
const actions = {
|
||||||
[cons.actions.settings.TOGGLE_SYSTEM_THEME]: () => {
|
[cons.actions.settings.TOGGLE_SYSTEM_THEME]: () => {
|
||||||
|
@ -186,6 +220,12 @@ class Settings extends EventEmitter {
|
||||||
setSettings('isNotificationSounds', this.isNotificationSounds);
|
setSettings('isNotificationSounds', this.isNotificationSounds);
|
||||||
this.emit(cons.events.settings.NOTIFICATION_SOUNDS_TOGGLED, this.isNotificationSounds);
|
this.emit(cons.events.settings.NOTIFICATION_SOUNDS_TOGGLED, this.isNotificationSounds);
|
||||||
},
|
},
|
||||||
|
[cons.actions.settings.TOGGLE_SHOW_ROOM_LIST_AVATAR]: () => {
|
||||||
|
this.toggleShowRoomListAvatar();
|
||||||
|
},
|
||||||
|
[cons.actions.settings.TOGGLE_SHOW_YOUTUBE_EMBED_PLAYER]: () => {
|
||||||
|
this.toggleShowYoutubeEmbedPlayer();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
actions[action.type]?.();
|
actions[action.type]?.();
|
||||||
|
|
Loading…
Reference in a new issue