Skip to content

Commit 55b26fa

Browse files
authored
Merge pull request #14 from hovancik/feature/settings
Create settings for stretchly
2 parents bfb88ec + 960a5f1 commit 55b26fa

File tree

12 files changed

+304
-16
lines changed

12 files changed

+304
-16
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
88
### Added
99
- rename strechly to stretchly (grammar, yay!)
1010
- allows only one instance of app
11+
- settings for microbreak (duration, interval)
12+
- 5 color scheme
1113

1214
## 0.0.1 - 2016-09-06
1315
### Added

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ Feel free to join development of this app via Issues and Pull Requests.
3434
- [x] PR tools
3535
- [x] make installers/executables
3636
- [x] create about page
37+
- [x] only one instance
3738
- [ ] notification on 2nd instance
3839
- [ ] create longer breaks (5min every 30 minutes)
39-
- [ ] create settings for breaks
40-
- [ ] remember settings after restart
40+
- [x] create settings for breaks
41+
- [x] remember settings after restart
4142
- [ ] autostart app
4243
- [ ] start break anytime from menu
4344
- [ ] create keyboard shortcuts
@@ -46,7 +47,7 @@ Feel free to join development of this app via Issues and Pull Requests.
4647
*(by date of the first contribution)*
4748

4849
- Jan Hovancik, @hovancik, [hovancik.net](https://hovancik.net)
49-
- Martina Mocinecova, (*stretchly* logo)
50+
- Martina Mocinecova, (*stretchly* logo), color schemes
5051

5152
### Humans and Tools
5253
- https://github.com/typefoo/node-icns

app/css/app.css

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
body {
1212
color: #fff;
13-
background-color: #478484;
1413
text-align: center;
1514
font-size: 28px;
1615
font-family: 'Lato Hairline'
@@ -23,6 +22,32 @@ body {
2322
margin: 0 auto;
2423
}
2524

25+
.color-scheme {
26+
padding-top: 60px;
27+
}
28+
29+
.settings {
30+
padding-top: 10px;
31+
}
32+
33+
.scheme {
34+
display: inline-block;
35+
text-align: center;
36+
width: 130px;
37+
font-size: 20px;
38+
}
39+
40+
.color {
41+
width: 20px;
42+
height: 20px;
43+
margin: 5px auto;
44+
box-shadow: 1px 1px 10px 0 rgba(50, 50, 50, 0.6);
45+
}
46+
47+
.pointer {
48+
cursor: pointer;
49+
}
50+
2651
.microbreak-idea,
2752
.about-name,
2853
.start-name {
@@ -31,7 +56,7 @@ body {
3156

3257
#close,
3358
#about-footer {
34-
color: white;
59+
color: #fff;
3560
position: absolute;
3661
bottom: 20px;
3762
left: 50%;

app/main.js

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
const {app, BrowserWindow, Tray, Menu, ipcMain} = require('electron')
33
const path = require('path')
44

5-
const Shuffled = require('./shuffled')
5+
const Shuffled = require('./utils/shuffled')
6+
const AppSettings = require('./utils/settings')
7+
68
let microbreakIdeas = new Shuffled([
79
'Go grab a glass of water.',
810
'Slowly look all the way left, then right.',
@@ -23,9 +25,11 @@ let appIcon = null
2325
let microbreakWin = null
2426
let appStartupWin = null
2527
let aboutWin = null
28+
let settingsWin = null
2629
let finishMicrobreakTimer
2730
let startMicrobreakTimer
2831
let planMicrobreakTimer
32+
let settings
2933

3034
function createTrayIcon () {
3135
if (process.platform === 'darwin') {
@@ -43,7 +47,7 @@ function showStartUpWindow () {
4347
frame: false,
4448
alwaysOnTop: true,
4549
title: 'stretchly',
46-
backgroundColor: '#478484',
50+
backgroundColor: settings.get('mainColor'),
4751
width: 600,
4852
height: 170
4953
})
@@ -58,7 +62,7 @@ function startMicrobreak () {
5862
microbreakWin = new BrowserWindow({
5963
frame: false,
6064
alwaysOnTop: true,
61-
backgroundColor: '#478484',
65+
backgroundColor: settings.get('mainColor'),
6266
title: 'stretchly'
6367
})
6468
microbreakWin.on('close', function () { microbreakWin = null })
@@ -67,7 +71,7 @@ function startMicrobreak () {
6771
microbreakWin.webContents.on('did-finish-load', () => {
6872
microbreakWin.webContents.send('breakIdea', microbreakIdeas.randomElement)
6973
})
70-
finishMicrobreakTimer = setTimeout(finishMicrobreak, 20000)
74+
finishMicrobreakTimer = setTimeout(finishMicrobreak, settings.get('microbreakDuration'))
7175
}
7276

7377
function finishMicrobreak () {
@@ -77,14 +81,19 @@ function finishMicrobreak () {
7781
}
7882

7983
function planMicrobreak () {
80-
startMicrobreakTimer = setTimeout(startMicrobreak, 600000)
84+
startMicrobreakTimer = setTimeout(startMicrobreak, settings.get('microbreakInterval'))
8185
}
8286

8387
ipcMain.on('finish-microbreak', function () {
8488
clearTimeout(finishMicrobreakTimer)
8589
finishMicrobreak()
8690
})
8791

92+
ipcMain.on('save-setting', function (event, key, value) {
93+
settings.set(key, value)
94+
settingsWin.webContents.send('renderSettings', settings.data)
95+
})
96+
8897
let shouldQuit = app.makeSingleInstance(function (commandLine, workingDirectory) {
8998
if (appIcon) {
9099
// Someone tried to run a second instance
@@ -96,6 +105,7 @@ if (shouldQuit) {
96105
app.quit()
97106
}
98107

108+
app.on('ready', loadSettings)
99109
app.on('ready', createTrayIcon)
100110
app.on('ready', planMicrobreak)
101111
app.on('ready', showStartUpWindow)
@@ -104,6 +114,12 @@ app.on('window-all-closed', () => {
104114
// do nothing, so app wont get closed
105115
})
106116

117+
function loadSettings () {
118+
const dir = app.getPath('userData')
119+
const settingsFile = `${dir}/config.json`
120+
settings = new AppSettings(settingsFile)
121+
}
122+
107123
function pauseMicrobreaks () {
108124
if (microbreakWin) {
109125
clearTimeout(finishMicrobreakTimer)
@@ -123,12 +139,25 @@ function showAboutWindow () {
123139
const modalPath = path.join('file://', __dirname, 'about.html')
124140
aboutWin = new BrowserWindow({
125141
alwaysOnTop: true,
126-
backgroundColor: '#478484',
142+
backgroundColor: settings.get('mainColor'),
127143
title: 'About stretchly'
128144
})
129145
aboutWin.loadURL(modalPath)
130146
}
131147

148+
function showSettingsWindow () {
149+
const modalPath = path.join('file://', __dirname, 'settings.html')
150+
settingsWin = new BrowserWindow({
151+
alwaysOnTop: true,
152+
backgroundColor: settings.get('mainColor'),
153+
title: 'Settings'
154+
})
155+
settingsWin.loadURL(modalPath)
156+
settingsWin.webContents.on('did-finish-load', () => {
157+
settingsWin.webContents.send('renderSettings', settings.data)
158+
})
159+
}
160+
132161
function getTrayMenu (MicrobreaksPaused) {
133162
let trayMenu = []
134163

@@ -138,6 +167,12 @@ function getTrayMenu (MicrobreaksPaused) {
138167
showAboutWindow()
139168
}
140169
}, {
170+
label: 'Settings',
171+
click: function () {
172+
showSettingsWindow()
173+
}
174+
}
175+
, {
141176
type: 'separator'
142177
})
143178

app/settings.html

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Settings</title>
5+
<link rel="stylesheet" type="text/css" href="css/app.css">
6+
</head>
7+
<body>
8+
<div class="settings">
9+
<div>
10+
<h2>microbreaks</h2>
11+
<p>
12+
<span id="microbreakDurationMinus" class="pointer">-</span>
13+
<span id="microbreakDuration"></span>
14+
<span id="microbreakDurationPlus" class="pointer">+</span>
15+
seconds break every
16+
<span id="microbreakIntervalMinus" class="pointer">-</span>
17+
<span id="microbreakInterval"></span>
18+
<span id="microbreakIntervalPlus" class="pointer">+</span>
19+
minutes
20+
</p>
21+
</div>
22+
<div class="color-scheme">
23+
<h2>color scheme</h2>
24+
<div class="scheme">
25+
<div class="color pointer" data-color="#478484"></div>
26+
green <br/> clouds
27+
</div>
28+
<div class="scheme">
29+
<div class="color pointer" data-color="#633738"></div>
30+
autumn be blessed
31+
</div>
32+
<div class="scheme">
33+
<div class="color pointer" data-color="#CCB6A1"></div>
34+
splash of cappuccino
35+
</div>
36+
<div class="scheme">
37+
<div class="color pointer" data-color="#A49898"></div>
38+
coffee <br/> kisses
39+
</div>
40+
<div class="scheme">
41+
<div class="color pointer" data-color="#567890"></div>
42+
morning <br/> swim
43+
</div>
44+
</div>
45+
</div>
46+
<script>
47+
require('./settings.js')
48+
</script>
49+
</body>
50+
</html>

app/settings.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
const {ipcRenderer} = require('electron')
2+
3+
let microbreakIntervalPlus = document.getElementById('microbreakIntervalPlus')
4+
let microbreakIntervalMinus = document.getElementById('microbreakIntervalMinus')
5+
let microbreakInterval = document.getElementById('microbreakInterval')
6+
7+
let microbreakDurationPlus = document.getElementById('microbreakDurationPlus')
8+
let microbreakDurationMinus = document.getElementById('microbreakDurationMinus')
9+
let microbreakDuration = document.getElementById('microbreakDuration')
10+
11+
microbreakIntervalPlus.addEventListener('click', function (e) {
12+
if (microbreakInterval.innerHTML !== '30') {
13+
ipcRenderer.send('save-setting', 'microbreakInterval', (parseInt(microbreakInterval.innerHTML, 10) + 5) * 1000 * 60)
14+
}
15+
})
16+
17+
microbreakIntervalMinus.addEventListener('click', function (e) {
18+
if (microbreakInterval.innerHTML !== '5') {
19+
ipcRenderer.send('save-setting', 'microbreakInterval', (parseInt(microbreakInterval.innerHTML, 10) - 5) * 1000 * 60)
20+
}
21+
})
22+
23+
microbreakDurationPlus.addEventListener('click', function (e) {
24+
if (microbreakDuration.innerHTML !== '30') {
25+
ipcRenderer.send('save-setting', 'microbreakDuration', (parseInt(microbreakDuration.innerHTML, 10) + 5) * 1000)
26+
}
27+
})
28+
29+
microbreakDurationMinus.addEventListener('click', function (e) {
30+
if (microbreakDuration.innerHTML !== '5') {
31+
ipcRenderer.send('save-setting', 'microbreakDuration', (parseInt(microbreakDuration.innerHTML, 10) - 5) * 1000)
32+
}
33+
})
34+
35+
ipcRenderer.on('renderSettings', (event, data) => {
36+
let colorElements = document.getElementsByClassName('color')
37+
for (var i = 0; i < colorElements.length; i++) {
38+
let element = colorElements[i]
39+
let color = element.dataset.color
40+
element.style.background = color
41+
element.addEventListener('click', function (e) {
42+
ipcRenderer.send('save-setting', 'mainColor', color)
43+
document.body.style.background = color
44+
})
45+
}
46+
microbreakInterval.innerHTML = data['microbreakInterval'] / 1000 / 60
47+
microbreakDuration.innerHTML = data['microbreakDuration'] / 1000
48+
})

app/utils/defaultSettings.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
microbreakDuration: 20000,
3+
microbreakInterval: 600000,
4+
mainColor: '#478484'
5+
}

app/utils/settings.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
const fs = require('fs')
2+
const defaultSettings = require('./defaultSettings')
3+
4+
class Settings {
5+
6+
constructor (configLocation) {
7+
this.settingsFile = configLocation
8+
this.data = null
9+
this.lastSync = 0
10+
11+
if (fs.existsSync(this.settingsFile)) {
12+
this._load()
13+
} else {
14+
this.data = defaultSettings
15+
this._save(true)
16+
}
17+
}
18+
19+
get (key) {
20+
if (!this.data[key]) {
21+
this.set(key, defaultSettings[key])
22+
}
23+
return this.data[key]
24+
}
25+
26+
set (key, value) {
27+
this.data[key] = value
28+
this._save()
29+
}
30+
31+
_load (retryCount = 5) {
32+
try {
33+
this.data = JSON.parse(fs.readFileSync(this.settingsFile, 'utf8'))
34+
} catch (e) {
35+
if (retryCount > 0) {
36+
setTimeout(this._load.bind(this, retryCount - 1), 10)
37+
console.log('Failed to load settings JSON file, retyring in 10 milliseconds')
38+
return
39+
}
40+
this.data = defaultSettings
41+
console.log('Failed to load settings JSON file, giving up and resetting')
42+
}
43+
}
44+
45+
_save (force) {
46+
const now = (new Date()).getTime()
47+
// don't blast the disk
48+
if ((now - this.lastSync > 250 || force)) {
49+
if (this.data) {
50+
try {
51+
fs.writeFileSync(this.settingsFile, JSON.stringify(this.data, null, 4))
52+
} catch (e) {
53+
if (this.saving) clearTimeout(this.saving)
54+
this.saving = setTimeout(this._save.bind(this), 275)
55+
}
56+
}
57+
if (this.saving) clearTimeout(this.saving)
58+
} else {
59+
if (this.saving) clearTimeout(this.saving)
60+
this.saving = setTimeout(this._save.bind(this), 275)
61+
}
62+
this.lastSync = now
63+
}
64+
65+
destroy () {
66+
this.data = null
67+
fs.unlinkSync(this.settingsFile)
68+
}
69+
}
70+
71+
module.exports = Settings
File renamed without changes.

0 commit comments

Comments
 (0)