diff --git a/background.html b/background.html
index dc6aa0f53..4a26917c6 100644
--- a/background.html
+++ b/background.html
@@ -78,23 +78,6 @@
-
-
-
diff --git a/background_test.html b/background_test.html
index c104bedee..5bf9defd6 100644
--- a/background_test.html
+++ b/background_test.html
@@ -76,22 +76,6 @@
{{ #summary }}
{{ summary }}
{{ /summary }}
-
-
diff --git a/js/background.js b/js/background.js
index 147ed7155..24acc0536 100644
--- a/js/background.js
+++ b/js/background.js
@@ -589,12 +589,6 @@
Whisper.events.on('showDebugLog', () => {
appView.openDebugLog();
});
- Whisper.events.on('unauthorized', () => {
- appView.inboxView.networkStatusView.update();
- });
- Whisper.events.on('reconnectTimer', () => {
- appView.inboxView.networkStatusView.setSocketReconnectInterval(60000);
- });
window.addEventListener('focus', () => Whisper.Notifications.clear());
window.addEventListener('unload', () => Whisper.Notifications.fastClear());
diff --git a/js/conversation_controller.js b/js/conversation_controller.js
index 78c7978d3..4141d7894 100644
--- a/js/conversation_controller.js
+++ b/js/conversation_controller.js
@@ -25,9 +25,6 @@
return messages;
};
- window.getConversationByName = name =>
- conversations.find(d => d.get('name') === name);
-
window.ConversationController = {
get(id) {
if (!this._initialFetchComplete) {
diff --git a/js/views/inbox_view.js b/js/views/inbox_view.js
index 30afb774f..825f7f7ae 100644
--- a/js/views/inbox_view.js
+++ b/js/views/inbox_view.js
@@ -21,28 +21,7 @@
this.ready = false;
this.render();
this.$el.attr('tabindex', '1');
-
- if (!options.initialLoadComplete) {
- this.appLoadingScreen = new Whisper.AppLoadingScreen();
- this.appLoadingScreen.render();
- this.appLoadingScreen.$el.prependTo(this.el);
- this.startConnectionListener();
- }
-
- // Inbox
- const inboxCollection = getInboxCollection();
-
// ConversationCollection
- this.listenTo(inboxCollection, 'messageError', () => {
- if (this.networkStatusView) {
- this.networkStatusView.render();
- }
- });
-
- this.networkStatusView = new Whisper.NetworkStatusView();
- this.$el
- .find('.network-status-container')
- .append(this.networkStatusView.render().el);
extension.expired(expired => {
if (expired) {
diff --git a/js/views/network_status_view.js b/js/views/network_status_view.js
deleted file mode 100644
index a780f87cd..000000000
--- a/js/views/network_status_view.js
+++ /dev/null
@@ -1,133 +0,0 @@
-/* global Whisper, extension, Backbone, moment, i18n */
-
-// eslint-disable-next-line func-names
-(function() {
- 'use strict';
-
- window.Whisper = window.Whisper || {};
-
- const DISCONNECTED_DELAY = 30000;
-
- Whisper.NetworkStatusView = Whisper.View.extend({
- className: 'network-status',
- templateName: 'networkStatus',
- initialize() {
- this.$el.hide();
-
- this.renderIntervalHandle = setInterval(this.update.bind(this), 5000);
- extension.windows.onClosed(() => {
- clearInterval(this.renderIntervalHandle);
- });
-
- setTimeout(this.finishConnectingGracePeriod.bind(this), 5000);
-
- this.withinConnectingGracePeriod = true;
- this.setSocketReconnectInterval(null);
-
- window.addEventListener('online', this.update.bind(this));
- window.addEventListener('offline', this.update.bind(this));
-
- this.model = new Backbone.Model();
- this.listenTo(this.model, 'change', this.onChange);
- this.connectedTimer = null;
- },
- onReconnectTimer() {
- this.setSocketReconnectInterval(60000);
- },
- finishConnectingGracePeriod() {
- this.withinConnectingGracePeriod = false;
- },
- setSocketReconnectInterval(millis) {
- this.socketReconnectWaitDuration = moment.duration(millis);
- },
- navigatorOnLine() {
- return navigator.onLine;
- },
- getSocketStatus() {
- return window.getSocketStatus();
- },
- getNetworkStatus(shortCircuit = false) {
- let message = '';
- let instructions = '';
- let hasInterruption = false;
-
- const socketStatus = this.getSocketStatus();
- switch (socketStatus) {
- case WebSocket.CONNECTING:
- message = i18n('connecting');
- this.setSocketReconnectInterval(null);
- window.clearTimeout(this.connectedTimer);
- this.connectedTimer = null;
- break;
- case WebSocket.OPEN:
- this.setSocketReconnectInterval(null);
- window.clearTimeout(this.connectedTimer);
- this.connectedTimer = null;
- break;
- case WebSocket.CLOSED:
- // Intentional fallthrough
- case WebSocket.CLOSING:
- // Intentional fallthrough
- default: {
- const markOffline = () => {
- message = i18n('offline');
- instructions = i18n('checkNetworkConnection');
- hasInterruption = true;
- };
- if (shortCircuit) {
- // Used to skip the timer for testing
- markOffline();
- break;
- }
- if (!this.connectedTimer) {
- // Mark offline if disconnected for 30 seconds
- this.connectedTimer = window.setTimeout(() => {
- markOffline();
- }, DISCONNECTED_DELAY);
- }
- break;
- }
- }
-
- if (
- socketStatus === WebSocket.CONNECTING &&
- !this.withinConnectingGracePeriod
- ) {
- hasInterruption = true;
- }
- if (this.socketReconnectWaitDuration.asSeconds() > 0) {
- instructions = i18n('attemptingReconnection', [
- this.socketReconnectWaitDuration.asSeconds(),
- ]);
- }
- if (!this.navigatorOnLine()) {
- hasInterruption = true;
- message = i18n('offline');
- instructions = i18n('checkNetworkConnection');
- }
-
- return {
- message,
- instructions,
- hasInterruption,
- action: null,
- buttonClass: null,
- };
- },
- update() {
- const status = this.getNetworkStatus();
- this.model.set(status);
- },
- render_attributes() {
- return this.model.attributes;
- },
- onChange() {
- this.render();
- if (this.model.attributes.hasInterruption) {
- this.$el.slideDown();
- } else {
- this.$el.hide();
- }
- },
- });
-})();
diff --git a/stylesheets/_index.scss b/stylesheets/_index.scss
index f801e8894..d060c96a1 100644
--- a/stylesheets/_index.scss
+++ b/stylesheets/_index.scss
@@ -166,28 +166,6 @@ h4.section-toggle,
}
}
-.network-status-container {
- .network-status {
- padding: 10px;
- padding-inline-start: 2 * $button-height;
- display: none;
-
- .network-status-message {
- h3 {
- padding: 0px;
- margin: 0px;
- margin-bottom: 2px;
- font-size: 14px;
- }
- span {
- display: inline-block;
- font-size: 12px;
- padding: 0.5em 0;
- }
- }
- }
-}
-
.left-pane-placeholder {
flex-grow: 1;
display: flex;
diff --git a/stylesheets/_session_theme.scss b/stylesheets/_session_theme.scss
index ce0d4dc24..14166b3ce 100644
--- a/stylesheets/_session_theme.scss
+++ b/stylesheets/_session_theme.scss
@@ -174,14 +174,3 @@ h4 {
font-size: 17px;
text-align: center;
}
-
-.network-status {
- @include themify($themes) {
- background: themed('accent');
- }
-
- h3,
- .network-status-message {
- color: $black;
- }
-}
diff --git a/test/index.html b/test/index.html
index 6ef6df4b9..44eda5088 100644
--- a/test/index.html
+++ b/test/index.html
@@ -105,24 +105,6 @@
-
-
-
-
@@ -260,7 +241,6 @@
-
diff --git a/test/views/network_status_view_test.js b/test/views/network_status_view_test.js
deleted file mode 100644
index 488ff7101..000000000
--- a/test/views/network_status_view_test.js
+++ /dev/null
@@ -1,160 +0,0 @@
-/* global _, $, Whisper */
-
-describe('NetworkStatusView', () => {
- describe('getNetworkStatus', () => {
- let networkStatusView;
- let socketStatus = WebSocket.OPEN;
-
- let oldGetSocketStatus;
-
- /* BEGIN stubbing globals */
- before(() => {
- oldGetSocketStatus = window.getSocketStatus;
- window.getSocketStatus = () => socketStatus;
- });
-
- after(() => {
- window.getSocketStatus = oldGetSocketStatus;
-
- // It turns out that continued calls to window.getSocketStatus happen
- // because we host NetworkStatusView in three mock interfaces, and the view
- // checks every N seconds. That results in infinite errors unless there is
- // something to call.
- window.getSocketStatus = () => WebSocket.OPEN;
- });
- /* END stubbing globals */
-
- beforeEach(() => {
- networkStatusView = new Whisper.NetworkStatusView();
- $('.network-status-container').append(networkStatusView.el);
- });
- afterEach(() => {
- // prevents huge number of errors on console after running tests
- clearInterval(networkStatusView.renderIntervalHandle);
- networkStatusView = null;
- });
-
- describe('initialization', () => {
- it('should have an empty interval', () => {
- assert.equal(
- networkStatusView.socketReconnectWaitDuration.asSeconds(),
- 0
- );
- });
- });
- describe('network status with no connection', () => {
- beforeEach(() => {
- networkStatusView.navigatorOnLine = () => false;
- });
- it('should be interrupted', () => {
- networkStatusView.update();
- const status = networkStatusView.getNetworkStatus();
- assert(status.hasInterruption);
- assert.equal(status.instructions, 'Check your network connection.');
- });
- it('should display an offline message', () => {
- networkStatusView.update();
- assert.match(networkStatusView.$el.text(), /Offline/);
- });
- it('should override socket status', () => {
- _([
- WebSocket.CONNECTING,
- WebSocket.OPEN,
- WebSocket.CLOSING,
- WebSocket.CLOSED,
- ]).forEach(socketStatusVal => {
- socketStatus = socketStatusVal;
- networkStatusView.update();
- assert.match(networkStatusView.$el.text(), /Offline/);
- });
- });
- it('should override registration status', () => {
- Whisper.Registration.remove();
- networkStatusView.update();
- assert.match(networkStatusView.$el.text(), /Offline/);
- });
- });
- describe('network status when registration is done', () => {
- beforeEach(() => {
- networkStatusView.navigatorOnLine = () => true;
- Whisper.Registration.markDone();
- networkStatusView.update();
- });
- it('should not display an unlinked message', () => {
- networkStatusView.update();
- assert.notMatch(networkStatusView.$el.text(), /Relink/);
- });
- });
- describe('network status when socket is connecting', () => {
- beforeEach(() => {
- Whisper.Registration.markDone();
- socketStatus = WebSocket.CONNECTING;
- networkStatusView.update();
- });
- it('it should display a connecting string if connecting and not in the connecting grace period', () => {
- networkStatusView.withinConnectingGracePeriod = false;
- networkStatusView.getNetworkStatus();
-
- assert.match(networkStatusView.$el.text(), /Connecting/);
- });
- it('it should not be interrupted if in connecting grace period', () => {
- assert(networkStatusView.withinConnectingGracePeriod);
- const status = networkStatusView.getNetworkStatus();
-
- assert.match(networkStatusView.$el.text(), /Connecting/);
- assert(!status.hasInterruption);
- });
- it('it should be interrupted if connecting grace period is over', () => {
- networkStatusView.withinConnectingGracePeriod = false;
- const status = networkStatusView.getNetworkStatus();
-
- assert(status.hasInterruption);
- });
- });
- describe('network status when socket is open', () => {
- before(() => {
- socketStatus = WebSocket.OPEN;
- });
- it('should not be interrupted', () => {
- const status = networkStatusView.getNetworkStatus();
- assert(!status.hasInterruption);
- assert.match(
- networkStatusView.$el
- .find('.network-status-message')
- .text()
- .trim(),
- /^$/
- );
- });
- });
- describe('network status when socket is closed or closing', () => {
- _([WebSocket.CLOSED, WebSocket.CLOSING]).forEach(socketStatusVal => {
- it('should be interrupted', () => {
- socketStatus = socketStatusVal;
- networkStatusView.update();
- const shortCircuit = true;
- const status = networkStatusView.getNetworkStatus(shortCircuit);
- assert(status.hasInterruption);
- });
- });
- });
- describe('the socket reconnect interval', () => {
- beforeEach(() => {
- socketStatus = WebSocket.CLOSED;
- networkStatusView.setSocketReconnectInterval(61000);
- networkStatusView.update();
- });
- it('should format the message based on the socketReconnectWaitDuration property', () => {
- assert.equal(
- networkStatusView.socketReconnectWaitDuration.asSeconds(),
- 61
- );
- assert.match(
- networkStatusView.$('.network-status-message:last').text(),
- /Attempting reconnect/
- );
- });
- it('should be reset by changing the socketStatus to CONNECTING', () => {});
- });
- });
-});
diff --git a/ts/components/LeftPane.tsx b/ts/components/LeftPane.tsx
index 74baa5ace..7a93167b2 100644
--- a/ts/components/LeftPane.tsx
+++ b/ts/components/LeftPane.tsx
@@ -15,6 +15,7 @@ import { SessionIconType } from './session/icon';
import { SessionTheme } from '../state/ducks/SessionTheme';
import { DefaultTheme } from 'styled-components';
import { SessionSettingCategory } from './session/settings/SessionSettings';
+import { SessionOffline } from './session/network/SessionOffline';
// from https://github.com/bvaughn/react-virtualized/blob/fb3484ed5dcc41bffae8eab029126c0fb8f7abc0/source/List/types.js#L5
export type RowRendererParamsType = {
@@ -136,17 +137,20 @@ export class LeftPane extends React.Component {
}
return (
-
+ <>
+
+
+ >
);
}
@@ -156,10 +160,13 @@ export class LeftPane extends React.Component {
const directContacts = this.getDirectContactsOnly();
return (
-
+ <>
+
+
+ >
);
}
@@ -177,11 +184,13 @@ export class LeftPane extends React.Component {
const category = settingsCategory || SessionSettingCategory.Appearance;
return (
-
+ <>
+
+ >
);
}
}
diff --git a/ts/components/session/SessionInboxView.tsx b/ts/components/session/SessionInboxView.tsx
index 7797f8b37..5ef27d9cf 100644
--- a/ts/components/session/SessionInboxView.tsx
+++ b/ts/components/session/SessionInboxView.tsx
@@ -30,7 +30,6 @@ type State = {
export class SessionInboxView extends React.Component {
private store: any;
- private interval: NodeJS.Timeout | null = null;
constructor(props: any) {
super(props);
@@ -40,7 +39,6 @@ export class SessionInboxView extends React.Component {
networkError: false,
};
- const conversationModels = window.getConversations();
this.fetchHandleMessageSentData = this.fetchHandleMessageSentData.bind(
this
);
@@ -55,18 +53,6 @@ export class SessionInboxView extends React.Component {
void this.setupLeftPane();
- // ConversationCollection
- // this.listenTo(inboxCollection, 'messageError', () => {
- // if (this.networkStatusView) {
- // this.networkStatusView.render();
- // }
- // });
-
- // this.networkStatusView = new Whisper.NetworkStatusView();
- // this.$el
- // .find('.network-status-container')
- // .append(this.networkStatusView.render().el);
-
// extension.expired(expired => {
// if (expired) {
// const banner = new Whisper.ExpiredAlertBanner().render();
@@ -144,10 +130,6 @@ export class SessionInboxView extends React.Component {
return null;
}
- // then, find in this conversation the very same message
- // const msg = conv.messageCollection.models.find(
- // convMsg => convMsg.id === tmpMsg.id
- // );
const msg = window.MessageController._get()[m.identifier];
if (!msg || !msg.message) {
@@ -256,34 +238,4 @@ export class SessionInboxView extends React.Component {
private showSessionViewConversation() {
this.setState({ settingsCategory: undefined });
}
-
- // private startConnectionListener() {
- // this.interval = global.setInterval(() => {
- // const status = window.getSocketStatus();
- // switch (status) {
- // case WebSocket.CONNECTING:
- // break;
- // case WebSocket.OPEN:
- // if (this.interval) {
- // clearInterval(this.interval);
- // }
- // // Default to connected, but lokinet is slow so we pretend empty event
- // // this.onEmpty();
- // this.interval = null;
- // break;
- // case WebSocket.CLOSING:
- // case WebSocket.CLOSED:
- // if (this.interval) {
- // clearInterval(this.interval);
- // }
- // this.interval = null;
- // // if we failed to connect, we pretend we got an empty event
- // // this.onEmpty();
- // break;
- // default:
- // // We also replicate empty here
- // // this.onEmpty();
- // }
- // }, 1000);
- // }
}
diff --git a/ts/components/session/network/SessionOffline.tsx b/ts/components/session/network/SessionOffline.tsx
new file mode 100644
index 000000000..be3a7f8d1
--- /dev/null
+++ b/ts/components/session/network/SessionOffline.tsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import styled from 'styled-components';
+import { useNetwork } from './useNetwork';
+
+type ContainerProps = {
+ show: boolean;
+};
+
+const OfflineContainer = styled.div`
+ background: ${props => props.theme.colors.accent};
+ color: ${props => props.theme.colors.textColor};
+ padding: ${props => (props.show ? props.theme.common.margins.sm : '0px')};
+ margin: ${props => (props.show ? props.theme.common.margins.xs : '0px')};
+ height: ${props => (props.show ? 'auto' : '0px')};
+ overflow: hidden;
+ transition: ${props => props.theme.common.animations.defaultDuration};
+`;
+
+const OfflineTitle = styled.h3`
+ padding-top: 0px;
+ margin-top: 0px;
+`;
+
+const OfflineMessage = styled.div``;
+
+export const SessionOffline = () => {
+ const isOnline = useNetwork();
+
+ return (
+
+ {window.i18n('offline')}
+ {window.i18n('checkNetworkConnection')}
+
+ );
+};
diff --git a/ts/components/session/network/useNetwork.ts b/ts/components/session/network/useNetwork.ts
new file mode 100644
index 000000000..4e05f96e5
--- /dev/null
+++ b/ts/components/session/network/useNetwork.ts
@@ -0,0 +1,19 @@
+import { useEffect, useState } from 'react';
+
+export function useNetwork() {
+ const [isOnline, setNetwork] = useState(window.navigator.onLine);
+ const updateNetwork = () => {
+ setNetwork(window.navigator.onLine);
+ };
+
+ useEffect(() => {
+ window.addEventListener('offline', updateNetwork);
+ window.addEventListener('online', updateNetwork);
+
+ return () => {
+ window.removeEventListener('offline', updateNetwork);
+ window.removeEventListener('online', updateNetwork);
+ };
+ });
+ return isOnline;
+}