Skip to content

Commit

Permalink
msg context menu in electron, copy msg text to clipboard
Browse files Browse the repository at this point in the history
  • Loading branch information
arnnis committed Jan 7, 2020
1 parent e18c274 commit 7ceb1a7
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 57 deletions.
2 changes: 1 addition & 1 deletion metro.config.js
Expand Up @@ -17,7 +17,7 @@ module.exports = (async () => {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
inlineRequires: true,
},
}),
},
Expand Down
4 changes: 4 additions & 0 deletions package.json
Expand Up @@ -80,6 +80,7 @@
"@svgr/webpack": "^4.3.3",
"@types/jest": "^24.0.19",
"@types/react": "^16.9.6",
"@types/react-dom": "^16.9.4",
"@types/react-native": "^0.60.20",
"@types/react-redux": "^7.1.4",
"@types/react-test-renderer": "^16.9.1",
Expand Down Expand Up @@ -152,5 +153,8 @@
"output": "../desktop/dist"
},
"publish": null
},
"react-native": {
"electron": false
}
}
37 changes: 37 additions & 0 deletions src/libs/platform/index.ts
@@ -0,0 +1,37 @@
import {Platform as _Platform} from 'react-native';

function isElectron() {
// Renderer process
if (
typeof window !== 'undefined' &&
typeof window.process === 'object' &&
window.process.type === 'renderer'
) {
return true;
}

// Main process
if (
typeof process !== 'undefined' &&
typeof process.versions === 'object' &&
!!process.versions.electron
) {
return true;
}

// Detect the user agent when the `nodeIntegration` option is set to true
if (
typeof navigator === 'object' &&
typeof navigator.userAgent === 'string' &&
navigator.userAgent.indexOf('Electron') >= 0
) {
return true;
}

return false;
}

export const Platform = {
..._Platform,
isElectron: isElectron(),
};
40 changes: 11 additions & 29 deletions src/screens/ChatUI/Bubble.tsx
Expand Up @@ -35,22 +35,6 @@ class Bubble extends Component<Props> {
this.props.dispatch(goToThread(this.props.messageId, this.props.navigation));
};

openMessageContextMenu = () => {
showMenu(
[
{
title: 'Reply',
onPress: this.goToThread,
},
// {
// title: 'Edit',
// onPress: () => alert('Edit?'),
// },
],
this.refs['bubble'],
);
};

renderMessageText() {
return <MessageText messageId={this.props.messageId} isMe={this.props.isMe} />;
}
Expand Down Expand Up @@ -104,20 +88,18 @@ class Bubble extends Component<Props> {
marginRight: isMe ? px(7.5) : 0,
},
]}>
<TouchableWithoutFeedback onLongPress={this.openMessageContextMenu}>
<View>
<View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
{this.renderName()}
{this.renderSendDate()}
</View>

{this.renderMessageText()}
{this.renderMessageImages()}
{this.renderMessageVideos()}
{this.renderMessageFiles()}
{this.renderReplies()}
<View>
<View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
{this.renderName()}
{this.renderSendDate()}
</View>
</TouchableWithoutFeedback>

{this.renderMessageText()}
{this.renderMessageImages()}
{this.renderMessageVideos()}
{this.renderMessageFiles()}
{this.renderReplies()}
</View>
</View>
);
}
Expand Down
119 changes: 95 additions & 24 deletions src/screens/ChatUI/Message.tsx
@@ -1,22 +1,29 @@
import React, {Component} from 'react';
import {StyleSheet, View} from 'react-native';
import {StyleSheet, View, TouchableWithoutFeedback, Clipboard} from 'react-native';
import ReactDOM from 'react-dom';
import {isSameUser} from './utils';
import {RootState} from '../../reducers';
import Bubble from './Bubble';
import {connect} from 'react-redux';
import {connect, DispatchProp} from 'react-redux';
import Electron from 'electron';

import Avatar from '../../components/Avatar';
import px from '../../utils/normalizePixel';
import withTheme, {ThemeInjectedProps} from '../../contexts/theme/withTheme';
import {NavigationInjectedProps, withNavigation} from 'react-navigation';
import Day from './Day';
import {meSelector} from '../../reducers/teams';
import rem from '../../utils/stylesheet/rem';
import {ChatType} from '.';
import Reactions from './Reactions';
import {goToThread} from '../../actions/chats/thunks';
import showMenu from '../../utils/showMenu';
import isNative from '../../utils/isNative';
import {Platform} from '../../libs/platform';

type Props = ReturnType<typeof mapStateToProps> &
NavigationInjectedProps &
ThemeInjectedProps & {
ThemeInjectedProps &
DispatchProp<any> & {
messageId: string;
prevMessageId: string;
nextMessageId: string;
Expand All @@ -27,6 +34,67 @@ type Props = ReturnType<typeof mapStateToProps> &
};

class Message extends Component<Props> {
messageContainerRef: any;

componentDidMount() {
Platform.isElectron &&
ReactDOM.findDOMNode(this).addEventListener('contextmenu', this.handleContextMenuElectron);
}

componentWillUnmount() {
Platform.isElectron &&
ReactDOM.findDOMNode(this).removeEventListener('contextmenu', this.handleContextMenuElectron);
}

goToReplies = () => {
this.props.dispatch(goToThread(this.props.messageId, this.props.navigation));
};

copyTextToClipboard = () => {
const {currentMessage} = this.props;
if (Platform.isElectron) {
Electron.clipboard.writeText(currentMessage.text);
} else {
Clipboard.setString(currentMessage.text);
}
};

handleContextMenuElectron = e => {
e.preventDefault();

const {Menu, MenuItem} = Electron.remote;

const menu = new Menu();
menu.append(
new MenuItem({
label: 'Reply',
click: this.goToReplies,
}),
);
// menu.append(new MenuItem({type: 'separator'}));
menu.append(new MenuItem({label: 'Copy text'}));

menu.popup({window: Electron.remote.getCurrentWindow()});
return false;
};

openMessageContextNative = () => {
if (!isNative()) return;
showMenu(
[
{
title: 'Reply',
onPress: this.goToReplies,
},
// {
// title: 'Edit',
// onPress: () => alert('Edit?'),
// },
],
this.refs['bubble'],
);
};

handleAvatarPress = (userId: string) => {
this.props.navigation.push('UserProfile', {userId: this.props.currentMessage.user});
};
Expand Down Expand Up @@ -119,26 +187,29 @@ class Message extends Component<Props> {
<>
{!inverted && this.renderDay()}
{inverted && this.renderReaction()}
<View
style={[
styles.container,
isMe ? styles.right : styles.left,
{marginBottom: sameUser ? 4 : 10},
]}>
{!isMe ? (
<>
{this.renderAvatar(isMe, sameUser)}
{this.renderAnchor(isMe, sameUser)}
</>
) : null}
{this.renderBubble(isMe, sameUser)}
{isMe && (
<>
{this.renderAnchor(isMe, sameUser)}
{this.renderAvatar(isMe, sameUser)}
</>
)}
</View>
<TouchableWithoutFeedback onLongPress={this.openMessageContextNative}>
<View
ref={this.messageContainerRef}
style={[
styles.container,
isMe ? styles.right : styles.left,
{marginBottom: sameUser ? 4 : 10},
]}>
{!isMe ? (
<>
{this.renderAvatar(isMe, sameUser)}
{this.renderAnchor(isMe, sameUser)}
</>
) : null}
{this.renderBubble(isMe, sameUser)}
{isMe && (
<>
{this.renderAnchor(isMe, sameUser)}
{this.renderAvatar(isMe, sameUser)}
</>
)}
</View>
</TouchableWithoutFeedback>
{!inverted && this.renderReaction()}
{this.renderDivder()}
{inverted && this.renderDay()}
Expand Down
5 changes: 3 additions & 2 deletions src/screens/Main/index.tsx
@@ -1,5 +1,6 @@
import React, {useState, useRef, useEffect} from 'react';
import {StyleSheet, SafeAreaView, StatusBar, View, Platform} from 'react-native';
import {StyleSheet, StatusBar, View} from 'react-native';

import MediaQuery from '../../utils/stylesheet/MediaQuery';
import Header from '../../components/Header';
import px from '../../utils/normalizePixel';
Expand All @@ -21,7 +22,7 @@ import {currentTeamSelector} from '../../reducers/teams';
import Toast from '../../components/Toast';
import {toggleToast} from '../../actions/app';
import Screen from '../../components/Screen';
import isNative from '../../utils/isNative';
import {Platform} from '../../libs/platform';

type Props = ReturnType<typeof mapStateToProps> & DispatchProp<any> & ThemeInjectedProps;

Expand Down
2 changes: 1 addition & 1 deletion web/webpack.config.js
Expand Up @@ -132,7 +132,7 @@ const config = {
'react-native-fast-image': 'react-native-web/dist/exports/Image',
'react-native-web/dist/exports/Modal': 'modal-enhanced-react-native-web',
},
extensions: ['.web.js', '.js', '.web.ts', '.web.tsx', '.ts', '.tsx', '.json'],
extensions: ['.web.js', '.web.ts', '.js', '.web.tsx', '.ts', '.tsx', '.json'],
},
};

Expand Down

0 comments on commit 7ceb1a7

Please sign in to comment.