Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed auto updater issues #180

Merged
merged 5 commits into from
Jan 19, 2018
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
1 change: 1 addition & 0 deletions __mocks__/electron.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module.exports = {
app: jest.fn(),
ipcRenderer: {
send: jest.fn(),
on: jest.fn(),
},
remote: {
require: jest.fn(name => {
Expand Down
26 changes: 19 additions & 7 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const omit = require('lodash').omit;

// Electron Libs
const { app, BrowserWindow, ipcMain } = require('electron');
const { autoUpdater } = require('electron-updater');

// Place a BrowserWindow in center of primary display
const centerOnPrimaryDisplay = require('./app/helpers/center-on-primary-display');
Expand Down Expand Up @@ -98,7 +99,6 @@ function createMainWindow() {
slashes: true,
})
);

// Add Event Listeners
mainWindow.on('show', event => {
if (isDev) mainWindow.webContents.openDevTools({ mode: 'detach' });
Expand Down Expand Up @@ -294,9 +294,19 @@ function addEventListeners() {
ipcMain.on('quit-app', () => {
app.quit();
});
// Use with autoUpdater
ipcMain.on('restart-app', () => {
app.relaunch();
// Quit and install
// https://github.com/electron-userland/electron-builder/issues/1604#issuecomment-306709572
ipcMain.on('quit-and-install', () => {
setImmediate(() => {
// Remove this listener
app.removeAllListeners("window-all-closed");
// Force close all windows
tourWindow.destroy();
mainWindow.destroy();
previewWindow.destroy();
// Start the quit and update sequence
autoUpdater.quitAndInstall(false);
})
});
}

Expand Down Expand Up @@ -371,9 +381,11 @@ function initialize() {
});
// Close all windows before quit the app
app.on('before-quit', () => {
tourWindow.destroy();
mainWindow.destroy();
previewWindow.destroy();
// Use condition in case quit sequence is initiated by autoUpdater
// which will destroy all there windows already before emitting this event
if (tourWindow !== null) tourWindow.destroy();
if (mainWindow !== null) mainWindow.destroy();
if (previewWindow !== null) previewWindow.destroy();
});
console.timeEnd('init');
}
Expand Down
1 change: 0 additions & 1 deletion app/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ class App extends PureComponent {
<AppNav activeTab={activeTab} changeTab={this.changeTab} />
<AppMain activeTab={activeTab} />
<AppNoti notifications={notifications} removeNoti={this.removeNoti} />
<AppUpdate />
</AppWrapper>
);
}
Expand Down
33 changes: 19 additions & 14 deletions app/components/layout/AppNav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const SideBar = styled.div`
position: relative;
display: flex;
flex-direction: column;
justify-content: flex-start;
justify-content: space-between;
height: 100%;
width: 80px;
min-width: 80px;
Expand Down Expand Up @@ -95,6 +95,8 @@ export const ActiveIndicator = styled.div`
}
`;

import AppUpdate from './AppUpdate';

function AppNav({ activeTab, changeTab }) {
const marginTopValue = setMarginValue(activeTab);
const allTabsComponent = allTabs.map(tab => (
Expand All @@ -104,19 +106,22 @@ function AppNav({ activeTab, changeTab }) {
));
return (
<SideBar>
<Motion style={{ marginTop: spring(marginTopValue, springConfig) }}>
{({ marginTop }) => (
<ActiveIndicator>
<div
style={{
height: `${100 / allTabs.length}%`,
top: `${marginTop}%`,
}}
/>
</ActiveIndicator>
)}
</Motion>
{allTabsComponent}
<div>
<Motion style={{ marginTop: spring(marginTopValue, springConfig) }}>
{({ marginTop }) => (
<ActiveIndicator>
<div
style={{
height: `${100 / allTabs.length}%`,
top: `${marginTop}%`,
}}
/>
</ActiveIndicator>
)}
</Motion>
{allTabsComponent}
</div>
<AppUpdate />
</SideBar>
);
}
Expand Down
140 changes: 64 additions & 76 deletions app/components/layout/AppUpdate.jsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,52 @@
// Libraries
import React, { Component } from 'react';
const ipc = require('electron').ipcRenderer;
import React, { PureComponent } from 'react';
import openDialog from '../../renderers/dialog';
import { Circle } from 'rc-progress';
const ipc = require('electron').ipcRenderer

// Styles
import styled from 'styled-components';
// Styled Components
import styled, { keyframes } from 'styled-components';

const Wrapper = styled.div`
position: fixed;
height: auto;
bottom: 0;
width: 100%;
padding-left: 120px;
padding-right: 40px;
`;

const Message = styled.p`
font-size: 12px;
letter-spacing: 0.5px;
color: white;
margin-bottom: 0px;
line-height: 1.75;
const breathing = keyframes`
0% { opacity: 0.5; }
100% { opacity: 1; }
`;

const Content = styled.div`
background: #469fe5;
border-radius: 4px 4px 0 0;
padding: 10px 20px;
border: 1px solid rgba(0, 0, 0, 0.1);
text-transform: uppercase;
${props => props.type === 'error' && `background: #EC476E;`};
${props => props.type === 'success' && `background: #6BBB69;`};
const Indicator = styled.div`
display: flex;
align-items: flex-start;
justify-content: space-between;
button {
color: white;
align-items: center;
justify-content: center;
height: 60px;
width: 100%;
color: #f2f3f4;
i {
font-size: 24px;
animation: ${breathing} 1s infinite alternate;
}
svg {
width: 24px;
height: 24px;
}
`;

import Button from '../../components/shared/Button';

class AppUpdate extends Component {
class AppUpdate extends PureComponent {
constructor(props) {
super(props);
this.state = {
message: null,
type: 'info',
checking: false,
downloading: false,
progress: null,
};
this.removeMessage = this.removeMessage.bind(this);
this.hideIndicator = this.hideIndicator.bind(this);
}

componentDidMount() {
ipc.on('update-checking', event => {
this.setState({ message: 'Checking for update' });
ipc.on('update-checking', () => {
this.setState({ checking: true });
});

ipc.on('update-available', () => {
this.hideIndicator();
openDialog(
{
type: 'info',
Expand All @@ -74,7 +64,7 @@ class AppUpdate extends Component {
title: 'No Updates',
message: 'Current version is up-to-date',
});
this.removeMessage();
this.hideIndicator();
});

ipc.on('update-error', (event, error) => {
Expand All @@ -83,36 +73,33 @@ class AppUpdate extends Component {
title: 'Update Error',
message: error,
});
this.removeMessage();
this.hideIndicator();
});

ipc.on('update-download-confirmed', (event, index) => {
// Start the download
if (index === 0) {
this.setState({
message: 'Downloading update ...',
type: 'success',
});
ipc.send('update-download-started');
}
// Cancel the download
if (index === 1) {
this.removeMessage();
this.hideIndicator();
return;
}
// Start the download
if (index === 0) {
this.setState(
{
downloading: true,
},
ipc.send('update-download-started')
);
}
});

ipc.on('update-download-progress', (event, progressMessage) => {
ipc.on('update-download-progress', (event, percentage) => {
this.setState({
message: progressMessage,
progress: percentage,
});
});

ipc.on('update-downloaded', () => {
// Update Message
this.setState({
message: 'Download Completed!',
});
// Ask user to upgrade now or later
openDialog(
{
type: 'info',
Expand All @@ -122,19 +109,16 @@ class AppUpdate extends Component {
},
'upgrade-confirmed'
);
this.hideIndicator();
});

ipc.on('upgrade-confirmed', (event, index) => {
if (index === 0) {
ipc.send('restart-app');
ipc.send('quit-and-install');
}
});
}

shouldComponentUpdate(nextProps, nextState) {
return this.state !== nextState;
}

componentWillUnmount() {
ipc.removeAllListeners([
'update-checking',
Expand All @@ -148,25 +132,29 @@ class AppUpdate extends Component {
]);
}

removeMessage() {
hideIndicator() {
this.setState({
message: null,
type: 'info',
checking: false,
downloading: false,
progress: null,
});
}

render() {
const { message, type } = this.state;
return message ? (
<Wrapper>
<Content type={type}>
<Message>{message}</Message>
<Button link onClick={this.removeMessage}>
<i className="ion-close" />
</Button>
</Content>
</Wrapper>
) : null;
return (
<Indicator>
{this.state.checking && <i className="ion-cloud" />}
{this.state.downloading && (
<Circle
percent={this.state.progress}
strokeWidth={16}
trailWidth={16}
trailColor="#4F555C"
strokeColor="#469FE5"
/>
)}
</Indicator>
);
}
}

Expand Down
8 changes: 4 additions & 4 deletions app/components/layout/__tests__/AppNav.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ describe('Renders correctly to the DOM', () => {
});

it('renders 4 tabs', () => {
// expect(wrapper.find('a')).toHaveLength(4);
expect(wrapper.find('a')).toHaveLength(4);
});

it('has correct porps', () => {
// expect(wrapper.prop('activeTab')).toEqual('form');
// expect(wrapper.prop('activeTab')).not.toEqual('settings');
});

// it('contains active indicator', () => {
it('contains active indicator', () => {
// const sideBar = shallow(<ActiveIndicator/>);
// expect(wrapper.contains(sideBar)).toEqual(true);
// });
// it('shows active indicator at the correct position');
});
it('shows active indicator at the correct position');
});
Loading