Show sharer preview for matrix.to links
This commit is contained in:
parent
85fab36308
commit
74b790927e
5 changed files with 128 additions and 62 deletions
|
@ -19,4 +19,8 @@ limitations under the License.
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,11 @@ import { getEvent, client } from 'matrix-cypher';
|
||||||
import { RoomPreviewWithTopic } from './RoomPreview';
|
import { RoomPreviewWithTopic } from './RoomPreview';
|
||||||
import InviteTile from './InviteTile';
|
import InviteTile from './InviteTile';
|
||||||
import { SafeLink, LinkKind } from '../parser/types';
|
import { SafeLink, LinkKind } from '../parser/types';
|
||||||
import UserPreview from './UserPreview';
|
import UserPreview, { WrappedInviterPreview } from './UserPreview';
|
||||||
import EventPreview from './EventPreview';
|
import EventPreview from './EventPreview';
|
||||||
import HomeserverOptions from './HomeserverOptions';
|
import HomeserverOptions from './HomeserverOptions';
|
||||||
import DefaultPreview from './DefaultPreview';
|
import DefaultPreview from './DefaultPreview';
|
||||||
|
import Toggle from './Toggle';
|
||||||
import { clientMap } from '../clients';
|
import { clientMap } from '../clients';
|
||||||
import {
|
import {
|
||||||
getRoomFromId,
|
getRoomFromId,
|
||||||
|
@ -32,12 +33,7 @@ import {
|
||||||
getUser,
|
getUser,
|
||||||
} from '../utils/cypher-wrapper';
|
} from '../utils/cypher-wrapper';
|
||||||
import { ClientContext } from '../contexts/ClientContext';
|
import { ClientContext } from '../contexts/ClientContext';
|
||||||
import HSContext, {
|
import useHSs from '../utils/getHS';
|
||||||
TempHSContext,
|
|
||||||
HSOptions,
|
|
||||||
State as HSState,
|
|
||||||
} from '../contexts/HSContext';
|
|
||||||
import Toggle from './Toggle';
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
link: SafeLink;
|
link: SafeLink;
|
||||||
|
@ -118,32 +114,14 @@ const Preview: React.FC<PreviewProps> = ({ link, client }: PreviewProps) => {
|
||||||
return content;
|
return content;
|
||||||
};
|
};
|
||||||
|
|
||||||
function selectedClient(link: SafeLink, hsOptions: HSState): string[] {
|
|
||||||
switch (hsOptions.option) {
|
|
||||||
case HSOptions.Unset:
|
|
||||||
return [];
|
|
||||||
case HSOptions.None:
|
|
||||||
return [];
|
|
||||||
case HSOptions.TrustedHSOnly:
|
|
||||||
return [hsOptions.hs];
|
|
||||||
case HSOptions.Any:
|
|
||||||
return [
|
|
||||||
'https://' + link.identifier.split(':')[1],
|
|
||||||
...link.arguments.vias,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const LinkPreview: React.FC<IProps> = ({ link }: IProps) => {
|
const LinkPreview: React.FC<IProps> = ({ link }: IProps) => {
|
||||||
let content: JSX.Element;
|
let content: JSX.Element;
|
||||||
const [showHSOptions, setShowHSOPtions] = useState(false);
|
const [showHSOptions, setShowHSOPtions] = useState(false);
|
||||||
const [hsOptions] = useContext(HSContext);
|
|
||||||
const [tempHSState] = useContext(TempHSContext);
|
|
||||||
|
|
||||||
if (
|
const hses = useHSs(link);
|
||||||
hsOptions.option === HSOptions.Unset &&
|
console.log(hses);
|
||||||
tempHSState.option === HSOptions.Unset
|
|
||||||
) {
|
if (!hses) {
|
||||||
content = (
|
content = (
|
||||||
<>
|
<>
|
||||||
<DefaultPreview link={link} />
|
<DefaultPreview link={link} />
|
||||||
|
@ -164,11 +142,7 @@ const LinkPreview: React.FC<IProps> = ({ link }: IProps) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const clients =
|
content = <Preview link={link} client={hses[0]} />;
|
||||||
tempHSState.option !== HSOptions.Unset
|
|
||||||
? selectedClient(link, tempHSState)
|
|
||||||
: selectedClient(link, hsOptions);
|
|
||||||
content = <Preview link={link} client={clients[0]} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const [{ clientId }] = useContext(ClientContext);
|
const [{ clientId }] = useContext(ClientContext);
|
||||||
|
@ -182,8 +156,20 @@ const LinkPreview: React.FC<IProps> = ({ link }: IProps) => {
|
||||||
|
|
||||||
const client = displayClientId ? clientMap[displayClientId] : null;
|
const client = displayClientId ? clientMap[displayClientId] : null;
|
||||||
|
|
||||||
|
const sharer = link.arguments.sharer ? (
|
||||||
|
<WrappedInviterPreview
|
||||||
|
link={{
|
||||||
|
kind: LinkKind.UserId,
|
||||||
|
identifier: link.arguments.sharer,
|
||||||
|
arguments: { vias: [] },
|
||||||
|
originalLink: '',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InviteTile client={client} link={link}>
|
<InviteTile client={client} link={link}>
|
||||||
|
{sharer}
|
||||||
{content}
|
{content}
|
||||||
</InviteTile>
|
</InviteTile>
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,10 +14,13 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { User } from 'matrix-cypher';
|
import { client, User, getUserDetails } from 'matrix-cypher';
|
||||||
|
import icon from '../imgs/chat-icon.svg';
|
||||||
|
|
||||||
import { UserAvatar } from './Avatar';
|
import Avatar, { UserAvatar } from './Avatar';
|
||||||
|
import useHSs from '../utils/getHS';
|
||||||
|
import { UserId } from '../parser/types';
|
||||||
|
|
||||||
import './UserPreview.scss';
|
import './UserPreview.scss';
|
||||||
|
|
||||||
|
@ -37,14 +40,49 @@ const UserPreview: React.FC<IProps> = ({ user, userId }: IProps) => (
|
||||||
|
|
||||||
export default UserPreview;
|
export default UserPreview;
|
||||||
|
|
||||||
export const InviterPreview: React.FC<IProps> = ({ user, userId }: IProps) => (
|
interface InviterPreviewProps {
|
||||||
<div className="miniUserPreview">
|
user?: User;
|
||||||
<div>
|
userId: string;
|
||||||
<h1>
|
}
|
||||||
Invited by <b>{user.displayname}</b>
|
|
||||||
</h1>
|
export const InviterPreview: React.FC<InviterPreviewProps> = ({
|
||||||
<p>{userId}</p>
|
user,
|
||||||
</div>
|
userId,
|
||||||
|
}: InviterPreviewProps) => {
|
||||||
|
const avatar = user ? (
|
||||||
<UserAvatar user={user} userId={userId} />
|
<UserAvatar user={user} userId={userId} />
|
||||||
</div>
|
) : (
|
||||||
);
|
<Avatar label={`Placeholder icon for ${userId}`} avatarUrl={icon} />
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div className="miniUserPreview">
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
Invited by <b>{user ? user.displayname : userId}</b>
|
||||||
|
</h1>
|
||||||
|
{user ? <p>{userId}</p> : null}
|
||||||
|
</div>
|
||||||
|
{avatar}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface WrappedInviterProps {
|
||||||
|
link: UserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WrappedInviterPreview: React.FC<WrappedInviterProps> = ({
|
||||||
|
link,
|
||||||
|
}: WrappedInviterProps) => {
|
||||||
|
const [user, setUser] = useState<User | undefined>(undefined);
|
||||||
|
const hss = useHSs(link);
|
||||||
|
useEffect(() => {
|
||||||
|
if (hss) {
|
||||||
|
client(hss[0])
|
||||||
|
.then((c) => getUserDetails(c, link.identifier))
|
||||||
|
.then(setUser)
|
||||||
|
.catch((x) => console.log("couldn't fetch user preview", x));
|
||||||
|
}
|
||||||
|
}, [hss, link]);
|
||||||
|
return <InviterPreview user={user} userId={link.identifier} />;
|
||||||
|
};
|
||||||
|
|
|
@ -29,17 +29,12 @@ export enum HSOptions {
|
||||||
TrustedHSOnly = 'TRUSTED_CLIENT_ONLY',
|
TrustedHSOnly = 'TRUSTED_CLIENT_ONLY',
|
||||||
// Matrix.to may contact any homeserver it requires
|
// Matrix.to may contact any homeserver it requires
|
||||||
Any = 'ANY',
|
Any = 'ANY',
|
||||||
// Matrix.to may not contact any homeservers
|
|
||||||
None = 'NONE',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const STATE_SCHEMA = union([
|
const STATE_SCHEMA = union([
|
||||||
object({
|
object({
|
||||||
option: literal(HSOptions.Unset),
|
option: literal(HSOptions.Unset),
|
||||||
}),
|
}),
|
||||||
object({
|
|
||||||
option: literal(HSOptions.None),
|
|
||||||
}),
|
|
||||||
object({
|
object({
|
||||||
option: literal(HSOptions.Any),
|
option: literal(HSOptions.Any),
|
||||||
}),
|
}),
|
||||||
|
@ -55,7 +50,6 @@ export type State = TypeOf<typeof STATE_SCHEMA>;
|
||||||
export enum ActionType {
|
export enum ActionType {
|
||||||
SetHS = 'SET_HS',
|
SetHS = 'SET_HS',
|
||||||
SetAny = 'SET_ANY',
|
SetAny = 'SET_ANY',
|
||||||
SetNone = 'SET_NONE',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SetHS {
|
export interface SetHS {
|
||||||
|
@ -67,11 +61,7 @@ export interface SetAny {
|
||||||
action: ActionType.SetAny;
|
action: ActionType.SetAny;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SetNone {
|
export type Action = SetHS | SetAny;
|
||||||
action: ActionType.SetNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Action = SetHS | SetAny | SetNone;
|
|
||||||
|
|
||||||
export const INITIAL_STATE: State = {
|
export const INITIAL_STATE: State = {
|
||||||
option: HSOptions.Unset,
|
option: HSOptions.Unset,
|
||||||
|
@ -81,10 +71,6 @@ export const unpersistedReducer = (state: State, action: Action): State => {
|
||||||
console.log('reducing');
|
console.log('reducing');
|
||||||
console.log(action);
|
console.log(action);
|
||||||
switch (action.action) {
|
switch (action.action) {
|
||||||
case ActionType.SetNone:
|
|
||||||
return {
|
|
||||||
option: HSOptions.None,
|
|
||||||
};
|
|
||||||
case ActionType.SetAny:
|
case ActionType.SetAny:
|
||||||
return {
|
return {
|
||||||
option: HSOptions.Any,
|
option: HSOptions.Any,
|
||||||
|
|
52
src/utils/getHS.ts
Normal file
52
src/utils/getHS.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import HSContext, {
|
||||||
|
TempHSContext,
|
||||||
|
State,
|
||||||
|
HSOptions,
|
||||||
|
} from '../contexts/HSContext';
|
||||||
|
import { SafeLink } from '../parser/types';
|
||||||
|
|
||||||
|
function selectedClient(link: SafeLink, hsOptions: State): string[] {
|
||||||
|
switch (hsOptions.option) {
|
||||||
|
case HSOptions.Unset:
|
||||||
|
return [];
|
||||||
|
case HSOptions.TrustedHSOnly:
|
||||||
|
return [hsOptions.hs];
|
||||||
|
case HSOptions.Any:
|
||||||
|
return [
|
||||||
|
...link.identifier
|
||||||
|
.split('/')
|
||||||
|
.map((i) => 'https://' + i.split(':')[1]),
|
||||||
|
...link.arguments.vias,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useHSs(link: SafeLink): string[] {
|
||||||
|
const [HSState] = useContext(HSContext);
|
||||||
|
const [TempHSState] = useContext(TempHSContext);
|
||||||
|
|
||||||
|
if (HSState.option !== HSOptions.Unset) {
|
||||||
|
return selectedClient(link, HSState);
|
||||||
|
} else if (TempHSState.option !== HSOptions.Unset) {
|
||||||
|
return selectedClient(link, TempHSState);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue