diff options
author | Thibaut Girka <thib@sitedethib.com> | 2019-06-09 12:07:23 +0200 |
---|---|---|
committer | multiple creatures <dev@multiple-creature.party> | 2019-11-19 16:40:34 -0600 |
commit | c28703fafd81161ff8da5e930ec56c3e1a58c20f (patch) | |
tree | 7c12fb8d4626434272a39d4c20ec45cea87084e4 /app/javascript/flavours/glitch/features/direct_timeline/components | |
parent | d107e52a8ae493312ef3025bd7119b839b8d5aaa (diff) |
Add DM conversations mode similar to upstream
Diffstat (limited to 'app/javascript/flavours/glitch/features/direct_timeline/components')
-rw-r--r-- | app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js | 64 | ||||
-rw-r--r-- | app/javascript/flavours/glitch/features/direct_timeline/components/conversations_list.js | 73 |
2 files changed, 137 insertions, 0 deletions
diff --git a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js new file mode 100644 index 000000000..9ddeabe75 --- /dev/null +++ b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js @@ -0,0 +1,64 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import StatusContainer from 'flavours/glitch/containers/status_container'; + +export default class Conversation extends ImmutablePureComponent { + + static contextTypes = { + router: PropTypes.object, + }; + + static propTypes = { + conversationId: PropTypes.string.isRequired, + accounts: ImmutablePropTypes.list.isRequired, + lastStatusId: PropTypes.string, + unread:PropTypes.bool.isRequired, + onMoveUp: PropTypes.func, + onMoveDown: PropTypes.func, + markRead: PropTypes.func.isRequired, + }; + + handleClick = () => { + if (!this.context.router) { + return; + } + + const { lastStatusId, unread, markRead } = this.props; + + if (unread) { + markRead(); + } + + this.context.router.history.push(`/statuses/${lastStatusId}`); + } + + handleHotkeyMoveUp = () => { + this.props.onMoveUp(this.props.conversationId); + } + + handleHotkeyMoveDown = () => { + this.props.onMoveDown(this.props.conversationId); + } + + render () { + const { accounts, lastStatusId, unread } = this.props; + + if (lastStatusId === null) { + return null; + } + + return ( + <StatusContainer + id={lastStatusId} + unread={unread} + otherAccounts={accounts} + onMoveUp={this.handleHotkeyMoveUp} + onMoveDown={this.handleHotkeyMoveDown} + onClick={this.handleClick} + /> + ); + } + +} diff --git a/app/javascript/flavours/glitch/features/direct_timeline/components/conversations_list.js b/app/javascript/flavours/glitch/features/direct_timeline/components/conversations_list.js new file mode 100644 index 000000000..4fa76fd6d --- /dev/null +++ b/app/javascript/flavours/glitch/features/direct_timeline/components/conversations_list.js @@ -0,0 +1,73 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import ConversationContainer from '../containers/conversation_container'; +import ScrollableList from 'flavours/glitch/components/scrollable_list'; +import { debounce } from 'lodash'; + +export default class ConversationsList extends ImmutablePureComponent { + + static propTypes = { + conversations: ImmutablePropTypes.list.isRequired, + hasMore: PropTypes.bool, + isLoading: PropTypes.bool, + onLoadMore: PropTypes.func, + }; + + getCurrentIndex = id => this.props.conversations.findIndex(x => x.get('id') === id) + + handleMoveUp = id => { + const elementIndex = this.getCurrentIndex(id) - 1; + this._selectChild(elementIndex, true); + } + + handleMoveDown = id => { + const elementIndex = this.getCurrentIndex(id) + 1; + this._selectChild(elementIndex, false); + } + + _selectChild (index, align_top) { + const container = this.node.node; + const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`); + + if (element) { + if (align_top && container.scrollTop > element.offsetTop) { + element.scrollIntoView(true); + } else if (!align_top && container.scrollTop + container.clientHeight < element.offsetTop + element.offsetHeight) { + element.scrollIntoView(false); + } + element.focus(); + } + } + + setRef = c => { + this.node = c; + } + + handleLoadOlder = debounce(() => { + const last = this.props.conversations.last(); + + if (last && last.get('last_status')) { + this.props.onLoadMore(last.get('last_status')); + } + }, 300, { leading: true }) + + render () { + const { conversations, onLoadMore, ...other } = this.props; + + return ( + <ScrollableList {...other} onLoadMore={onLoadMore && this.handleLoadOlder} scrollKey='direct' ref={this.setRef}> + {conversations.map(item => ( + <ConversationContainer + key={item.get('id')} + conversationId={item.get('id')} + onMoveUp={this.handleMoveUp} + onMoveDown={this.handleMoveDown} + /> + ))} + </ScrollableList> + ); + } + +} |