commit c46cc161346263ed0d7614f1357438d12a847c0c
parent dc02dd4c05cd6ffac286b11e91ccc0bb8b9124ec
Author: Johan Lindskogen <johan.lindskogen@gmail.com>
Date: Mon, 2 Apr 2018 22:05:29 +0200
Persist connection info
Diffstat:
8 files changed, 76 insertions(+), 25 deletions(-)
diff --git a/package.json b/package.json
@@ -18,6 +18,7 @@
"react-native-parsed-text": "^0.0.20",
"react-redux": "^5.0.7",
"redux": "^3.7.2",
+ "redux-persist": "^5.9.1",
"redux-thunk": "^2.2.0"
},
"devDependencies": {
diff --git a/src/lib/weechat/connection.ts b/src/lib/weechat/connection.ts
@@ -7,6 +7,7 @@ export default class WeechatConnection {
dispatch: any;
hostname: string;
password: string;
+ ssl: boolean;
compressed: boolean;
websocket: WebSocket;
@@ -15,11 +16,20 @@ export default class WeechatConnection {
this.websocket = null;
}
- connect(host, password = "", onSuccess, onError) {
+ connect(
+ host: string,
+ password: string = "",
+ ssl: boolean,
+ onSuccess: (conn: WeechatConnection) => any,
+ onError: (event: Event) => any
+ ) {
this.hostname = host;
this.password = password;
+ this.ssl = ssl;
- this.websocket = new WebSocket(this.hostname);
+ this.websocket = new WebSocket(
+ `${this.ssl ? "wss" : "ws"}://${this.hostname}/weechat`
+ );
this.websocket.onopen = () => this.onopen(onSuccess);
this.websocket.onmessage = event => this.onmessage(event);
@@ -30,7 +40,8 @@ export default class WeechatConnection {
this.dispatch({
type: "SET_CONNECTION_INFO",
hostname: this.hostname,
- password: this.password
+ password: this.password,
+ ssl: this.ssl
});
this.send(
`init password=${this.password},compression=${
diff --git a/src/store/connection-info.ts b/src/store/connection-info.ts
@@ -1,11 +1,13 @@
export type ConnectionInfo = {
hostname: string | null;
password: string | null;
+ ssl: boolean;
};
const initialState: ConnectionInfo = {
hostname: null,
- password: null
+ password: null,
+ ssl: false
};
export default (state: ConnectionInfo = initialState, action) => {
@@ -13,7 +15,8 @@ export default (state: ConnectionInfo = initialState, action) => {
case "SET_CONNECTION_INFO":
return {
hostname: action.hostname,
- password: action.password
+ password: action.password,
+ ssl: action.ssl
};
case "CLEAR_CONNECTION_INFO":
return initialState;
diff --git a/src/store/index.ts b/src/store/index.ts
@@ -1,9 +1,12 @@
import { compose, combineReducers, createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
+import { persistStore, persistReducer } from "redux-persist";
+import storage from "redux-persist/lib/storage";
import buffers, { BufferState } from "./buffers";
import lines, { LineState } from "./lines";
import hotlists, { HotListState } from "./hotlists";
+import connection, { ConnectionInfo } from "./connection-info";
type AppState = {
connected: boolean;
@@ -12,6 +15,7 @@ type AppState = {
export type StoreState = {
app: AppState;
+ connection: ConnectionInfo;
buffers: BufferState;
lines: LineState;
hotlists: HotListState;
@@ -43,10 +47,16 @@ const reducer = combineReducers({
app,
buffers,
lines,
+ connection,
hotlists
});
const composeEnhancers =
(<any>window).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
-export default createStore(reducer, composeEnhancers(applyMiddleware(thunk)));
+export const store = createStore(
+ persistReducer({ storage, key: "state", whitelist: ["connection"] }, reducer),
+ composeEnhancers(applyMiddleware(thunk))
+);
+
+export const persistor = persistStore(store);
diff --git a/src/usecase/ConnectionGate.tsx b/src/usecase/ConnectionGate.tsx
@@ -1,11 +1,12 @@
import * as React from "react";
import { connect } from "react-redux";
import LoginForm from "./login/LoginForm";
+import { StoreState } from "../store";
interface Props {
connecting: boolean;
connected: boolean;
- onConnect: (hostname: string, password: string) => void;
+ onConnect: (hostname: string, password: string, ssl: boolean) => void;
}
class ConnectionGate extends React.Component<Props> {
@@ -19,6 +20,6 @@ class ConnectionGate extends React.Component<Props> {
}
}
-export default connect(state => ({
+export default connect((state: StoreState) => ({
connected: state.app.connected
}))(ConnectionGate);
diff --git a/src/usecase/Root.tsx b/src/usecase/Root.tsx
@@ -1,9 +1,10 @@
import * as React from "react";
import { StatusBar } from "react-native";
import { Provider } from "react-redux";
+import { PersistGate } from "redux-persist/integration/react";
import WeechatConnection from "../lib/weechat/connection";
-import store from "../store";
+import { store, persistor } from "../store";
import App from "./App";
import ConnectionGate from "./ConnectionGate";
@@ -39,12 +40,12 @@ export default class WeechatNative extends React.Component<{}, State> {
console.log(error);
};
- onConnect = (hostname: string, password: string) => {
- console.log(hostname, password);
+ onConnect = (hostname: string, password: string, ssl: boolean) => {
this.setState({ connecting: true });
this.connection.connect(
hostname,
password,
+ ssl,
this.onConnectionSuccess,
this.onConnectionError
);
@@ -72,14 +73,16 @@ export default class WeechatNative extends React.Component<{}, State> {
return (
<Provider store={store}>
- <ConnectionGate connecting={connecting} onConnect={this.onConnect}>
- <StatusBar barStyle="light-content" />
- <App
- clearHotlistForBuffer={this.clearHotlistForBuffer}
- sendMessageToBuffer={this.sendMessageToBuffer}
- fetchLinesForBuffer={this.fetchLines}
- />
- </ConnectionGate>
+ <PersistGate loading={null} persistor={persistor}>
+ <ConnectionGate connecting={connecting} onConnect={this.onConnect}>
+ <StatusBar barStyle="light-content" />
+ <App
+ clearHotlistForBuffer={this.clearHotlistForBuffer}
+ sendMessageToBuffer={this.sendMessageToBuffer}
+ fetchLinesForBuffer={this.fetchLines}
+ />
+ </ConnectionGate>
+ </PersistGate>
</Provider>
);
}
diff --git a/src/usecase/login/LoginForm.tsx b/src/usecase/login/LoginForm.tsx
@@ -10,10 +10,14 @@ import {
TouchableOpacity
} from "react-native";
import { connect } from "react-redux";
+import { StoreState } from "../../store";
interface Props {
- onConnect: (hostname: string, password: string) => void;
+ onConnect: (hostname: string, password: string, ssl: boolean) => void;
connecting: boolean;
+ hostname: string;
+ password: string;
+ ssl: boolean;
}
interface State {
hostname: string;
@@ -21,21 +25,30 @@ interface State {
ssl: boolean;
}
-export default class LoginForm extends React.Component<Props, State> {
+class LoginForm extends React.Component<Props, State> {
state: State = {
hostname: "",
password: "",
ssl: true
};
+ static getDerivedStateFromProps(nextProps: Props, prevState: State) {
+ if (!prevState.hostname && !prevState.password) {
+ return {
+ ...prevState,
+ hostname: nextProps.hostname,
+ password: nextProps.password
+ };
+ } else {
+ return null;
+ }
+ }
+
onPress = () => {
const { hostname, password, ssl } = this.state;
- this.props.onConnect(this.getFullWebsocketUrl(hostname, ssl), password);
+ this.props.onConnect(hostname, password, ssl);
};
- getFullWebsocketUrl = (hostname: string, ssl: boolean) =>
- `${ssl ? "wss" : "ws"}://${hostname}/weechat`;
-
setHostname = (hostname: string) => {
this.setState({ hostname });
};
@@ -101,6 +114,11 @@ export default class LoginForm extends React.Component<Props, State> {
}
}
+export default connect((state: StoreState) => ({
+ hostname: state.connection.hostname,
+ password: state.connection.password
+}))(LoginForm);
+
const styles = StyleSheet.create({
container: {
backgroundColor: "#f8f8f8",
diff --git a/yarn.lock b/yarn.lock
@@ -4485,6 +4485,10 @@ realpath-native@^1.0.0:
dependencies:
util.promisify "^1.0.0"
+redux-persist@^5.9.1:
+ version "5.9.1"
+ resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-5.9.1.tgz#83bd4abd526ef768f63fceee338fa9d8ed6552d6"
+
redux-thunk@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5"