mirror of https://github.com/vector-im/riot-web
				
				
				
			Selected state, cleanup, and profile display
							parent
							
								
									ea6b0a60ab
								
							
						
					
					
						commit
						1d8833e9f8
					
				| 
						 | 
					@ -14,6 +14,9 @@ See the License for the specific language governing permissions and
 | 
				
			||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: Rename to mx_LeftPanel during replacement of old component
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: Put these variables in the right place, or namespace them.
 | 
				
			||||||
$tagPanelWidth: 70px;
 | 
					$tagPanelWidth: 70px;
 | 
				
			||||||
$roomListMinimizedWidth: 50px;
 | 
					$roomListMinimizedWidth: 50px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
 | 
				
			||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: Rename to mx_RoomList during replacement of old component
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_RoomList2 {
 | 
					.mx_RoomList2 {
 | 
				
			||||||
    // Create a column-based flexbox for the sublists. That's pretty much all we have to
 | 
					    // Create a column-based flexbox for the sublists. That's pretty much all we have to
 | 
				
			||||||
    // worry about in this stylesheet.
 | 
					    // worry about in this stylesheet.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
 | 
				
			||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: Rename to mx_RoomSublist during replacement of old component
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@import "../../../../node_modules/react-resizable/css/styles.css";
 | 
					@import "../../../../node_modules/react-resizable/css/styles.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_RoomSublist2 {
 | 
					.mx_RoomSublist2 {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,15 +14,24 @@ See the License for the specific language governing permissions and
 | 
				
			||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: Rename to mx_RoomTile during replacement of old component
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Note: the room tile expects to be in a flexbox column container
 | 
					// Note: the room tile expects to be in a flexbox column container
 | 
				
			||||||
.mx_RoomTile2 {
 | 
					.mx_RoomTile2 {
 | 
				
			||||||
    width: 100%;
 | 
					    width: calc(100% - 11px); // 8px for padding (4px on either side), 3px for margin
 | 
				
			||||||
    padding-bottom: 12px;
 | 
					    margin-bottom: 4px;
 | 
				
			||||||
 | 
					    margin-right: 3px;
 | 
				
			||||||
 | 
					    padding: 4px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // The tile is also a flexbox row itself
 | 
					    // The tile is also a flexbox row itself
 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
    flex-wrap: wrap;
 | 
					    flex-wrap: wrap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.mx_RoomTile2_selected {
 | 
				
			||||||
 | 
					        background-color: $roomtile2-selected-bg-color;
 | 
				
			||||||
 | 
					        border-radius: 32px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .mx_RoomTile2_avatarContainer {
 | 
					    .mx_RoomTile2_avatarContainer {
 | 
				
			||||||
        margin-right: 8px;
 | 
					        margin-right: 8px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -176,6 +176,7 @@ $header-divider-color: #91A1C0;
 | 
				
			||||||
// TODO: Dark theme
 | 
					// TODO: Dark theme
 | 
				
			||||||
$roomtile2-preview-color: #9e9e9e;
 | 
					$roomtile2-preview-color: #9e9e9e;
 | 
				
			||||||
$roomtile2-badge-color: #61708b;
 | 
					$roomtile2-badge-color: #61708b;
 | 
				
			||||||
 | 
					$roomtile2-selected-bg-color: #FFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$roomtile-name-color: #61708b;
 | 
					$roomtile-name-color: #61708b;
 | 
				
			||||||
$roomtile-badge-fg-color: $accent-fg-color;
 | 
					$roomtile-badge-fg-color: $accent-fg-color;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@ import RoomViewStore from './stores/RoomViewStore';
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class ActiveRoomObserver {
 | 
					class ActiveRoomObserver {
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        this._listeners = {};
 | 
					        this._listeners = {}; // key=roomId, value=function(isActive:boolean)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._activeRoomId = RoomViewStore.getRoomId();
 | 
					        this._activeRoomId = RoomViewStore.getRoomId();
 | 
				
			||||||
        // TODO: We could self-destruct when the last listener goes away, or at least
 | 
					        // TODO: We could self-destruct when the last listener goes away, or at least
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,10 @@ class ActiveRoomObserver {
 | 
				
			||||||
        this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate.bind(this));
 | 
					        this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate.bind(this));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get activeRoomId(): string {
 | 
				
			||||||
 | 
					        return this._activeRoomId;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    addListener(roomId, listener) {
 | 
					    addListener(roomId, listener) {
 | 
				
			||||||
        if (!this._listeners[roomId]) this._listeners[roomId] = [];
 | 
					        if (!this._listeners[roomId]) this._listeners[roomId] = [];
 | 
				
			||||||
        this._listeners[roomId].push(listener);
 | 
					        this._listeners[roomId].push(listener);
 | 
				
			||||||
| 
						 | 
					@ -51,23 +55,23 @@ class ActiveRoomObserver {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _emit(roomId) {
 | 
					    _emit(roomId, isActive: boolean) {
 | 
				
			||||||
        if (!this._listeners[roomId]) return;
 | 
					        if (!this._listeners[roomId]) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (const l of this._listeners[roomId]) {
 | 
					        for (const l of this._listeners[roomId]) {
 | 
				
			||||||
            l.call();
 | 
					            l.call(null, isActive);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onRoomViewStoreUpdate() {
 | 
					    _onRoomViewStoreUpdate() {
 | 
				
			||||||
        // emit for the old room ID
 | 
					        // emit for the old room ID
 | 
				
			||||||
        if (this._activeRoomId) this._emit(this._activeRoomId);
 | 
					        if (this._activeRoomId) this._emit(this._activeRoomId, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // update our cache
 | 
					        // update our cache
 | 
				
			||||||
        this._activeRoomId = RoomViewStore.getRoomId();
 | 
					        this._activeRoomId = RoomViewStore.getRoomId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // and emit for the new one
 | 
					        // and emit for the new one
 | 
				
			||||||
        if (this._activeRoomId) this._emit(this._activeRoomId);
 | 
					        if (this._activeRoomId) this._emit(this._activeRoomId, true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,26 +86,35 @@ export default class LeftPanel2 extends React.Component<IProps, IState> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private renderHeader(): React.ReactNode {
 | 
					    private renderHeader(): React.ReactNode {
 | 
				
			||||||
        // TODO: Use real profile info
 | 
					        // TODO: Update when profile info changes
 | 
				
			||||||
        // TODO: Presence
 | 
					        // TODO: Presence
 | 
				
			||||||
        // TODO: Breadcrumbs toggle
 | 
					        // TODO: Breadcrumbs toggle
 | 
				
			||||||
        // TODO: Menu button
 | 
					        // TODO: Menu button
 | 
				
			||||||
        const avatarSize = 32;
 | 
					        const avatarSize = 32;
 | 
				
			||||||
 | 
					        // TODO: Don't do this profile lookup in render()
 | 
				
			||||||
 | 
					        const client = MatrixClientPeg.get();
 | 
				
			||||||
 | 
					        let displayName = client.getUserId();
 | 
				
			||||||
 | 
					        let avatarUrl: string = null;
 | 
				
			||||||
 | 
					        const myUser = client.getUser(client.getUserId());
 | 
				
			||||||
 | 
					        if (myUser) {
 | 
				
			||||||
 | 
					            displayName = myUser.rawDisplayName;
 | 
				
			||||||
 | 
					            avatarUrl = myUser.avatarUrl;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <div className="mx_LeftPanel2_userHeader">
 | 
					            <div className="mx_LeftPanel2_userHeader">
 | 
				
			||||||
                <div className="mx_LeftPanel2_headerRow">
 | 
					                <div className="mx_LeftPanel2_headerRow">
 | 
				
			||||||
                    <span className="mx_LeftPanel2_userAvatarContainer">
 | 
					                    <span className="mx_LeftPanel2_userAvatarContainer">
 | 
				
			||||||
                        <BaseAvatar
 | 
					                        <BaseAvatar
 | 
				
			||||||
                            idName={MatrixClientPeg.get().getUserId()}
 | 
					                            idName={MatrixClientPeg.get().getUserId()}
 | 
				
			||||||
                            name={"TODO: Display Name"}
 | 
					                            name={displayName}
 | 
				
			||||||
                            url={null}
 | 
					                            url={avatarUrl}
 | 
				
			||||||
                            width={avatarSize}
 | 
					                            width={avatarSize}
 | 
				
			||||||
                            height={avatarSize}
 | 
					                            height={avatarSize}
 | 
				
			||||||
                            resizeMethod="crop"
 | 
					                            resizeMethod="crop"
 | 
				
			||||||
                            className="mx_LeftPanel2_userAvatar"
 | 
					                            className="mx_LeftPanel2_userAvatar"
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                    </span>
 | 
					                    </span>
 | 
				
			||||||
                    <span className="mx_LeftPanel2_userName">Irene</span>
 | 
					                    <span className="mx_LeftPanel2_userName">{displayName}</span>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div className="mx_LeftPanel2_headerRow mx_LeftPanel2_breadcrumbsContainer">
 | 
					                <div className="mx_LeftPanel2_headerRow mx_LeftPanel2_breadcrumbsContainer">
 | 
				
			||||||
                    <RoomBreadcrumbs />
 | 
					                    <RoomBreadcrumbs />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,6 @@ import classNames from "classnames";
 | 
				
			||||||
import { RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex";
 | 
					import { RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex";
 | 
				
			||||||
import AccessibleButton from "../../views/elements/AccessibleButton";
 | 
					import AccessibleButton from "../../views/elements/AccessibleButton";
 | 
				
			||||||
import RoomAvatar from "../../views/avatars/RoomAvatar";
 | 
					import RoomAvatar from "../../views/avatars/RoomAvatar";
 | 
				
			||||||
import Tooltip from "../../views/elements/Tooltip";
 | 
					 | 
				
			||||||
import dis from '../../../dispatcher/dispatcher';
 | 
					import dis from '../../../dispatcher/dispatcher';
 | 
				
			||||||
import { Key } from "../../../Keyboard";
 | 
					import { Key } from "../../../Keyboard";
 | 
				
			||||||
import * as RoomNotifs from '../../../RoomNotifs';
 | 
					import * as RoomNotifs from '../../../RoomNotifs';
 | 
				
			||||||
| 
						 | 
					@ -32,6 +31,7 @@ import * as Unread from '../../../Unread';
 | 
				
			||||||
import * as FormattingUtils from "../../../utils/FormattingUtils";
 | 
					import * as FormattingUtils from "../../../utils/FormattingUtils";
 | 
				
			||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
 | 
					import { MatrixClientPeg } from "../../../MatrixClientPeg";
 | 
				
			||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
					import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
				
			||||||
 | 
					import ActiveRoomObserver from "../../../ActiveRoomObserver";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*******************************************************************
 | 
					/*******************************************************************
 | 
				
			||||||
 *   CAUTION                                                       *
 | 
					 *   CAUTION                                                       *
 | 
				
			||||||
| 
						 | 
					@ -66,6 +66,7 @@ interface INotificationState {
 | 
				
			||||||
interface IState {
 | 
					interface IState {
 | 
				
			||||||
    hover: boolean;
 | 
					    hover: boolean;
 | 
				
			||||||
    notificationState: INotificationState;
 | 
					    notificationState: INotificationState;
 | 
				
			||||||
 | 
					    selected: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
					export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
				
			||||||
| 
						 | 
					@ -88,12 +89,14 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
				
			||||||
        this.state = {
 | 
					        this.state = {
 | 
				
			||||||
            hover: false,
 | 
					            hover: false,
 | 
				
			||||||
            notificationState: this.getNotificationState(),
 | 
					            notificationState: this.getNotificationState(),
 | 
				
			||||||
 | 
					            selected: ActiveRoomObserver.activeRoomId === this.props.room.roomId,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.props.room.on("Room.receipt", this.handleRoomEventUpdate);
 | 
					        this.props.room.on("Room.receipt", this.handleRoomEventUpdate);
 | 
				
			||||||
        this.props.room.on("Room.timeline", this.handleRoomEventUpdate);
 | 
					        this.props.room.on("Room.timeline", this.handleRoomEventUpdate);
 | 
				
			||||||
        this.props.room.on("Room.redaction", this.handleRoomEventUpdate);
 | 
					        this.props.room.on("Room.redaction", this.handleRoomEventUpdate);
 | 
				
			||||||
        MatrixClientPeg.get().on("Event.decrypted", this.handleRoomEventUpdate);
 | 
					        MatrixClientPeg.get().on("Event.decrypted", this.handleRoomEventUpdate);
 | 
				
			||||||
 | 
					        ActiveRoomObserver.addListener(this.props.room.roomId, this.onActiveRoomUpdate);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public componentWillUnmount() {
 | 
					    public componentWillUnmount() {
 | 
				
			||||||
| 
						 | 
					@ -101,6 +104,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
				
			||||||
            this.props.room.removeListener("Room.receipt", this.handleRoomEventUpdate);
 | 
					            this.props.room.removeListener("Room.receipt", this.handleRoomEventUpdate);
 | 
				
			||||||
            this.props.room.removeListener("Room.timeline", this.handleRoomEventUpdate);
 | 
					            this.props.room.removeListener("Room.timeline", this.handleRoomEventUpdate);
 | 
				
			||||||
            this.props.room.removeListener("Room.redaction", this.handleRoomEventUpdate);
 | 
					            this.props.room.removeListener("Room.redaction", this.handleRoomEventUpdate);
 | 
				
			||||||
 | 
					            ActiveRoomObserver.removeListener(this.props.room.roomId, this.onActiveRoomUpdate);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (MatrixClientPeg.get()) {
 | 
					        if (MatrixClientPeg.get()) {
 | 
				
			||||||
            MatrixClientPeg.get().removeListener("Event.decrypted", this.handleRoomEventUpdate);
 | 
					            MatrixClientPeg.get().removeListener("Event.decrypted", this.handleRoomEventUpdate);
 | 
				
			||||||
| 
						 | 
					@ -187,6 +191,10 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private onActiveRoomUpdate = (isActive: boolean) => {
 | 
				
			||||||
 | 
					        this.setState({selected: isActive});
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public render(): React.ReactElement {
 | 
					    public render(): React.ReactElement {
 | 
				
			||||||
        // TODO: Collapsed state
 | 
					        // TODO: Collapsed state
 | 
				
			||||||
        // TODO: Invites
 | 
					        // TODO: Invites
 | 
				
			||||||
| 
						 | 
					@ -195,6 +203,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const classes = classNames({
 | 
					        const classes = classNames({
 | 
				
			||||||
            'mx_RoomTile2': true,
 | 
					            'mx_RoomTile2': true,
 | 
				
			||||||
 | 
					            'mx_RoomTile2_selected': this.state.selected,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let badge;
 | 
					        let badge;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue