weechatRN

Weechat relay client for iOS using websockets https://github.com/mhoran/weechatRN
git clone http://git.hanabi.in/repos/weechatRN.git
Log | Files | Refs | README | LICENSE

commit ace3b98470a50bd71bfd8051099997080932bf60
parent aecd0484341b987d8cfea3246aa348792ee239c3
Author: Johan Lindskogen <johan.lindskogen@gmail.com>
Date:   Fri, 30 Mar 2018 18:59:41 +0200

Fetch lines for bufferId

Diffstat:
Mindex.js | 13++++++++++---
Msrc/lib/weechat/action_transformer.ts | 12++++++++++--
Msrc/lib/weechat/types.ts | 17+++++++++++++++++
Msrc/store/index.js | 4+++-
Asrc/store/lines.ts | 15+++++++++++++++
Msrc/usecase/App.tsx | 27++++++++++++++++++++-------
Dsrc/usecase/buffers/ui/Buffer.js | 87-------------------------------------------------------------------------------
Asrc/usecase/buffers/ui/Buffer.tsx | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/usecase/buffers/ui/BufferLine.js | 14--------------
Asrc/usecase/buffers/ui/BufferLine.tsx | 20++++++++++++++++++++
Msrc/usecase/buffers/ui/BufferList.tsx | 2+-
Msrc/usecase/buffers/ui/BufferView.js | 26++++++++++++--------------
Dsrc/usecase/buffers/ui/themes/Default.js | 97-------------------------------------------------------------------------------
Asrc/usecase/buffers/ui/themes/Default.tsx | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
14 files changed, 307 insertions(+), 226 deletions(-)

diff --git a/index.js b/index.js @@ -10,10 +10,11 @@ import store from "./src/store"; import App from "./src/usecase/App"; import ConnectionGate from "./src/usecase/ConnectionGate"; +const connection = new WeechatConnection(store.dispatch, HOSTNAME, PASSWORD); + class WeechatNative extends React.Component { componentWillMount() { - let connection = new WeechatConnection(store.dispatch, HOSTNAME, PASSWORD); - let compressed = false; + const compressed = false; connection.connect().then( conn => { @@ -33,11 +34,17 @@ class WeechatNative extends React.Component { } ); } + fetchLines = (bufferId, numLines = 50) => { + connection && + connection.send( + `(lines) hdata buffer:0x${bufferId}/own_lines/last_line(-${numLines})/data` + ); + }; render() { return ( <Provider store={store}> <ConnectionGate> - <App /> + <App fetchLinesForBuffer={this.fetchLines} /> </ConnectionGate> </Provider> ); diff --git a/src/lib/weechat/action_transformer.ts b/src/lib/weechat/action_transformer.ts @@ -18,8 +18,8 @@ export const transformToReduxAction = (data: WeechatResponse<any>) => { return { type: "FETCH_BUFFERS", payload: reduceToObjectByKey( - object.content, - buffer => buffer.pointers[0] + object.content.map(o => ({ ...o, id: o.pointers[0] })), + buffer => buffer.id ) }; } @@ -31,6 +31,14 @@ export const transformToReduxAction = (data: WeechatResponse<any>) => { payload: infolist.content.value }; } + case "lines": { + const object = data.objects[0] as WeechatObject<WeechatLine[]>; + return { + type: "FETCH_LINES", + bufferId: object.content[0].buffer, + payload: object.content + }; + } } } }; diff --git a/src/lib/weechat/types.ts b/src/lib/weechat/types.ts @@ -49,3 +49,20 @@ interface Header { length: number; compression: number; } + +interface WeechatLine { + pointers: string[]; + prefix_length: number; + prefix: string; + displayed: number; + message: string; + refresh_needed: number; + str_time: string; + date: string; + tags_count: number; + date_printed: string; + tags_array: string[]; + buffer: string; + highlight: number; + y: number; +} diff --git a/src/store/index.js b/src/store/index.js @@ -1,6 +1,7 @@ import { combineReducers, createStore, applyMiddleware } from "redux"; import buffers from "./buffers"; +import lines from "./lines"; const app = (state = { connected: false }, action) => { switch (action.type) { @@ -15,7 +16,8 @@ const app = (state = { connected: false }, action) => { const reducer = combineReducers({ app, - buffers + buffers, + lines }); export default createStore( diff --git a/src/store/lines.ts b/src/store/lines.ts @@ -0,0 +1,15 @@ +type LinesState = { [key: string]: WeechatLine }; + +const initialState: LinesState = {}; + +export default (state: LinesState = initialState, action): LinesState => { + switch (action.type) { + case "FETCH_LINES": + return { + ...state, + [action.bufferId]: action.payload + }; + default: + return state; + } +}; diff --git a/src/usecase/App.tsx b/src/usecase/App.tsx @@ -13,28 +13,41 @@ import BufferList from "./buffers/ui/BufferList"; interface Props { buffers: WeechatBuffer[]; currentBufferName: string; + fetchLinesForBuffer: (string) => void; } -class App extends React.Component<Props> { +interface State { + currentBufferId: string | null; +} + +class App extends React.Component<Props, State> { drawer: Drawer; - changeCurrentBuffer(bufferName) { + state: State = { currentBufferId: null }; + + changeCurrentBuffer = buffer => { // this.props.dispatch(changeCurrentBuffer(bufferName)); this.drawer.close(); - } + this.props.fetchLinesForBuffer(buffer.id); + console.log(buffer, buffer.id); + this.setState({ + currentBufferId: buffer.id + }); + }; render() { + const { currentBufferId } = this.state; const { buffers, currentBufferName } = this.props; - console.log(buffers); - const sidebar = ( <BufferList buffers={_.orderBy(buffers, ["number"])} currentBufferName={currentBufferName} - onSelectBuffer={b => this.changeCurrentBuffer(b.short_name)} + onSelectBuffer={this.changeCurrentBuffer} /> ); + console.log({ currentBufferId }); + return ( <View style={styles.container}> <Drawer @@ -61,7 +74,7 @@ class App extends React.Component<Props> { </View> <View style={styles.channels} /> </View> - <BufferView bufferName={currentBufferName} /> + <BufferView bufferId={currentBufferId} /> </Drawer> </View> ); diff --git a/src/usecase/buffers/ui/Buffer.js b/src/usecase/buffers/ui/Buffer.js @@ -1,87 +0,0 @@ -import React from "react"; -import { StyleSheet, Animated, Keyboard, ListView, View } from "react-native"; -import { connect } from "react-redux"; - -import AppleEasing from "react-apple-easing"; - -import BufferLine from "./BufferLine"; - -//const easingFunction = Easing.bezier(0.55, 0.085, 0.68, 0.53); -const easingFunction = AppleEasing.easeIn; - -class Buffer extends React.Component { - state = { - keyboardOffset: new Animated.Value(0) - }; - - componentDidMount() { - this.cancelKeyboardWillShow = Keyboard.addListener("keyboardWillShow", e => - this._keyboardWillShow(e) - ); - this.cancelKeyboardWillHide = Keyboard.addListener("keyboardWillHide", e => - this._keyboardWillHide(e) - ); - } - _keyboardWillShow(e) { - console.log(e); - Animated.timing(this.state.keyboardOffset, { - toValue: e.endCoordinates.height, - duration: e.duration, - easing: easingFunction - }).start(); - } - _keyboardWillHide(e) { - Animated.timing(this.state.keyboardOffset, { - toValue: 0, - duration: e.duration, - easing: easingFunction - }).start(); - } - render() { - const { dataSource, onLongPress, parseArgs } = this.props; - return ( - <ListView - style={styles.main} - dataSource={dataSource} - keyboardDismissMode="interactive" - renderRow={line => ( - <BufferLine - line={line} - onLongPress={onLongPress} - parseArgs={parseArgs} - /> - )} - /> - ); - } -} - -export default connect((state, { buffer }) => { - const dataSource = new ListView.DataSource({ - rowHasChanged: (r1, r2) => r1 !== r2 - }); - - return { - dataSource: dataSource.cloneWithRows(buffer.lines) - }; -})(Buffer); - -const styles = StyleSheet.create({ - topbar: { - height: 20, - backgroundColor: "#001" - }, - bottomBox: { - height: 40, - paddingHorizontal: 10, - justifyContent: "center", - backgroundColor: "#aaa" - }, - inputBox: { - height: 25, - paddingHorizontal: 5, - justifyContent: "center", - borderColor: "gray", - backgroundColor: "#fff" - } -}); diff --git a/src/usecase/buffers/ui/Buffer.tsx b/src/usecase/buffers/ui/Buffer.tsx @@ -0,0 +1,96 @@ +import React from "react"; +import { + StyleSheet, + Animated, + Keyboard, + FlatList, + View, + EmitterSubscription +} from "react-native"; +import { connect } from "react-redux"; + +import AppleEasing from "react-apple-easing"; + +import BufferLine from "./BufferLine"; + +//const easingFunction = Easing.bezier(0.55, 0.085, 0.68, 0.53); +const easingFunction = AppleEasing.easeIn; + +interface Props { + lines: WeechatLine[]; + onLongPress: () => any; + parseArgs: any; +} + +class Buffer extends React.Component<Props> { + cancelKeyboardWillShow: EmitterSubscription; + cancelKeyboardWillHide: EmitterSubscription; + + state = { + keyboardOffset: new Animated.Value(0) + }; + + componentDidMount() { + this.cancelKeyboardWillShow = Keyboard.addListener("keyboardWillShow", e => + this._keyboardWillShow(e) + ); + this.cancelKeyboardWillHide = Keyboard.addListener("keyboardWillHide", e => + this._keyboardWillHide(e) + ); + } + _keyboardWillShow(e) { + console.log(e); + Animated.timing(this.state.keyboardOffset, { + toValue: e.endCoordinates.height, + duration: e.duration, + easing: easingFunction + }).start(); + } + _keyboardWillHide(e) { + Animated.timing(this.state.keyboardOffset, { + toValue: 0, + duration: e.duration, + easing: easingFunction + }).start(); + } + render() { + const { lines, onLongPress, parseArgs } = this.props; + return ( + <FlatList + data={lines} + keyboardDismissMode="interactive" + renderItem={({ item }) => ( + <BufferLine + line={item} + onLongPress={onLongPress} + parseArgs={parseArgs} + /> + )} + /> + ); + } +} + +export default connect((state, { bufferId }) => ({ + lines: state.lines[bufferId] || [] +}))(Buffer); + +const styles = StyleSheet.create({ + topbar: { + height: 20, + backgroundColor: "#001" + }, + bottomBox: { + height: 40, + paddingHorizontal: 10, + justifyContent: "center", + backgroundColor: "#aaa" + }, + inputBox: { + height: 25, + paddingHorizontal: 5, + justifyContent: "center", + borderColor: "gray", + backgroundColor: "#fff" + } +}); diff --git a/src/usecase/buffers/ui/BufferLine.js b/src/usecase/buffers/ui/BufferLine.js @@ -1,14 +0,0 @@ -import React from "react"; - -import Default from "./themes/Default"; -import Messenger from "./themes/Messenger"; - -export default class BufferLine extends React.Component { - render() { - const { line, onLongPress, parseArgs } = this.props; - - return ( - <Default line={line} onLongPress={onLongPress} parseArgs={parseArgs} /> - ); - } -} diff --git a/src/usecase/buffers/ui/BufferLine.tsx b/src/usecase/buffers/ui/BufferLine.tsx @@ -0,0 +1,20 @@ +import React from "react"; + +import Default from "./themes/Default"; +import Messenger from "./themes/Messenger"; + +interface Props { + line: WeechatLine; + onLongPress: (any) => any; + parseArgs: any; +} + +export default class BufferLine extends React.Component<Props> { + render() { + const { line, onLongPress, parseArgs } = this.props; + + return ( + <Default line={line} onLongPress={onLongPress} parseArgs={parseArgs} /> + ); + } +} diff --git a/src/usecase/buffers/ui/BufferList.tsx b/src/usecase/buffers/ui/BufferList.tsx @@ -61,7 +61,7 @@ export default class BufferList extends React.Component<Props> { <FlatList style={styles.container} data={buffers} - keyExtractor={buffer => buffer.pointers[0]} + keyExtractor={buffer => buffer.id} renderItem={({ item }) => ( <BufferListItem buffer={item} diff --git a/src/usecase/buffers/ui/BufferView.js b/src/usecase/buffers/ui/BufferView.js @@ -66,7 +66,7 @@ const formatUrl = (type, text) => { const easingFunction = Easing.bezier(0.55, 0.085, 0.68, 0.53); //const easingFunction = AppleEasing.easeIn; -class BufferView extends React.Component { +export default class BufferView extends React.Component { state = { keyboardOffset: new Animated.Value(0), inputWidth: new Animated.Value(350) @@ -119,17 +119,19 @@ class BufferView extends React.Component { ); } handleOnPress(type, text) { - console.log(type, text); - if (type === "channel") { - this.props.dispatch(changeCurrentBuffer(text)); - } else { - LinkingIOS.openURL(formatUrl(type, text)); - } + // console.log(type, text); + // if (type === "channel") { + // this.props.dispatch(changeCurrentBuffer(text)); + // } else { + // LinkingIOS.openURL(formatUrl(type, text)); + // } } render() { - const { buffer } = this.props; + const { bufferId } = this.props; + + console.log({ bufferId }); - if (!buffer) { + if (!bufferId) { return <View style={styles.container} />; } @@ -138,7 +140,7 @@ class BufferView extends React.Component { style={[styles.container, { marginBottom: this.state.keyboardOffset }]} > <Buffer - buffer={buffer} + bufferId={bufferId} onLongPress={line => null} parseArgs={getParseArgs(this.handleOnPress, this.handleOnLongPress)} /> @@ -156,10 +158,6 @@ class BufferView extends React.Component { } } -export default connect((state, props) => ({ - buffer: state.buffers[props.bufferName] -}))(BufferView); - const light = false; const styles = StyleSheet.create({ diff --git a/src/usecase/buffers/ui/themes/Default.js b/src/usecase/buffers/ui/themes/Default.js @@ -1,97 +0,0 @@ -import React from "react"; -import { StyleSheet, Text, TouchableHighlight, View } from "react-native"; - -import ParsedText from "react-native-parsed-text"; - -import { hashNickToColor } from "../../../../lib/helpers/colorizer"; - -const highlightedViewStyles = line => { - if (line.highlight) { - return { - backgroundColor: "#FFCF7F" - }; - } else { - return null; - } -}; - -const getHighlightedTextStyles = line => { - if (line.highlight) { - return { - color: "#000" - }; - } else { - return null; - } -}; - -export default class BufferLine extends React.Component { - render() { - const { line, onLongPress, parseArgs } = this.props; - return ( - <TouchableHighlight onLongPress={() => onLongPress(line)}> - <View style={[styles.container, highlightedViewStyles(line)]}> - <View style={styles.metaContainer}> - <View style={styles.userContainer}> - <Text - style={[ - styles.text, - styles.meta, - { color: hashNickToColor(line.nick) }, - getHighlightedTextStyles(line) - ]} - > - {line.nick} - </Text> - </View> - <Text - style={[styles.text, styles.meta, getHighlightedTextStyles(line)]} - > - {line.time} - </Text> - </View> - <View style={[styles.messageContainer, highlightedViewStyles(line)]}> - <ParsedText - style={[ - styles.text, - { color: hashNickToColor(line.nick) }, - getHighlightedTextStyles(line) - ]} - parse={parseArgs} - > - {line.message} - </ParsedText> - </View> - </View> - </TouchableHighlight> - ); - } -} - -const styles = StyleSheet.create({ - container: { - backgroundColor: "#222", - paddingTop: 4, - paddingBottom: 8, - paddingHorizontal: 7 - }, - metaContainer: { - flexDirection: "row", - paddingBottom: 2 - }, - userContainer: { - flex: 1 - }, - messageContainer: { - flex: 1, - paddingHorizontal: 5 - }, - text: { - fontFamily: "Menlo", - color: "#eee", - fontSize: 12 - }, - meta: { - fontSize: 10 - } -}); diff --git a/src/usecase/buffers/ui/themes/Default.tsx b/src/usecase/buffers/ui/themes/Default.tsx @@ -0,0 +1,103 @@ +import React from "react"; +import { StyleSheet, Text, TouchableHighlight, View } from "react-native"; + +import ParsedText from "react-native-parsed-text"; + +import { hashNickToColor } from "../../../../lib/helpers/colorizer"; + +const highlightedViewStyles = line => { + if (line.highlight) { + return { + backgroundColor: "#FFCF7F" + }; + } else { + return null; + } +}; + +const getHighlightedTextStyles = line => { + if (line.highlight) { + return { + color: "#000" + }; + } else { + return null; + } +}; + +interface Props { + line: WeechatLine; + onLongPress: (any) => any; + parseArgs: any; +} + +export default class BufferLine extends React.Component<Props> { + render() { + const { line, onLongPress, parseArgs } = this.props; + return ( + <TouchableHighlight onLongPress={() => onLongPress(line)}> + <View style={[styles.container, highlightedViewStyles(line)]}> + <View style={styles.metaContainer}> + <View style={styles.userContainer}> + <Text + style={[ + styles.text, + styles.meta, + { color: hashNickToColor(line.prefix) }, + getHighlightedTextStyles(line) + ]} + > + {line.prefix} + </Text> + </View> + <Text + style={[styles.text, styles.meta, getHighlightedTextStyles(line)]} + > + {String(line.date_printed)} + </Text> + </View> + <View style={[styles.messageContainer, highlightedViewStyles(line)]}> + <ParsedText + style={[ + styles.text, + { color: hashNickToColor(line.prefix) }, + getHighlightedTextStyles(line) + ]} + parse={parseArgs} + > + {line.message} + </ParsedText> + </View> + </View> + </TouchableHighlight> + ); + } +} + +const styles = StyleSheet.create({ + container: { + backgroundColor: "#222", + paddingTop: 4, + paddingBottom: 8, + paddingHorizontal: 7 + }, + metaContainer: { + flexDirection: "row", + paddingBottom: 2 + }, + userContainer: { + flex: 1 + }, + messageContainer: { + flex: 1, + paddingHorizontal: 5 + }, + text: { + fontFamily: "Menlo", + color: "#eee", + fontSize: 12 + }, + meta: { + fontSize: 10 + } +});