Merge branch 'travis/communities/tag-panel' into travis/communities/room-behaviour

This commit is contained in:
Travis Ralston 2020-08-21 18:19:20 -06:00
commit dc95ca6776
5 changed files with 63 additions and 6 deletions

View file

@ -42,6 +42,9 @@ import IconizedContextMenu, {
IconizedContextMenuOption, IconizedContextMenuOption,
IconizedContextMenuOptionList IconizedContextMenuOptionList
} from "../views/context_menus/IconizedContextMenu"; } from "../views/context_menus/IconizedContextMenu";
import TagOrderStore from "../../stores/TagOrderStore";
import * as fbEmitter from "fbemitter";
import FlairStore from "../../stores/FlairStore";
interface IProps { interface IProps {
isMinimized: boolean; isMinimized: boolean;
@ -52,11 +55,16 @@ type PartialDOMRect = Pick<DOMRect, "width" | "left" | "top" | "height">;
interface IState { interface IState {
contextMenuPosition: PartialDOMRect; contextMenuPosition: PartialDOMRect;
isDarkTheme: boolean; isDarkTheme: boolean;
selectedCommunityProfile: {
displayName: string;
avatarMxc: string;
};
} }
export default class UserMenu extends React.Component<IProps, IState> { export default class UserMenu extends React.Component<IProps, IState> {
private dispatcherRef: string; private dispatcherRef: string;
private themeWatcherRef: string; private themeWatcherRef: string;
private tagStoreRef: fbEmitter.EventSubscription;
private buttonRef: React.RefObject<HTMLButtonElement> = createRef(); private buttonRef: React.RefObject<HTMLButtonElement> = createRef();
constructor(props: IProps) { constructor(props: IProps) {
@ -65,6 +73,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
this.state = { this.state = {
contextMenuPosition: null, contextMenuPosition: null,
isDarkTheme: this.isUserOnDarkTheme(), isDarkTheme: this.isUserOnDarkTheme(),
selectedCommunityProfile: null,
}; };
OwnProfileStore.instance.on(UPDATE_EVENT, this.onProfileUpdate); OwnProfileStore.instance.on(UPDATE_EVENT, this.onProfileUpdate);
@ -77,6 +86,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
public componentDidMount() { public componentDidMount() {
this.dispatcherRef = defaultDispatcher.register(this.onAction); this.dispatcherRef = defaultDispatcher.register(this.onAction);
this.themeWatcherRef = SettingsStore.watchSetting("theme", null, this.onThemeChanged); this.themeWatcherRef = SettingsStore.watchSetting("theme", null, this.onThemeChanged);
this.tagStoreRef = TagOrderStore.addListener(this.onTagStoreUpdate);
} }
public componentWillUnmount() { public componentWillUnmount() {
@ -93,6 +103,25 @@ export default class UserMenu extends React.Component<IProps, IState> {
return theme === "dark"; return theme === "dark";
} }
private onTagStoreUpdate = async () => {
if (!SettingsStore.getValue("feature_communities_v2_prototypes")) {
return;
}
const selectedId = TagOrderStore.getSelectedTags()[0];
if (!selectedId) {
this.setState({selectedCommunityProfile: null});
return;
}
// For some reason the group's profile info isn't on the js-sdk Group object but
// is in the flair store, so get it from there.
const profile = await FlairStore.getGroupProfileCached(MatrixClientPeg.get(), selectedId);
const displayName = profile.name || selectedId;
const avatarMxc = profile.avatarUrl;
this.setState({selectedCommunityProfile: {displayName, avatarMxc}});
};
private onProfileUpdate = async () => { private onProfileUpdate = async () => {
// the store triggered an update, so force a layout update. We don't // the store triggered an update, so force a layout update. We don't
// have any state to store here for that to magically happen. // have any state to store here for that to magically happen.
@ -295,7 +324,20 @@ export default class UserMenu extends React.Component<IProps, IState> {
public render() { public render() {
const avatarSize = 32; // should match border-radius of the avatar const avatarSize = 32; // should match border-radius of the avatar
let name = <span className="mx_UserMenu_userName">{OwnProfileStore.instance.displayName}</span>; let displayName = OwnProfileStore.instance.displayName || MatrixClientPeg.get().getUserId();
let avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(avatarSize);
if (this.state.selectedCommunityProfile) {
displayName = this.state.selectedCommunityProfile.displayName
const mxc = this.state.selectedCommunityProfile.avatarMxc;
if (mxc) {
avatarUrl = MatrixClientPeg.get().mxcUrlToHttp(mxc, avatarSize, avatarSize);
} else {
avatarUrl = null;
}
}
let name = <span className="mx_UserMenu_userName">{displayName}</span>;
let buttons = ( let buttons = (
<span className="mx_UserMenu_headerButtons"> <span className="mx_UserMenu_headerButtons">
{/* masked image in CSS */} {/* masked image in CSS */}
@ -324,9 +366,9 @@ export default class UserMenu extends React.Component<IProps, IState> {
<div className="mx_UserMenu_row"> <div className="mx_UserMenu_row">
<span className="mx_UserMenu_userAvatarContainer"> <span className="mx_UserMenu_userAvatarContainer">
<BaseAvatar <BaseAvatar
idName={MatrixClientPeg.get().getUserId()} idName={displayName}
name={OwnProfileStore.instance.displayName || MatrixClientPeg.get().getUserId()} name={displayName}
url={OwnProfileStore.instance.getHttpAvatarUrl(avatarSize)} url={avatarUrl}
width={avatarSize} width={avatarSize}
height={avatarSize} height={avatarSize}
resizeMethod="crop" resizeMethod="crop"

View file

@ -30,6 +30,7 @@ import GroupStore from '../../../stores/GroupStore';
import TagOrderStore from '../../../stores/TagOrderStore'; import TagOrderStore from '../../../stores/TagOrderStore';
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import AccessibleButton from "./AccessibleButton"; import AccessibleButton from "./AccessibleButton";
import SettingsStore from "../../../settings/SettingsStore";
// A class for a child of TagPanel (possibly wrapped in a DNDTagTile) that represents // A class for a child of TagPanel (possibly wrapped in a DNDTagTile) that represents
// a thing to click on for the user to filter the visible rooms in the RoomList to: // a thing to click on for the user to filter the visible rooms in the RoomList to:
@ -112,6 +113,7 @@ export default createReactClass({
}, },
onMouseOver: function() { onMouseOver: function() {
if (SettingsStore.getValue("feature_communities_v2_prototypes")) return;
this.setState({ hover: true }); this.setState({ hover: true });
}, },
@ -123,6 +125,7 @@ export default createReactClass({
// Prevent the TagTile onClick event firing as well // Prevent the TagTile onClick event firing as well
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
if (SettingsStore.getValue("feature_communities_v2_prototypes")) return;
this.setState({ hover: false }); this.setState({ hover: false });
this.props.openMenu(); this.props.openMenu();
}, },

View file

@ -444,6 +444,7 @@
"%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s",
"%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s",
"Change notification settings": "Change notification settings", "Change notification settings": "Change notification settings",
"Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.",
"New spinner design": "New spinner design", "New spinner design": "New spinner design",
"Message Pinning": "Message Pinning", "Message Pinning": "Message Pinning",
"Custom user status messages": "Custom user status messages", "Custom user status messages": "Custom user status messages",

View file

@ -109,6 +109,15 @@ export interface ISetting {
} }
export const SETTINGS: {[setting: string]: ISetting} = { export const SETTINGS: {[setting: string]: ISetting} = {
"feature_communities_v2_prototypes": {
isFeature: true,
displayName: _td(
"Communities v2 prototypes. Requires compatible homeserver. " +
"Highly experimental - use with caution.",
),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_new_spinner": { "feature_new_spinner": {
isFeature: true, isFeature: true,
displayName: _td("New spinner design"), displayName: _td("New spinner design"),

View file

@ -115,9 +115,11 @@ class TagOrderStore extends Store {
break; break;
} }
case 'select_tag': { case 'select_tag': {
const allowMultiple = !SettingsStore.getValue("feature_communities_v2_prototypes");
let newTags = []; let newTags = [];
// Shift-click semantics // Shift-click semantics
if (payload.shiftKey) { if (payload.shiftKey && allowMultiple) {
// Select range of tags // Select range of tags
let start = this._state.orderedTags.indexOf(this._state.anchorTag); let start = this._state.orderedTags.indexOf(this._state.anchorTag);
let end = this._state.orderedTags.indexOf(payload.tag); let end = this._state.orderedTags.indexOf(payload.tag);
@ -135,7 +137,7 @@ class TagOrderStore extends Store {
this._state.orderedTags.slice(start, end + 1).concat(newTags), this._state.orderedTags.slice(start, end + 1).concat(newTags),
)]; )];
} else { } else {
if (payload.ctrlOrCmdKey) { if (payload.ctrlOrCmdKey && allowMultiple) {
// Toggle individual tag // Toggle individual tag
if (this._state.selectedTags.includes(payload.tag)) { if (this._state.selectedTags.includes(payload.tag)) {
newTags = this._state.selectedTags.filter((t) => t !== payload.tag); newTags = this._state.selectedTags.filter((t) => t !== payload.tag);