Merge branch 'develop' into joriks/appearance-advanced
This commit is contained in:
commit
2294d23b32
75 changed files with 2203 additions and 710 deletions
|
@ -118,7 +118,7 @@ class PassphraseField extends PureComponent<IProps, IState> {
|
|||
value={this.props.value}
|
||||
onChange={this.props.onChange}
|
||||
onValidate={this.onValidate}
|
||||
/>
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
|
|||
|
||||
_onResetRecoveryClick = () => {
|
||||
this.props.onFinished(false);
|
||||
accessSecretStorage(() => {}, {forceReset: true});
|
||||
accessSecretStorage(() => {}, /* forceReset = */ true);
|
||||
}
|
||||
|
||||
_onRecoveryKeyChange = (e) => {
|
||||
|
|
|
@ -32,9 +32,6 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
|
|||
keyInfo: PropTypes.object.isRequired,
|
||||
// Function from one of { passphrase, recoveryKey } -> boolean
|
||||
checkPrivateKey: PropTypes.func.isRequired,
|
||||
// If true, only prompt for a passphrase and do not offer to restore with
|
||||
// a recovery key or reset keys.
|
||||
passphraseOnly: PropTypes.bool,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -61,7 +58,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
|
|||
_onResetRecoveryClick = () => {
|
||||
// Re-enter the access flow, but resetting storage this time around.
|
||||
this.props.onFinished(false);
|
||||
accessSecretStorage(() => {}, {forceReset: true});
|
||||
accessSecretStorage(() => {}, /* forceReset = */ true);
|
||||
}
|
||||
|
||||
_onRecoveryKeyChange = (e) => {
|
||||
|
@ -167,7 +164,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
|
|||
primaryDisabled={this.state.passPhrase.length === 0}
|
||||
/>
|
||||
</form>
|
||||
{this.props.passphraseOnly ? null : _t(
|
||||
{_t(
|
||||
"If you've forgotten your recovery passphrase you can "+
|
||||
"<button1>use your recovery key</button1> or " +
|
||||
"<button2>set up new recovery options</button2>."
|
||||
|
@ -237,7 +234,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
|
|||
primaryDisabled={!this.state.recoveryKeyValid}
|
||||
/>
|
||||
</form>
|
||||
{this.props.passphraseOnly ? null : _t(
|
||||
{_t(
|
||||
"If you've forgotten your recovery key you can "+
|
||||
"<button>set up new recovery options</button>."
|
||||
, {}, {
|
||||
|
|
|
@ -19,7 +19,7 @@ import React from 'react';
|
|||
import {Key} from '../../../Keyboard';
|
||||
import classnames from 'classnames';
|
||||
|
||||
export type ButtonEvent = React.MouseEvent<Element> | React.KeyboardEvent<Element>
|
||||
export type ButtonEvent = React.MouseEvent<Element> | React.KeyboardEvent<Element>;
|
||||
|
||||
/**
|
||||
* children: React's magic prop. Represents all children given to the element.
|
||||
|
@ -40,7 +40,7 @@ interface IProps extends React.InputHTMLAttributes<Element> {
|
|||
disabled?: boolean;
|
||||
className?: string;
|
||||
onClick?(e?: ButtonEvent): void;
|
||||
};
|
||||
}
|
||||
|
||||
interface IAccessibleButtonProps extends React.InputHTMLAttributes<Element> {
|
||||
ref?: React.Ref<Element>;
|
||||
|
|
|
@ -17,20 +17,20 @@ limitations under the License.
|
|||
import React from 'react';
|
||||
|
||||
interface IProps {
|
||||
className: string,
|
||||
dragFunc: (currentLocation: ILocationState, event: MouseEvent) => ILocationState,
|
||||
onMouseUp: (event: MouseEvent) => void,
|
||||
className: string;
|
||||
dragFunc: (currentLocation: ILocationState, event: MouseEvent) => ILocationState;
|
||||
onMouseUp: (event: MouseEvent) => void;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
onMouseMove: (event: MouseEvent) => void,
|
||||
onMouseUp: (event: MouseEvent) => void,
|
||||
location: ILocationState,
|
||||
onMouseMove: (event: MouseEvent) => void;
|
||||
onMouseUp: (event: MouseEvent) => void;
|
||||
location: ILocationState;
|
||||
}
|
||||
|
||||
export interface ILocationState {
|
||||
currentX: number,
|
||||
currentY: number,
|
||||
currentX: number;
|
||||
currentY: number;
|
||||
}
|
||||
|
||||
export default class Draggable extends React.Component<IProps, IState> {
|
||||
|
@ -58,13 +58,13 @@ export default class Draggable extends React.Component<IProps, IState> {
|
|||
|
||||
document.addEventListener("mousemove", this.state.onMouseMove);
|
||||
document.addEventListener("mouseup", this.state.onMouseUp);
|
||||
}
|
||||
};
|
||||
|
||||
private onMouseUp = (event: MouseEvent): void => {
|
||||
document.removeEventListener("mousemove", this.state.onMouseMove);
|
||||
document.removeEventListener("mouseup", this.state.onMouseUp);
|
||||
this.props.onMouseUp(event);
|
||||
}
|
||||
};
|
||||
|
||||
private onMouseMove(event: MouseEvent): void {
|
||||
const newLocation = this.props.dragFunc(this.state.location, event);
|
||||
|
@ -75,7 +75,7 @@ export default class Draggable extends React.Component<IProps, IState> {
|
|||
}
|
||||
|
||||
render() {
|
||||
return <div className={this.props.className} onMouseDown={this.onMouseDown.bind(this)} />
|
||||
return <div className={this.props.className} onMouseDown={this.onMouseDown.bind(this)} />;
|
||||
}
|
||||
|
||||
}
|
|
@ -87,20 +87,20 @@ interface ITextareaProps extends IProps, TextareaHTMLAttributes<HTMLTextAreaElem
|
|||
type PropShapes = IInputProps | ISelectProps | ITextareaProps;
|
||||
|
||||
interface IState {
|
||||
valid: boolean,
|
||||
feedback: React.ReactNode,
|
||||
feedbackVisible: boolean,
|
||||
focused: boolean,
|
||||
valid: boolean;
|
||||
feedback: React.ReactNode;
|
||||
feedbackVisible: boolean;
|
||||
focused: boolean;
|
||||
}
|
||||
|
||||
export default class Field extends React.PureComponent<PropShapes, IState> {
|
||||
private id: string;
|
||||
private input: HTMLInputElement;
|
||||
|
||||
private static defaultProps = {
|
||||
public static readonly defaultProps = {
|
||||
element: "input",
|
||||
type: "text",
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* This was changed from throttle to debounce: this is more traditional for
|
||||
|
|
|
@ -20,15 +20,15 @@ import Draggable, {ILocationState} from './Draggable';
|
|||
|
||||
interface IProps {
|
||||
// Current room
|
||||
roomId: string,
|
||||
minWidth: number,
|
||||
maxWidth: number,
|
||||
};
|
||||
roomId: string;
|
||||
minWidth: number;
|
||||
maxWidth: number;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
width: number,
|
||||
IRCLayoutRoot: HTMLElement,
|
||||
};
|
||||
width: number;
|
||||
IRCLayoutRoot: HTMLElement;
|
||||
}
|
||||
|
||||
export default class IRCTimelineProfileResizer extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
|
@ -37,20 +37,19 @@ export default class IRCTimelineProfileResizer extends React.Component<IProps, I
|
|||
this.state = {
|
||||
width: SettingsStore.getValue("ircDisplayNameWidth", this.props.roomId),
|
||||
IRCLayoutRoot: null,
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
IRCLayoutRoot: document.querySelector(".mx_IRCLayout") as HTMLElement,
|
||||
}, () => this.updateCSSWidth(this.state.width))
|
||||
}, () => this.updateCSSWidth(this.state.width));
|
||||
}
|
||||
|
||||
private dragFunc = (location: ILocationState, event: React.MouseEvent<Element, MouseEvent>): ILocationState => {
|
||||
const offset = event.clientX - location.currentX;
|
||||
const newWidth = this.state.width + offset;
|
||||
|
||||
console.log({offset})
|
||||
// If we're trying to go smaller than min width, don't.
|
||||
if (newWidth < this.props.minWidth) {
|
||||
return location;
|
||||
|
@ -69,8 +68,8 @@ export default class IRCTimelineProfileResizer extends React.Component<IProps, I
|
|||
return {
|
||||
currentX: event.clientX,
|
||||
currentY: location.currentY,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
private updateCSSWidth(newWidth: number) {
|
||||
this.state.IRCLayoutRoot.style.setProperty("--name-width", newWidth + "px");
|
||||
|
@ -83,6 +82,10 @@ export default class IRCTimelineProfileResizer extends React.Component<IProps, I
|
|||
}
|
||||
|
||||
render() {
|
||||
return <Draggable className="mx_ProfileResizer" dragFunc={this.dragFunc.bind(this)} onMouseUp={this.onMoueUp.bind(this)}/>
|
||||
return <Draggable
|
||||
className="mx_ProfileResizer"
|
||||
dragFunc={this.dragFunc.bind(this)}
|
||||
onMouseUp={this.onMoueUp.bind(this)}
|
||||
/>;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -48,18 +48,18 @@ export default class SettingsFlag extends React.Component<IProps, IState> {
|
|||
this.props.roomId,
|
||||
this.props.isExplicit,
|
||||
),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private onChange = (checked: boolean): void => {
|
||||
this.save(checked);
|
||||
this.setState({ value: checked });
|
||||
if (this.props.onChange) this.props.onChange(checked);
|
||||
}
|
||||
};
|
||||
|
||||
private checkBoxOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.onChange(e.target.checked);
|
||||
}
|
||||
};
|
||||
|
||||
private save = (val?: boolean): void => {
|
||||
return SettingsStore.setValue(
|
||||
|
@ -68,7 +68,7 @@ export default class SettingsFlag extends React.Component<IProps, IState> {
|
|||
this.props.level,
|
||||
val !== undefined ? val : this.state.value,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
const canChange = SettingsStore.canSetValue(this.props.name, this.props.roomId, this.props.level);
|
||||
|
|
|
@ -65,9 +65,9 @@ export default class Slider extends React.Component<IProps> {
|
|||
|
||||
const intervalWidth = 1 / (values.length - 1);
|
||||
|
||||
const linearInterpolation = (value - closestLessValue) / (closestGreaterValue - closestLessValue)
|
||||
const linearInterpolation = (value - closestLessValue) / (closestGreaterValue - closestLessValue);
|
||||
|
||||
return 100 * (closest - 1 + linearInterpolation) * intervalWidth
|
||||
return 100 * (closest - 1 + linearInterpolation) * intervalWidth;
|
||||
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ export default class Slider extends React.Component<IProps> {
|
|||
selection = <div className="mx_Slider_selection">
|
||||
<div className="mx_Slider_selectionDot" style={{left: "calc(-0.55em + " + offset + "%)"}} />
|
||||
<hr style={{width: offset + "%"}} />
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
return <div className="mx_Slider">
|
||||
|
@ -115,13 +115,13 @@ export default class Slider extends React.Component<IProps> {
|
|||
|
||||
interface IDotProps {
|
||||
// Callback for behavior onclick
|
||||
onClick: () => void,
|
||||
onClick: () => void;
|
||||
|
||||
// Whether the dot should appear active
|
||||
active: boolean,
|
||||
active: boolean;
|
||||
|
||||
// The label on the dot
|
||||
label: string,
|
||||
label: string;
|
||||
|
||||
// Whether the slider is disabled
|
||||
disabled: boolean;
|
||||
|
@ -129,7 +129,7 @@ interface IDotProps {
|
|||
|
||||
class Dot extends React.PureComponent<IDotProps> {
|
||||
render(): React.ReactNode {
|
||||
let className = "mx_Slider_dot"
|
||||
let className = "mx_Slider_dot";
|
||||
if (!this.props.disabled && this.props.active) {
|
||||
className += " mx_Slider_dotActive";
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ export default class StyledCheckbox extends React.PureComponent<IProps, IState>
|
|||
|
||||
public static readonly defaultProps = {
|
||||
className: "",
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
@ -51,6 +51,6 @@ export default class StyledCheckbox extends React.PureComponent<IProps, IState>
|
|||
{ this.props.children }
|
||||
</div>
|
||||
</label>
|
||||
</span>
|
||||
</span>;
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ interface IState {
|
|||
export default class StyledRadioButton extends React.PureComponent<IProps, IState> {
|
||||
public static readonly defaultProps = {
|
||||
className: '',
|
||||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
const { children, className, disabled, ...otherProps } = this.props;
|
||||
|
@ -43,6 +43,6 @@ export default class StyledRadioButton extends React.PureComponent<IProps, IStat
|
|||
<div><div></div></div>
|
||||
<span>{children}</span>
|
||||
<div className="mx_RadioButton_spacer" />
|
||||
</label>
|
||||
</label>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ interface IProps {
|
|||
|
||||
// Called when the checked state changes. First argument will be the new state.
|
||||
onChange(checked: boolean): void;
|
||||
};
|
||||
}
|
||||
|
||||
// Controlled Toggle Switch element, written with Accessibility in mind
|
||||
export default ({checked, disabled = false, onChange, ...props}: IProps) => {
|
||||
|
|
|
@ -29,15 +29,15 @@ const MIN_TOOLTIP_HEIGHT = 25;
|
|||
|
||||
interface IProps {
|
||||
// Class applied to the element used to position the tooltip
|
||||
className: string,
|
||||
className: string;
|
||||
// Class applied to the tooltip itself
|
||||
tooltipClassName?: string,
|
||||
tooltipClassName?: string;
|
||||
// Whether the tooltip is visible or hidden.
|
||||
// The hidden state allows animating the tooltip away via CSS.
|
||||
// Defaults to visible if unset.
|
||||
visible?: boolean,
|
||||
visible?: boolean;
|
||||
// the react element to put into the tooltip
|
||||
label: React.ReactNode,
|
||||
label: React.ReactNode;
|
||||
}
|
||||
|
||||
export default class Tooltip extends React.Component<IProps> {
|
||||
|
@ -126,7 +126,7 @@ export default class Tooltip extends React.Component<IProps> {
|
|||
tooltip: this.tooltip,
|
||||
parent: parent,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
// Render a placeholder
|
||||
|
|
|
@ -240,6 +240,7 @@ export class ListNotificationState extends EventEmitter implements IDestroyable
|
|||
this.rooms = rooms;
|
||||
for (const oldRoom of diff.removed) {
|
||||
const state = this.states[oldRoom.roomId];
|
||||
if (!state) continue; // We likely just didn't have a badge (race condition)
|
||||
delete this.states[oldRoom.roomId];
|
||||
state.off(NOTIFICATION_STATE_UPDATE, this.onRoomNotificationStateUpdate);
|
||||
state.destroy();
|
||||
|
|
|
@ -97,7 +97,7 @@ export default class RoomBreadcrumbs2 extends React.PureComponent<IProps, IState
|
|||
>
|
||||
<RoomAvatar room={r} width={32} height={32}/>
|
||||
</AccessibleButton>
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
if (tiles.length > 0) {
|
||||
|
|
|
@ -41,6 +41,11 @@ import { ListAlgorithm, SortAlgorithm } from "../../../stores/room-list/algorith
|
|||
* warning disappears. *
|
||||
*******************************************************************/
|
||||
|
||||
const SHOW_N_BUTTON_HEIGHT = 32; // As defined by CSS
|
||||
const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS
|
||||
|
||||
const MAX_PADDING_HEIGHT = SHOW_N_BUTTON_HEIGHT + RESIZE_HANDLE_HEIGHT;
|
||||
|
||||
interface IProps {
|
||||
forRooms: boolean;
|
||||
rooms?: Room[];
|
||||
|
@ -105,7 +110,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private onShowAllClick = () => {
|
||||
this.props.layout.visibleTiles = this.numTiles;
|
||||
this.props.layout.visibleTiles = this.props.layout.tilesWithPadding(this.numTiles, MAX_PADDING_HEIGHT);
|
||||
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
||||
};
|
||||
|
||||
|
@ -359,7 +364,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
|||
{showMoreText}
|
||||
</div>
|
||||
);
|
||||
} else if (tiles.length <= nVisible) {
|
||||
} else if (tiles.length <= nVisible && tiles.length > this.props.layout.minVisibleTiles) {
|
||||
// we have all tiles visible - add a button to show less
|
||||
let showLessText = (
|
||||
<span className='mx_RoomSublist2_showNButtonText'>
|
||||
|
@ -393,18 +398,16 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
|||
// goes backwards and can become wildly incorrect (visibleTiles says 18 when there's
|
||||
// only mathematically 7 possible).
|
||||
|
||||
const showMoreHeight = 32; // As defined by CSS
|
||||
const resizeHandleHeight = 4; // As defined by CSS
|
||||
|
||||
// The padding is variable though, so figure out what we need padding for.
|
||||
let padding = 0;
|
||||
if (showNButton) padding += showMoreHeight;
|
||||
if (handles.length > 0) padding += resizeHandleHeight;
|
||||
if (showNButton) padding += SHOW_N_BUTTON_HEIGHT;
|
||||
padding += RESIZE_HANDLE_HEIGHT; // always append the handle height
|
||||
|
||||
const minTilesPx = layout.calculateTilesToPixelsMin(tiles.length, layout.minVisibleTiles, padding);
|
||||
const relativeTiles = layout.tilesWithPadding(tiles.length, padding);
|
||||
const minTilesPx = layout.calculateTilesToPixelsMin(relativeTiles, layout.minVisibleTiles, padding);
|
||||
const maxTilesPx = layout.tilesToPixelsWithPadding(tiles.length, padding);
|
||||
const tilesWithoutPadding = Math.min(tiles.length, layout.visibleTiles);
|
||||
const tilesPx = layout.calculateTilesToPixelsMin(tiles.length, tilesWithoutPadding, padding);
|
||||
const tilesWithoutPadding = Math.min(relativeTiles, layout.visibleTiles);
|
||||
const tilesPx = layout.calculateTilesToPixelsMin(relativeTiles, tilesWithoutPadding, padding);
|
||||
|
||||
content = (
|
||||
<ResizableBox
|
||||
|
@ -420,7 +423,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
|||
{visibleTiles}
|
||||
{showNButton}
|
||||
</ResizableBox>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: onKeyDown support
|
||||
|
|
|
@ -232,7 +232,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
|
|||
/>
|
||||
{contextMenu}
|
||||
</React.Fragment>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public render(): React.ReactElement {
|
||||
|
|
|
@ -113,7 +113,7 @@ export default class CrossSigningPanel extends React.PureComponent {
|
|||
_bootstrapSecureSecretStorage = async (forceReset=false) => {
|
||||
this.setState({ error: null });
|
||||
try {
|
||||
await accessSecretStorage(() => undefined, {forceReset});
|
||||
await accessSecretStorage(() => undefined, forceReset);
|
||||
} catch (e) {
|
||||
this.setState({ error: e });
|
||||
console.error("Error bootstrapping secret storage", e);
|
||||
|
|
|
@ -34,14 +34,14 @@ interface IProps {
|
|||
}
|
||||
|
||||
interface IThemeState {
|
||||
theme: string,
|
||||
useSystemTheme: boolean,
|
||||
theme: string;
|
||||
useSystemTheme: boolean;
|
||||
}
|
||||
|
||||
export interface CustomThemeMessage {
|
||||
isError: boolean,
|
||||
text: string
|
||||
};
|
||||
isError: boolean;
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface IState extends IThemeState {
|
||||
// String displaying the current selected fontSize.
|
||||
|
@ -164,7 +164,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
|
|||
);
|
||||
|
||||
return {valid: true, feedback: _t('Use between %(min)s pt and %(max)s pt', {min, max})};
|
||||
}
|
||||
};
|
||||
|
||||
private onAddCustomTheme = async (): Promise<void> => {
|
||||
let currentThemes: string[] = SettingsStore.getValue("custom_themes");
|
||||
|
|
|
@ -90,7 +90,7 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
|
|||
} catch (err) {
|
||||
console.error("Error while cancelling verification request", err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
accept = async () => {
|
||||
ToastStore.sharedInstance().dismissToast(this.props.toastKey);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue