Skip to content

Commit

Permalink
add a stupid auto update checker
Browse files Browse the repository at this point in the history
  • Loading branch information
Darmody committed Mar 29, 2016
1 parent f99b88c commit 6a9eb35
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 12 deletions.
38 changes: 28 additions & 10 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
"redux-thunk": "^1.0.2",
"sass-flex-mixin": "^1.0.0",
"seamless-immutable": "^5.1.0",
"semver": "^5.1.0",
"url-loader": "^0.5.7"
},
"devEngines": {
Expand Down
52 changes: 50 additions & 2 deletions src/containers/HomePage/HomePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@ import { show } from 'redux-modal';
import { connect } from 'react-redux';
import { logout, verify } from 'reducers/auth';
import { fetch as fetchCaptcha } from 'reducers/captcha';
import { check } from 'reducers/updater';
import { shell } from 'electron';
import Navbar from './Navbar/Navbar';
import styles from './HomePage.scss';
import updaterIcon from './updater.gif';

@connect(
state => ({
currentUser: state.auth.user,
song: state.channel.song,
outdated: state.updater.outdated,
}),
dispatch => ({
...bindActionCreators({ show, fetchCaptcha, logout, verify }, dispatch)
...bindActionCreators({ show, fetchCaptcha, logout, verify, check }, dispatch)
})
)
export default class HomePage extends Component {
Expand All @@ -21,8 +26,10 @@ export default class HomePage extends Component {
location: PropTypes.object.isRequired,
currentUser: PropTypes.object,
song: PropTypes.object,
outdated: PropTypes.bool.isRequired,
show: PropTypes.func.isRequired,
logout: PropTypes.func.isRequired,
check: PropTypes.func.isRequired,
verify: PropTypes.func.isRequired,
fetchCaptcha: PropTypes.func.isRequired,
}
Expand All @@ -31,8 +38,19 @@ export default class HomePage extends Component {
router: React.PropTypes.object
}

constructor(props) {
super(props);

const updaterInterval = setInterval(() => {
props.check();
}, 1000 * 60 * 60 * 24 * 7);

this.state = { updaterInterval };
}

componentDidMount() {
this.props.verify();
this.props.check();
}

componentWillReceiveProps(nextProps) {
Expand All @@ -41,6 +59,14 @@ export default class HomePage extends Component {
}
}

componentWillUnmount() {
const { updaterInterval } = this.state;

if (updaterInterval) {
clearInterval(updaterInterval);
}
}

notice = (song) => {
if (document.hasFocus()) return;

Expand All @@ -60,8 +86,24 @@ export default class HomePage extends Component {
this.props.logout();
}

downloadLatestVersion = () => {
shell.openExternal(
'http://doubanfmac.oss-cn-hangzhou.aliyuncs.com/DoubanFMac.dmg'
);
}

renderUpdateBar = () => {
return (
<div className={styles.updaterBar} >
<button title="有新版本可以更新" onClick={this.downloadLatestVersion} >
<img src={updaterIcon} className="icon" />
</button>
</div>
);
}

render() {
const { children, currentUser, location } = this.props;
const { children, currentUser, location, outdated } = this.props;

return (
<div>
Expand All @@ -72,6 +114,12 @@ export default class HomePage extends Component {
logoutUser={this.logoutUser}
/>
{children}
<div className={styles.footer} >
{ outdated && this.renderUpdateBar() }
<div className={styles.contactBar} >
<a href="mailto:eterlf41@gmail.com" className={styles.link} >问题反馈</a>
</div>
</div>
</div>
);
}
Expand Down
38 changes: 38 additions & 0 deletions src/containers/HomePage/HomePage.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@import '~sass-flex-mixin/flex';

.footer {
@extend %flexbox;
@include justify-content(flex-end);

position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 0.5rem;
}

.updaterBar {
@extend %flexbox;
@include flex-grow(1);
@include align-items(center);

:global {
.icon {
width: 1.5rem;
margin-left: 1rem;
}
}
}

.contactBar {
width: 4rem;
}

.link {
font-size: 0.5rem;
color: #fff;
background: #ceecd2;
padding: 0.2rem;
margin-right: 1rem;
text-decoration: none;
}
Binary file added src/containers/HomePage/updater.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/containers/HomePage/updater.gif.old.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 68 additions & 0 deletions src/reducers/__tests__/updater.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import configureMockStore from 'redux-mock-store';
import { expect } from 'chai';
import nock from 'nock';
import Immutable from 'seamless-immutable';
import { apiMiddleware } from 'redux-api-middleware';
import thunk from 'redux-thunk';
import apiMiddlewareHook from '../../middlewares/apiMiddlewareHook';
import camelizeState from '../../middlewares/camelizeState';
import _last from 'lodash/last';
import updater, { FETCH_SUCCESS, check } from '../updater';

const middlewares = [
thunk, apiMiddlewareHook, apiMiddleware, camelizeState
];
const mockStore = configureMockStore(middlewares);

describe('Updater Actions', function actions() {
afterEach(() => {
nock.cleanAll();
});

it('FETCH_SUCCESS', function fetchSuccess(done) {
nock('https://api.github.com')
.get('/repos/Darmody/DoubanFMac/releases/latest')
.reply(200, { tagName: 'v1.0.0' });

const store = mockStore({
updater: {
currentVersion: '1.0.0'
}
});
store.dispatch(check());
setTimeout(() => {
expect(_last(store.getActions()).type).to.equal(FETCH_SUCCESS);
done();
}, 20);
});
});

describe('Updater Reducers', function reducers() {
it('FETCH_SUCCESS', function fetchSuccess() {
expect(
updater(Immutable({
currentVersion: '1.0.0',
outdated: false,
}), {
type: FETCH_SUCCESS,
payload: { tagName: 'v1.0.1' }
})
).to.deep.equal({
currentVersion: '1.0.0',
outdated: true,
});

expect(
updater(Immutable({
currentVersion: '1.0.0',
outdated: false,
}), {
type: FETCH_SUCCESS,
payload: { tagName: 'v1.0.0' }
})
).to.deep.equal({
currentVersion: '1.0.0',
outdated: false,
});
});
});
2 changes: 2 additions & 0 deletions src/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import auth from './auth';
import captcha from './captcha';
import channel from './channel';
import favorite from './favorite';
import updater from './updater';

const rootReducer = combineReducers({
routing,
Expand All @@ -15,6 +16,7 @@ const rootReducer = combineReducers({
captcha,
channel,
favorite,
updater,
});

export default rootReducer;
35 changes: 35 additions & 0 deletions src/reducers/updater.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Immutable from 'seamless-immutable';
import { CALL_API } from 'redux-api-middleware';
import { handleActions } from 'redux-actions';
import semver from 'semver';
import pkg from '../../package.json';

export const FETCH_REQUEST = 'UPDATER/FETCH_REQUEST';
export const FETCH_SUCCESS = 'UPDATER/FETCH_SUCCESS';
export const FETCH_FAILURE = 'UPDATER/FETCH_FAILURE';

const initialState = Immutable({
outdated: false,
currentVersion: pkg.version
});

export default handleActions({
[FETCH_SUCCESS]: (state, action) => {
const latestVersion = semver.clean(action.payload.tagName);
return state.merge({ outdated: semver.gt(latestVersion, state.currentVersion) });
}
}, initialState);

export function check() {
return {
[CALL_API]: {
endpoint: 'https://api.github.com/repos/Darmody/DoubanFMac/releases/latest',
method: 'GET',
types: [
FETCH_REQUEST,
FETCH_SUCCESS,
FETCH_FAILURE
]
}
};
}

0 comments on commit 6a9eb35

Please sign in to comment.