From 3cc671c87dbf404a8935ad11ca57cfc0583a1406 Mon Sep 17 00:00:00 2001 From: Sven Slootweg Date: Sun, 14 Jul 2019 23:41:19 +0200 Subject: [PATCH] Refactoring room view --- src/components/chat.js | 203 +++++++++++++++++++--------------------- src/lib/group-events.js | 34 +++++++ 2 files changed, 130 insertions(+), 107 deletions(-) create mode 100644 src/lib/group-events.js diff --git a/src/components/chat.js b/src/components/chat.js index 23ff2e6..a11fbda 100644 --- a/src/components/chat.js +++ b/src/components/chat.js @@ -1,49 +1,50 @@ -'use strict'; -const React = require('react'); -const create = require('create-react-class'); -const sanitize = require('sanitize-html'); +"use strict"; -const Event = require('./events/Event.js'); -const Info = require('./info.js'); -const Input = require('./input.js'); -const User = require('./events/user.js'); -const Loading = require('./loading.js'); +const Promise = require("bluebird"); +const React = require("react"); +const create = require("create-react-class"); +const sanitize = require("sanitize-html"); + +const Event = require("./events/Event.js"); +const Info = require("./info.js"); +const Input = require("./input.js"); +const User = require("./events/user.js"); +const Loading = require("./loading.js"); const generateJdenticon = require("../lib/generate-jdenticon"); +const groupEvents = require("../lib/group-events"); let eventFunctions = { plaintext: function() { - let plain = "unknown event"; - if (this.type == "m.room.message") { - plain = this.content.body; - if (this.content.format == "org.matrix.custom.html") { - plain = sanitize(this.content.formatted_body, {allowedTags: []}); + return sanitize(this.content.formatted_body, {allowedTags: []}); + } else { + return this.content.body; } - } - if (this.type == "m.room.member") { + } else if (this.type == "m.room.member") { if (this.content.membership == "invite") { - plain = `${this.sender} invited ${this.state_key}`; + return `${this.sender} invited ${this.state_key}`; } else if (this.content.membership == "join") { - plain = `${this.state_key} joined the room`; + return `${this.state_key} joined the room`; } else if (this.content.membership == "leave") { - plain = `${this.state_key} left the room`; + return `${this.state_key} left the room`; } else if (this.content.membership == "kick") { - plain = `${this.sender} kicked ${this.state_key}`; + return `${this.sender} kicked ${this.state_key}`; } else if (this.content.membership == "ban") { - plain = `${this.sender} banned ${this.state_key}`; + return `${this.sender} banned ${this.state_key}`; + } else { + return "unknown member event"; } - } - if (this.type == "m.room.avatar") { + } else if (this.type == "m.room.avatar") { if (this.content.url.length > 0) { - plain = `${this.sender} changed the room avatar`; + return `${this.sender} changed the room avatar`; } - } - if (this.type == "m.room.name") { + } else if (this.type == "m.room.name") { return `${this.sender} changed the room name to ${this.content.name}`; + } else { + return "unknown event"; } - return plain; } }; @@ -59,114 +60,102 @@ let chat = create({ getSnapshotBeforeUpdate: function(_oldProps, _oldState) { let ref = this.state.ref; - if (ref == null) {return null;} - if ((ref.scrollHeight - ref.offsetHeight) - ref.scrollTop < 100) { // Less than 100px from bottom + + if (ref != null && (ref.scrollHeight - ref.offsetHeight) - ref.scrollTop < 100) { + // Less than 100px from bottom return true; + } else { + return null; } - return null; }, componentDidUpdate(prevProps, prevState, snapshot) { let ref = this.state.ref; - if (ref == null) {return;} - if (snapshot) { // scroll to bottom + + if (ref != null && snapshot) { + // scroll to bottom ref.scrollTop = (ref.scrollHeight - ref.offsetHeight); } }, setRef: function(ref) { if (ref != null) { - this.setState({ref: ref}); + this.setState({ ref: ref }); } }, onReplyClick: function(e) { - this.setState({replyEvent: e}); + this.setState({ replyEvent: e }); }, paginateBackwards: function() { - if (this.state.loading) { - return; + if (!this.state.loading) { + let client = this.props.client; + let timeline = client.getRoom(this.props.roomId).getLiveTimeline(); + + this.setState({loading: true}); + + return Promise.try(() => { + return client.paginateEventTimeline(timeline, {backwards: true}); + }).then(() => { + this.setState({loading: false}); + }); } - let client = this.props.client; - client.paginateEventTimeline(client.getRoom(this.props.roomId).getLiveTimeline(), {backwards: true}).then(() => { - this.setState({loading: false}); - }); - this.setState({loading: true}); }, render: function() { let client = this.props.client; - let empty = ( -
-
- ); - if (this.props.roomId == undefined) { - //empty screen - return empty; - } - - let room = client.getRoom(this.props.roomId); - if (room == null) { - return empty; - } - let messageGroups = { - current: [], - groups: [], - sender: "", - type: "" - }; - - // if the sender is the same, add it to the 'current' messageGroup, if not, - // push the old one to 'groups' and start with a new array. - - let liveTimeline = room.getLiveTimeline(); - let liveTimelineEvents = liveTimeline.getEvents(); - - let events = []; - if (liveTimelineEvents.length > 0) { - liveTimelineEvents.forEach((MatrixEvent) => { - let event = MatrixEvent.event; - event = Object.assign(event, eventFunctions); - if (event.sender == null) { // localecho messages - event.sender = event.user_id; - event.local = true; - } - if (event.sender != messageGroups.sender || event.type != messageGroups.type) { - messageGroups.sender = event.sender; - messageGroups.type = event.type; - if (messageGroups.current.length != 0) { - messageGroups.groups.push(messageGroups.current); - } - messageGroups.current = []; - } - messageGroups.current.push(event); - }); - messageGroups.groups.push(messageGroups.current); + let empty =
; - events = messageGroups.groups.map((events) => { - return ; - }); - } - //TODO: replace with something that only renders events in view - return ( -
- -
-
-
- {this.state.loading ? - : - load older messages - } + if (this.props.roomId == null) { + //empty screen + return empty; + } else { + let room = client.getRoom(this.props.roomId); + if (room == null) { + return empty; + } else { + let liveTimeline = room.getLiveTimeline(); + let liveTimelineEvents = liveTimeline.getEvents(); + + let events = liveTimelineEvents.map((item) => { + let event = item.event; + + return Object.assign( + event, + eventFunctions, + (event.sender == null) + /* Whether this event is a local echo */ + ? { local: true, sender: event.user_id } + : null + ); + }); + + let eventGroups = groupEvents(events); + + //TODO: replace with something that only renders events in view + return ( +
+ +
+
+
+ {this.state.loading ? + : + load older messages + } +
+ {(eventGroups.map((group) => { + return ; + }))} +
- {events} +
-
- -
- ); + ); + } + } } }); diff --git a/src/lib/group-events.js b/src/lib/group-events.js new file mode 100644 index 0000000..0529736 --- /dev/null +++ b/src/lib/group-events.js @@ -0,0 +1,34 @@ +"use strict"; + +module.exports = function groupEvents(events) { + let currentSender = ""; + let currentType = ""; + let currentEvents = []; + let eventGroups = []; + + function finalizeGroup() { + if (currentEvents.length > 0) { + eventGroups.push({ + sender: currentSender, + events: currentEvents + }); + + currentEvents = []; + } + } + + events.forEach((event) => { + /* TODO: Eventually group multiple non-message events from a single user into a single event item as well, even when they are of different types */ + if (event.sender !== currentSender || event.type !== currentType) { + finalizeGroup(); + currentSender = event.sender; + currentType = event.type; + } + + currentEvents.push(event); + }); + + finalizeGroup(); + + return eventGroups; +};