diff --git a/.doclets.yml b/.doclets.yml new file mode 100644 index 0000000..f8b3f58 --- /dev/null +++ b/.doclets.yml @@ -0,0 +1,9 @@ +dir: . +packageJson: package.json +articles: + - Overview: README.md + - Changelog: CHANGELOG.md + - License: LICENSE +branches: + - master + - develop diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..a188e06 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +docs/* diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..5956f32 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,8 @@ +# Contribution Guidelines + +Thanks for contributing to this module! + +Please create pull requests to the branch `develop`. + +To hold one code style and standard there are several linters and tools in this project set. Make sure you fullfill the requirements. +Also there will be automatically analysis performed once you created the pull request. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..5bbae68 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,9 @@ +Platform (Hardware/OS): + +Node version: + +MagicMirror version: + +Module version: + +Description of the issue: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..63fa699 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,5 @@ +Please create pull requests to the branch `develop`. + +* Does the pull request solve an issue (add a reference)? +* What are the features of this pr? +* Add screenshots for visual changes. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2a19034 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.log +npm-debug.log* + +node_modules/ + +.idea/ + +docs/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..abe492e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +# MMM-AlarmClock Changelog + +## [1.1.0] + +### Added + +* Volume fade in (see config options fade, fadeTimer and fadeStep). +* French translations +* Indonesian translations +* Documentation +* [Doclets.io](https://doclets.io/fewieden/MMM-AlarmClock/master) integration +* Contributing guidelines +* Issue template +* Pull request template +* gitignore + +## [1.0.0] + +Initial version diff --git a/MMM-AlarmClock.js b/MMM-AlarmClock.js index a1fadb6..21e7028 100644 --- a/MMM-AlarmClock.js +++ b/MMM-AlarmClock.js @@ -1,40 +1,126 @@ -/* global Module Log config moment MM */ - -/* Magic Mirror - * Module: MMM-AlarmClock +/** + * @file MMM-AlarmClock.js + * + * @author fewieden + * @license MIT * - * By fewieden https://github.com/fewieden/MMM-AlarmClock - * MIT Licensed. + * @see https://github.com/fewieden/MMM-AlarmClock + */ + +/* global Module Log moment config MM */ + +/** + * @external Module + * @see https://github.com/MichMich/MagicMirror/blob/master/js/module.js + */ + +/** + * @external Log + * @see https://github.com/MichMich/MagicMirror/blob/master/js/logger.js + */ + +/** + * @external moment + * @see https://www.npmjs.com/package/moment + */ + +/** + * @external config + * @see https://github.com/MichMich/MagicMirror/blob/master/config/config.js.sample */ +/** + * @external MM + * @see https://github.com/MichMich/MagicMirror/blob/master/js/main.js + */ + +/** + * @module MMM-AlarmClock + * @description Frontend for the module to display data. + * + * @requires external:Module + * @requires external:Log + * @requires external:moment + * @requires external:config + * @requires external:MM + */ Module.register('MMM-AlarmClock', { + /** @member {?Object} next - Contains the next alarm object. */ next: null, + /** @member {boolean} alarmFired - Flag that indicates if there is a alarm firing right now. */ alarmFired: false, + /** @member {?Timeout} timer - Fires resetAlarmClock */ + timer: null, + /** @member {?Interval} fadeInterval - Fades in the alarm volume. */ + fadeInterval: null, + + /** + * @member {Object} defaults - Defines the default config values. + * @property {string} sound - Alarm sound file. + * @property {boolean} touch - Flag to enable touch support. + * @property {number} volume - Alarm sound volume. + * @property {string} format - Alarm datetime format to display in UI. + * @property {int} timer - Alarm sound duration. + * @property {boolean} fade - Flag to fade in alarm sound volume. + * @property {int} fadeTimer - Fade in duration. + * @property {number} fadeStep - Fade in volume steps. + */ defaults: { sound: 'alarm.mp3', touch: false, volume: 1.0, format: 'ddd, h:mmA', - timer: 60 * 1000 // one minute + timer: 60 * 1000, // one minute + fade: false, + fadeTimer: 60 * 1000, // 60 seconds + fadeStep: 0.005 // 0.5% }, + /** + * @function getStyles + * @description Style dependencies for this module. + * @override + * + * @returns {string[]} List of the style dependency filepaths. + */ getStyles() { return ['font-awesome.css', 'MMM-AlarmClock.css']; }, + /** + * @function getScripts + * @description Script dependencies for this module. + * @override + * + * @returns {string[]} List of the script dependency filepaths. + */ getScripts() { return ['moment.js']; }, + /** + * @function getTranslations + * @description Translations for this module. + * @override + * + * @returns {Object.} Available translations for this module (key: language code, value: filepath). + */ getTranslations() { return { en: 'translations/en.json', - de: 'translations/de.json' + de: 'translations/de.json', + fr: 'translations/fr.json', + id: 'translations/id.json' }; }, + /** + * @function start + * @description Sets first alarm and creates interval to check the alarm event. + * @override + */ start() { Log.info(`Starting module: ${this.name}`); this.setNextAlarm(); @@ -44,6 +130,10 @@ Module.register('MMM-AlarmClock', { moment.locale(config.language); }, + /** + * @function checkAlarm + * @description Checks the alarm event and triggers the alert. + */ checkAlarm() { if (!this.alarmFired && this.next && moment().diff(this.next.moment) >= 0) { const alert = { @@ -65,6 +155,7 @@ Module.register('MMM-AlarmClock', { if (module.name === 'alert') { module.alerts['MMM-AlarmClock'].ntf.addEventListener('click', () => { clearTimeout(this.timer); + clearTimeout(this.fadeInterval); this.resetAlarmClock(); }); } @@ -73,6 +164,29 @@ Module.register('MMM-AlarmClock', { } }, + /** + * @function fadeAlarm + * @description Fades in the alarm sound step by step. + */ + fadeAlarm() { + let volume = 0; + let counter = 0; + this.fadeInterval = setInterval(() => { + const player = document.getElementById('MMM-AlarmClock-Player'); + player.volume = volume; + volume += this.config.fadeStep; + counter += 1000; + if (volume >= this.config.volume || counter >= this.config.fadeTimer) { + player.volume = this.config.volume; + clearInterval(this.fadeInterval); + } + }, 1000); + }, + + /** + * @function setNextAlarm + * @description Sets the next occurring alarm event. + */ setNextAlarm() { this.next = null; for (let i = 0; i < this.config.alarms.length; i += 1) { @@ -84,6 +198,10 @@ Module.register('MMM-AlarmClock', { } }, + /** + * @function resetAlarmClock + * @description Resets the alarm clock. + */ resetAlarmClock() { this.alarmFired = false; if (this.config.touch) { @@ -93,6 +211,24 @@ Module.register('MMM-AlarmClock', { this.updateDom(300); }, + /** + * @function getMoment + * @description Creates a moment object based on alarm event. + * + * @param {Object} alarm - Alarm event. + * @param {string} alarm.time - Alarm event time. + * @param {int[]} alarm.days - Weekdays the alarm event occurrs. + * + * @returns {Object} Moment object for the next occurrence of this alarm event. + * + * @example alarm object + * { + * time: "18:30", + * days: [2,4], + * title: "Soccer", + * message: "Get ready for soccer training!" + * } + */ getMoment(alarm) { const now = moment(); let difference = Math.min(); @@ -120,6 +256,13 @@ Module.register('MMM-AlarmClock', { }); }, + /** + * @function getDom + * @description Creates the UI as DOM for displaying in MagicMirror application. + * @override + * + * @returns {Element} + */ getDom() { const wrapper = document.createElement('div'); const header = document.createElement('header'); @@ -141,14 +284,18 @@ Module.register('MMM-AlarmClock', { wrapper.appendChild(text); } else if (this.alarmFired) { const sound = document.createElement('audio'); + sound.setAttribute('id', 'MMM-AlarmClock-Player'); if (this.config.sound.match(/^https?:\/\//)) { sound.src = this.config.sound; } else { sound.src = this.file(`sounds/${this.config.sound}`); } - sound.volume = this.config.volume; + sound.volume = this.config.fade ? 0 : this.config.volume; sound.setAttribute('autoplay', true); sound.setAttribute('loop', true); + if (this.config.fade === true) { + this.fadeAlarm(); + } wrapper.appendChild(sound); } else { const alarm = document.createElement('div'); diff --git a/README.md b/README.md index aba9f30..5d9647b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# MMM-AlarmClock [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://raw.githubusercontent.com/fewieden/MMM-AlarmClock/master/LICENSE) [![Build Status](https://travis-ci.org/fewieden/MMM-AlarmClock.svg?branch=master)](https://travis-ci.org/fewieden/MMM-AlarmClock) [![Code Climate](https://codeclimate.com/github/fewieden/MMM-AlarmClock/badges/gpa.svg?style=flat)](https://codeclimate.com/github/fewieden/MMM-AlarmClock) [![Known Vulnerabilities](https://snyk.io/test/github/fewieden/mmm-alarmclock/badge.svg)](https://snyk.io/test/github/fewieden/mmm-alarmclock) +# MMM-AlarmClock [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://raw.githubusercontent.com/fewieden/MMM-AlarmClock/master/LICENSE) [![Build Status](https://travis-ci.org/fewieden/MMM-AlarmClock.svg?branch=master)](https://travis-ci.org/fewieden/MMM-AlarmClock) [![Code Climate](https://codeclimate.com/github/fewieden/MMM-AlarmClock/badges/gpa.svg?style=flat)](https://codeclimate.com/github/fewieden/MMM-AlarmClock) [![Known Vulnerabilities](https://snyk.io/test/github/fewieden/mmm-alarmclock/badge.svg)](https://snyk.io/test/github/fewieden/mmm-alarmclock) [![API Doc](https://doclets.io/fewieden/MMM-AlarmClock/master.svg)](https://doclets.io/fewieden/MMM-AlarmClock/master) Alarm Clock Module for MagicMirror2 @@ -39,6 +39,9 @@ Alarm Clock Module for MagicMirror2 | `touch` | `false` | If you are using a touch screen device you need to press a button to disable an alarm.. | | `format` | `'ddd, h:mmA'` | In which format the alarm in the header should be displayed. [All Options](http://momentjs.com/docs/#/displaying/format/) | | `timer` | `60000` (1 min) | How long the alarm should ring for non touch screen or without interaction on touch screen devices. | +| `fade` | `false` | Set to enable a gradual fade-in of the alarm sound. +| `fadeTimer` | `60 * 1000` (1 min) | How long to fade into the alarm before `volume` is set. +| `fadeStep` | `.005` (.5%) | Increase the volume this percent amount each second until `fadeTimer` is reached. ## Alarm Sounds @@ -46,3 +49,12 @@ There are already two alarm sounds: * [alarm.mp3](http://www.orangefreesounds.com/mp3-alarm-clock/) | From Alexander licensed under [CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) * [blackforest.mp3](http://www.orangefreesounds.com/coo-coo-clock-sound/) | From Alexander licensed under [CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) + +## Developer + +* `npm run lint` - Lints JS and CSS files. +* `npm run docs` - Generates documentation. + +### Documentation + +The documentation can be found [here](https://doclets.io/fewieden/MMM-AlarmClock/master) diff --git a/jsdoc.json b/jsdoc.json new file mode 100644 index 0000000..7c46152 --- /dev/null +++ b/jsdoc.json @@ -0,0 +1,18 @@ +{ + "tags": { + "dictionaries": ["jsdoc"] + }, + "source": { + "include": [ + "package.json", + "README.md" + ], + "exclude": [ + "node_modules" + ] + }, + "opts": { + "destination": "docs", + "recurse": true + } +} diff --git a/package.json b/package.json index c4ddc7f..a5d6f7f 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,10 @@ { "name": "mmm-alarmclock", - "version": "1.0.0", + "version": "1.1.0", "description": "Alarm Clock Module for MagicMirror2", "scripts": { - "lint": "./node_modules/.bin/eslint . && ./node_modules/.bin/stylelint ." + "lint": "./node_modules/.bin/eslint . && ./node_modules/.bin/stylelint .", + "docs": "./node_modules/.bin/jsdoc -c jsdoc.json ." }, "repository": { "type": "git", @@ -23,6 +24,7 @@ "eslint": "^3.14.1", "eslint-config-airbnb-base": "^11.0.1", "eslint-plugin-import": "^2.2.0", + "jsdoc": "^3.4.3", "stylelint": "^7.8.0", "stylelint-config-standard": "^16.0.0" } diff --git a/translations/fr.json b/translations/fr.json new file mode 100644 index 0000000..d48032f --- /dev/null +++ b/translations/fr.json @@ -0,0 +1,4 @@ +{ + "LOADING": "Chargement...", + "ALARM_CLOCK": "Réveil" +} diff --git a/translations/id.json b/translations/id.json new file mode 100644 index 0000000..b733a05 --- /dev/null +++ b/translations/id.json @@ -0,0 +1,4 @@ +{ + "LOADING": "Memuat...", + "ALARM_CLOCK": "Jam Alarm" +} \ No newline at end of file