Skip to content
This repository was archived by the owner on Oct 11, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions flow-typed/npm/@expo/react-native-action-sheet_vx.x.x.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// flow-typed signature: e49a967b35c065ea303b9bb16e18af7b
// flow-typed version: <<STUB>>/@expo/react-native-action-sheet_v1.0.2/flow_v0.66.0

/**
* This is an autogenerated libdef stub for:
*
* '@expo/react-native-action-sheet'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/

declare module '@expo/react-native-action-sheet' {
declare module.exports: any;
}

/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module '@expo/react-native-action-sheet/ActionSheet.android' {
declare module.exports: any;
}

declare module '@expo/react-native-action-sheet/ActionSheet.ios' {
declare module.exports: any;
}

declare module '@expo/react-native-action-sheet/ActionSheetProvider' {
declare module.exports: any;
}

declare module '@expo/react-native-action-sheet/connectActionSheet' {
declare module.exports: any;
}

// Filename aliases
declare module '@expo/react-native-action-sheet/ActionSheet.android.js' {
declare module.exports: $Exports<'@expo/react-native-action-sheet/ActionSheet.android'>;
}
declare module '@expo/react-native-action-sheet/ActionSheet.ios.js' {
declare module.exports: $Exports<'@expo/react-native-action-sheet/ActionSheet.ios'>;
}
declare module '@expo/react-native-action-sheet/ActionSheetProvider.js' {
declare module.exports: $Exports<'@expo/react-native-action-sheet/ActionSheetProvider'>;
}
declare module '@expo/react-native-action-sheet/connectActionSheet.js' {
declare module.exports: $Exports<'@expo/react-native-action-sheet/connectActionSheet'>;
}
declare module '@expo/react-native-action-sheet/index' {
declare module.exports: $Exports<'@expo/react-native-action-sheet'>;
}
declare module '@expo/react-native-action-sheet/index.js' {
declare module.exports: $Exports<'@expo/react-native-action-sheet'>;
}
2 changes: 1 addition & 1 deletion mobile/.expo/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"lanType": "ip",
"dev": true,
"minify": false,
"urlRandomness": "66-qcw"
"urlRandomness": "2s-bjc"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have notes around why this needs to be this specific thing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's automatically generated by Expo

}
5 changes: 4 additions & 1 deletion mobile/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { createStore } from 'redux';
import { Provider } from 'react-redux';
import { ApolloProvider } from 'react-apollo';
import { ThemeProvider } from 'styled-components';
import { ActionSheetProvider } from '@expo/react-native-action-sheet';
import { type ApolloClient } from 'apollo-client';

import theme from './components/theme';
Expand Down Expand Up @@ -84,7 +85,9 @@ class App extends React.Component<{}, State> {
<Provider store={store}>
<ApolloProvider client={client}>
<ThemeProvider theme={theme}>
{!token ? <Login /> : <TabBar />}
<ActionSheetProvider>
{!token ? <Login /> : <TabBar />}
</ActionSheetProvider>
</ThemeProvider>
</ApolloProvider>
</Provider>
Expand Down
73 changes: 36 additions & 37 deletions mobile/components/ChatInput/index.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,47 @@
// @flow
import React from 'react';
import { TextInput, View, Button } from 'react-native';
import KeyboardSpacer from 'react-native-keyboard-spacer';
import compose from 'recompose/compose';
import { connect } from 'react-redux';
import { withNavigation } from 'react-navigation';
import { replyToMessage } from '../../../src/actions/message';
import Input, { type InputProps } from './input';
import { QuotedMessage } from '../Message/QuotedMessage';
import { getMessageById } from '../../../shared/graphql/queries/message/getMessage';
import type { Node } from 'react';

type Props = {
onSubmit: (text: string) => void,
// Don't let people pass in their own children, this container takes care of that
...$Diff<InputProps, { children: Node }>,
dispatch: Function,
quotedMessage?: string,
};

type State = {
value: string,
};

class ChatInput extends React.Component<Props, State> {
state = {
value: '',
};
const QuotedMessageById = getMessageById(props => {
if (props.data.loading || !props.data.message) return null;
return <QuotedMessage noPadding message={props.data.message} />;
});

onChangeText = (value: string) => {
this.setState({ value });
// Get the quoted message ID for the current thread
// by combining the navigation state + the redux state
const mapStateToProps = (state, ownProps): * => {
const { state: navigationState } = ownProps.navigation;
const threadId =
navigationState.routeName === 'Thread' ? navigationState.params.id : null;
return {
quotedMessage: threadId ? state.message.quotedMessage[threadId] : null,
};
};

submit = () => {
this.props.onSubmit(this.state.value);
this.onChangeText('');
};
const ChatInputContainer = (props: Props) => {
const { quotedMessage, dispatch, ...inputProps } = props;

render() {
return (
<View>
<TextInput
value={this.state.value}
onChangeText={this.onChangeText}
placeholder="Your message here..."
multiline
autoFocus={false}
disableFullscreenUI
onSubmitEditing={this.submit}
/>
<Button onPress={this.submit} title="Send" />
{/* NOTE(@mxstbr): Magic number, otherwise the chatinput is way above the keyboard */}
<KeyboardSpacer topSpacing={-75} />
</View>
);
}
}
return (
<Input {...inputProps}>
{quotedMessage ? <QuotedMessageById id={quotedMessage} /> : null}
</Input>
);
};

export default ChatInput;
export default compose(withNavigation, connect(mapStateToProps))(
ChatInputContainer
);
61 changes: 61 additions & 0 deletions mobile/components/ChatInput/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// @flow
import React from 'react';
import { TextInput, View, Button } from 'react-native';
import KeyboardSpacer from 'react-native-keyboard-spacer';
import {
ChatInputWrapper,
ChatInputTextInputWrapper,
SendButton,
} from './style';

import type { Node } from 'react';

export type InputProps = {
onSubmit: (text: string) => void,
children?: Node,
};

type State = {
value: string,
};

class ChatInput extends React.Component<InputProps, State> {
state = {
value: '',
};

onChangeText = (value: string) => {
this.setState({ value });
};

submit = () => {
this.props.onSubmit(this.state.value);
this.onChangeText('');
};

render() {
return (
<View style={{ width: '100%' }}>
<ChatInputWrapper>
<ChatInputTextInputWrapper>
{this.props.children}
<TextInput
value={this.state.value}
onChangeText={this.onChangeText}
placeholder="Your message here..."
multiline
autoFocus={false}
disableFullscreenUI
onSubmitEditing={this.submit}
/>
</ChatInputTextInputWrapper>
<SendButton onPress={this.submit} size={32} />
</ChatInputWrapper>
{/* NOTE(@mxstbr): Magic number, otherwise the chatinput is way above the keyboard */}
<KeyboardSpacer topSpacing={-75} />
</View>
);
}
}

export default ChatInput;
53 changes: 53 additions & 0 deletions mobile/components/ChatInput/style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// @flow
import { TouchableOpacity } from 'react-native';
import { Svg } from 'expo';
import React from 'react';
import styled, { withTheme } from 'styled-components/native';

const { Path, G } = Svg;

export const ChatInputWrapper = styled.View`
flex-direction: row;
align-items: center;
width: 100%;
margin: 0px;
padding: 8px 4px;
background-color: ${props => props.theme.bg.default};
border-top-width: 1px;
border-top-color: ${({ theme }) => theme.bg.border};
`;

export const ChatInputTextInputWrapper = styled.View`
flex: 1;
flex-direction: column;
min-height: 40px;
padding: ${props => (props.hasAttachment ? '16px' : '8px 16px')};
border-radius: 24px;
border-width: 1px;
border-color: ${props => props.theme.bg.border};
background: ${props => props.theme.bg.default};
`;

type SendButtonProps = {
onPress: Function,
size?: number,
theme: Object,
};

export const SendButton = withTheme(
({ onPress, size, theme }: SendButtonProps) => {
const actualSize = size ? size : 64;
return (
<TouchableOpacity onPress={onPress}>
<Svg width={actualSize} height={actualSize} viewBox={`0 0 32 32`}>
<G>
<Path
fill={theme.text.alt}
d="M9,8l0,5.287l7.054,1.495c0.628,0.133 0.966,0.665 0.989,1.164c0,0.009 0.001,0.022 0.001,0.034c0,0.004 0,0.008 0,0.012c0,0.005 0,0.009 0,0.013c0,0.012 -0.001,0.025 -0.001,0.034c-0.023,0.498 -0.361,1.031 -0.989,1.164l-7.054,1.495l0,5.627c0.02,0.001 0.049,-0.002 0.09,-0.017c4.386,-1.524 15.41,-7.808 15.41,-8.308c0,-0.5 -11.075,-6.473 -15.41,-7.984c-0.041,-0.014 -0.07,-0.017 -0.09,-0.016Zm17.555,7.992l0,-0.011l0,-0.003c-0.011,-0.698 -0.39,-1.289 -0.925,-1.685c-3.631,-2.688 -11.512,-6.642 -15.882,-8.165c-0.624,-0.218 -1.3,-0.158 -1.843,0.185c-0.554,0.349 -0.905,0.958 -0.905,1.667l0,5.712c0,0.708 0.496,1.32 1.189,1.467l3.931,0.833l-3.931,0.834c-0.693,0.146 -1.189,0.758 -1.189,1.467l0,6.052c0,0.709 0.351,1.317 0.905,1.667c0.543,0.343 1.219,0.403 1.843,0.185c4.371,-1.527 12.29,-5.85 15.881,-8.505c0.536,-0.397 0.915,-0.987 0.925,-1.685l0,-0.003l0.001,-0.012Z"
/>
</G>
</Svg>
</TouchableOpacity>
);
}
);
63 changes: 63 additions & 0 deletions mobile/components/Message/QuotedMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// @flow
import React from 'react';
import { TouchableOpacity } from 'react-native';
import Message from './';
import Author from '../Messages/Author';
import { QuoteWrapper, QuotedParagraph, QuoteGradient } from './style';

import { isShort } from '../../../shared/clients/draft-js/utils/isShort';
import type { MessageInfoType } from '../../../shared/graphql/fragments/message/messageInfo';

type QuotedMessageProps = {
message: MessageInfoType,
noPadding?: boolean,
};

type QuotedMessageState = {
isShort: boolean,
isExpanded: boolean,
};

export class QuotedMessage extends React.Component<
QuotedMessageProps,
QuotedMessageState
> {
constructor(props: QuotedMessageProps) {
super(props);

const short = isShort(props.message);
this.state = {
isShort: short,
isExpanded: short,
};
}

shouldComponentUpdate(
nextProps: QuotedMessageProps,
nextState: QuotedMessageState
) {
return nextState.isExpanded !== this.state.isExpanded;
}

toggle = () => {
if (this.state.isShort) return;
this.setState(prev => ({ isExpanded: !prev.isExpanded }));
};

render() {
const { message, noPadding = false } = this.props;
const { isExpanded, isShort } = this.state;
// TODO(@mxstbr): Use <ConditionalWrap> to only add TouchableOpacity to long messages
return (
<TouchableOpacity onPress={this.toggle}>
<QuoteWrapper noPadding={noPadding} expanded={isExpanded}>
<Author me={false} avatar={false} author={message.author} />
<QuotedParagraph>
<Message bubble={false} message={message} me={false} />
</QuotedParagraph>
{!isExpanded && <QuoteGradient />}
</QuoteWrapper>
</TouchableOpacity>
);
}
}
Loading