diff --git a/README.md b/README.md index 773cf9c..99553ab 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,4 @@ Music awesomeness for hue lights. - integration with youtube, soundcloud, spotify ??? - auto beat detection mode - lights on/off switch + diff --git a/app/components/bridge-controls.js b/app/components/bridge-controls.js index 20a223a..89ed2bf 100644 --- a/app/components/bridge-controls.js +++ b/app/components/bridge-controls.js @@ -29,7 +29,7 @@ export default Em.Component.extend({ // automatically close the group menu when the user clicks somewhere else click: function() { - if(this.get('groupControlDisplayed') && !event.target.classList.contains('menu') && !$(event.target).closest('#groupControls').length) { + if(this.get('groupControlDisplayed') && !event.target.classList.contains('group') && !$(event.target).closest('#groupControls').length) { this.toggleProperty('groupControlDisplayed'); } }, diff --git a/app/components/controls/light-control.js b/app/components/controls/light-control.js index afd453f..820eabe 100644 --- a/app/components/controls/light-control.js +++ b/app/components/controls/light-control.js @@ -3,23 +3,26 @@ import Em from 'ember'; export default Em.Component.extend({ classNames: ['innerControlFrame'], classNameBindings: ['active::hidden'], + elementId: 'lightControl', activeLights: [], lightsData: null, lightsDataIntervalHandle: null, - modalData: null, - isShowingLightsModal: false, isShowingAddGroupsModal: false, - actions: { - clickLight: function(id, data){ - if(this.get('isShowingLightsModal')){ - this.set('modalData', {data:data, id:id}); - } - this.toggleProperty('isShowingLightsModal'); - } + didInsertElement: function(){ + // handle color changes + var self = this; + + Em.$('.color').colorPicker({ + opacity: false, + + renderCallback: function(elem){ + console.log(elem[0].value); + } + }); }, // determines whether the lights are on/off for the lights switch @@ -35,6 +38,18 @@ export default Em.Component.extend({ }); }.property('lightsData', 'activeLights', 'strobeOn'), + // color of the lights in the group + color: function(){ + var lightsData = this.get('lightsData'), + color = [0,0,0]; + + if(this.get('strobeOn') || this.get('activeLights').length === 0){ + return color; + } + + return [lightsData[0].state.hue, lightsData[0].state.sat, lightsData[0].state.bri]; + }.property('lightsData', 'activeLights', 'strobeOn'), + // determines the average brightness of the hue system for the brightness slider lightsBrightness: function(){ var lightsData = this.get('lightsData'), activeLights = this.get('activeLights'), lightsBrightness = 0; diff --git a/app/components/controls/music-control.js b/app/components/controls/music-control.js index 5f13d28..7c6f261 100644 --- a/app/components/controls/music-control.js +++ b/app/components/controls/music-control.js @@ -12,7 +12,7 @@ export default Em.Component.extend(musicControlMixin, { audio.src = this.get('playQueue')[index].url; if(dancer.audio) { - this.send('clearCurrentAudio'); + this.clearCurrentAudio(true); } dancer.load(audio); @@ -24,22 +24,9 @@ export default Em.Component.extend(musicControlMixin, { this.send('play'); } }, - clearCurrentAudio: function() { - var dancer = this.get('dancer'); - - dancer.pause(); - clearInterval(this.get('incrementElapseTimeHandle')); - - this.setProperties({ - playQueuePointer: -1, - timeElapsed: 0, - timeTotal: 0, - playing: false - }); - }, removeAudio: function(index){ if(index === this.get('playQueuePointer')) { - this.send('clearCurrentAudio'); + this.clearCurrentAudio(true); } this.get('playQueue').removeAt(index); @@ -94,9 +81,13 @@ export default Em.Component.extend(musicControlMixin, { }, next: function () { var playQueuePointer = this.get('playQueuePointer'), playQueueLength = this.get('playQueue.length'); - var nextSong = (playQueuePointer + 1) % playQueueLength; + var nextSong = (playQueuePointer + 1); - this.send('goToSong', nextSong); + if(nextSong > playQueueLength-1 && this.get('repeat') === 1){ + nextSong = nextSong % playQueueLength; + + this.send('goToSong', nextSong); + } }, previous: function () { if(this.get('timeElapsed') > 5) { @@ -112,13 +103,15 @@ export default Em.Component.extend(musicControlMixin, { this.send('goToSong', nextSong); } }, - fullscreen: function () { - - }, + fullscreen: function () {}, seekChanged: function (position) { - var audioPosition = Math.floor(this.get('timeTotal') * position / 100); - this.get('dancer').source.currentTime = audioPosition; - this.set('timeElapsed', audioPosition); + var dancer = this.get('dancer'); + + if(dancer.audio){ + var audioPosition = Math.floor(this.get('timeTotal') * position / 100); + dancer.audio.currentTime = audioPosition; + this.set('timeElapsed', audioPosition); + } }, volumeMutedChanged: function (value) { var dancer = this.get('dancer'), @@ -205,7 +198,33 @@ export default Em.Component.extend(musicControlMixin, { } }, - dragLeaveTimeoutHandle: null, + clearCurrentAudio: function(resetPointer) { + var dancer = this.get('dancer'); + + dancer.pause(); + clearInterval(this.get('incrementElapseTimeHandle')); + + if(resetPointer){ + this.set('playQueuePointer', -1); + } + + this.setProperties({ + timeElapsed: 0, + timeTotal: 0, + playing: false + }); + }, + + goToNextSong: function() { + this.get('beatHistory').clear(); + + if(this.get('repeat') === 2){ + this.send('goToSong', this.get('playQueuePointer')); + } else { + this.get('timeElapsed') + this.send('next'); + } + }, dragOver: function() { var dragLeaveTimeoutHandle = this.get('dragLeaveTimeoutHandle'); @@ -222,17 +241,6 @@ export default Em.Component.extend(musicControlMixin, { this.set('dragLeaveTimeoutHandle', setTimeout(function(){ self.set('dragging', false); }, 500)); }, - changePlayerControl: function(name, value, isOption){ - if(isOption){ - var options = {}; - options[name] = value; - this.get('kick').set(options); - } - - this.set(name, value); - localStorage.setItem('huegasm.' + name, value); - }, - init: function () { this._super(); diff --git a/app/components/mixins/music-control.js b/app/components/mixins/music-control.js index d182d0e..72c19a5 100644 --- a/app/components/mixins/music-control.js +++ b/app/components/mixins/music-control.js @@ -5,11 +5,11 @@ export default Em.Mixin.create({ beatOptions: { threshold: { - range: {min: 0.1, max: 0.6}, + range: {min: 0.1, max: 0.9}, defaultValue: 0.3, pips: { mode: 'positions', - values: [0,20,40,60,80,100], + values: [0,25,50,75,100], density: 3, format: { to: function ( value ) {return value;}, @@ -34,7 +34,7 @@ export default Em.Mixin.create({ frequency: { range: {min: 0, max: 10}, step: 1, - defaultValue: [0,5], + defaultValue: [0,10], pips: { mode: 'values', values: [0,2,4,6,8,10], @@ -61,6 +61,7 @@ export default Em.Mixin.create({ dragging: false, draggingOverPlayListArea: false, + dragLeaveTimeoutHandle: null, playQueueEmpty: Em.computed.empty('playQueue'), playQueueNotEmpty: Em.computed.notEmpty('playQueue'), @@ -97,9 +98,23 @@ export default Em.Mixin.create({ } }.property('speakerViewed'), + changePlayerControl: function(name, value, isOption){ + if(isOption){ + var options = {}; + options[name] = value; + this.get('kick').set(options); + } + + this.set(name, value); + localStorage.setItem('huegasm.' + name, value); + }, + incrementElapseTimeHandle: null, incrementElapseTime: function(){ this.incrementProperty('timeElapsed'); + if(this.get('timeElapsed') > this.get('timeTotal')){ + this.goToNextSong(); + } }, repeatIcon: function () { diff --git a/app/components/modals/light-control-modal.js b/app/components/modals/light-control-modal.js deleted file mode 100644 index f50df47..0000000 --- a/app/components/modals/light-control-modal.js +++ /dev/null @@ -1,9 +0,0 @@ -import Em from 'ember'; - -export default Em.Component.extend({ - actions: { - close: function(){ - this.sendAction(); - } - } -}); diff --git a/app/styles/app.scss b/app/styles/app.scss index b6dcd18..11ad9f4 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -11,6 +11,12 @@ $playerDefaultIconColor: #BBBBBB; $footerHeight: 40px; // BRIDGE FINDER +* { + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + html { min-height: 100%; height: auto; @@ -122,21 +128,40 @@ md-progress-linear { padding: 0 10px 0 10px; } -.navigationItem:hover{ - text-decoration: underline; -} - .navigationItem.active { font-weight: bold; cursor: default; } -.navigationItem.active:hover { - color: #000; - text-decoration: none; +.navigationItem:hover { + font-weight: bold; +} + +.cp-color-picker{ + z-index: 100; +} + +#lightControl{ + min-height: 500px; +} + +.color { + width: 50px; + padding: 22px; + cursor: pointer; + font-size: 0; + margin-right: 20px; +} + // LIGHT GROUP +md-slider { + cursor: pointer; +} + +md-slider.md-default-theme .md-thumb:after { + border-color: #F12B24; + background-color: #F12B24; } -// LIGHT GROUP .paper-sidenav { overflow: visible; } @@ -165,7 +190,7 @@ md-progress-linear { .lightGroup { margin: 0 auto 0 auto; .tooltip.top { - margin-top: -10px; + margin-top: 8px; } } @@ -176,28 +201,35 @@ md-progress-linear { } .lightInactive { - cursor: pointer; position: relative; - } .lightInactive::before { font-weight: bold; position: absolute; content: "X"; - top: -20px; - left: 6px; + top: 0; + left: 15px; font-size: 40px; color: rgba(255, 0, 0, 0.37); font-family: cursive; } +.horizontalLightGroup { + .lightInactive::before { + top: -21px; + left: 6px; + } + .tooltip.top { + margin-top: -10px; + } +} + .lightUnreachable { background-color: rgba(255, 0, 0, 0.7); } .lightActive img { - cursor: pointer; transition-duration: 0.3s; transition-property: transform; box-shadow: 0 0 1px rgba(0, 0, 0, 0); @@ -215,7 +247,7 @@ md-icon { color: rgba(0, 0, 0, 0.54) !important; } -md-icon.menu { +md-icon.group { margin: 30px 0 0 16px; } @@ -240,10 +272,6 @@ md-toolbar { background-color: inherit !important; } -//.innerControlFrame { -// height: 100vh; -//} - // GROUP CONTROL .groupRow.selectedRow { background-color: #7F7F7F !important; @@ -296,6 +324,13 @@ md-toolbar { } // MUSIC CONTROL +md-switch.md-default-theme.md-checked .md-bar { + background-color: rgba(241, 43, 36, 0.5); +} + +md-switch.md-default-theme.md-checked .md-thumb{ + background-color: #F12B24; +} #playerControls { opacity: 0; transition: all 0.2s ease-in-out; @@ -500,7 +535,6 @@ md-toolbar { } .playlistItem { - border-bottom: 1px solid #9E9E9E; height: 45px; font-family: 'Open Sans', sans-serif; padding: 5px; @@ -541,16 +575,20 @@ md-toolbar { #beatArea * .noUi-vertical { height: 170px; margin-top: 20px; - margin-bottom: 5px; + margin-bottom: 15px; } -.beatOption { - display: inline-block; - margin-right: 2em; +#beatOptionGroup { + margin-top: 20px; + .beatOption { + display: inline-block; + margin-right: 2em; + } } #playerBottom { - background-color: grey; + color: white; + background-color: #5D5D5D; } #beatSpeakerContainer { @@ -567,27 +605,35 @@ md-toolbar { #beatSpeaker { position: relative; - margin: 20px auto 0 auto; + margin: 10px auto 0 auto; + border-radius: 50%; + width: 280px; + height: 280px; background-image: url('images/speaker-outer.png'); - width: 284px; - height: 283px; + //border: 1px solid white; + //background: black; #beatSpeakerCenter { width: 188px; height: 186px; + position: absolute; + top: 17%; + left: 17%; + border-radius: 50%; + //border: 3px solid brown; + //background: orange; background-image: url('images/speaker-inner.png'); - position: absolute; - top: 16%; - left: 18%; - } - #beatSpeakerCenterBackground { - width: 188px; - height: 186px; - background-color: black; - position: absolute; - top: 16%; - left: 18%; - z-index: -1; } + //#beatSpeakerCenter::before { + // position: absolute; + // top: 28%; + // left: 28%; + // width: 80px; + // height: 80px; + // content: ''; + // background-color: black; + // border: 1px solid white; + // border-radius: 50%; + //} } .pop { @@ -603,7 +649,12 @@ md-toolbar { } } #beatArea .lightGroup { - margin: 10px 0 0 40px; + margin: 10px 50px 0 40px; + float: right; + span { + display: block; + padding: 10px; + } } #playerButtonGroup { @@ -621,7 +672,7 @@ md-toolbar { #beatHistory { height: 250px; - background-color: #CFCFCF; + background-color: white; border-radius: 10px; width: 80%; margin: 20px auto; diff --git a/app/templates/components/bridge-controls.hbs b/app/templates/components/bridge-controls.hbs index 642eceb..f1b2457 100644 --- a/app/templates/components/bridge-controls.hbs +++ b/app/templates/components/bridge-controls.hbs @@ -1,6 +1,6 @@ {{#if ready}} - {{paper-icon icon="menu"}} + {{paper-icon icon="group"}} {{controls/group-control lightsData=lightsData groupsData=groupsData activeLights=activeLights apiURL=apiURL updateGroupsData=updateGroupsData groupControlDisplayed=groupControlDisplayed}} diff --git a/app/templates/components/controls/light-control.hbs b/app/templates/components/controls/light-control.hbs index 288ba8a..db58a85 100644 --- a/app/templates/components/controls/light-control.hbs +++ b/app/templates/components/controls/light-control.hbs @@ -1,6 +1,6 @@ {{#paper-list}} {{#paper-item class="item"}} - {{light-group lightsData=lightsData activeLights=activeLights action='clickLight' apiURL=apiURL}} + {{light-group lightsData=lightsData activeLights=activeLights action='clickLight' apiURL=apiURL classNames="horizontalLightGroup"}} {{/paper-item}} {{#paper-item class="item"}} @@ -15,11 +15,15 @@ {{paper-slider flex=true min='1' max='254' value=lightsBrightness disabled=brightnessControlDisabled}} {{/paper-item}} + {{#paper-item class="item"}} + {{paper-icon icon="color-lens"}} +

Color

+ + {{/paper-item}} + {{#paper-item class="item"}} {{paper-icon icon="flare"}}

Strobe

{{#paper-switch checked=strobeOn disabled=trial}} {{strobeOnTxt}} {{/paper-switch}} {{/paper-item}} - - {{modals/light-control-modal modalData=modalData apiURL=apiURL action="clickLight" isShowingLightsModal=isShowingLightsModal}} {{/paper-list}} \ No newline at end of file diff --git a/app/templates/components/controls/music-control.hbs b/app/templates/components/controls/music-control.hbs index 0dae7f3..34aba5e 100644 --- a/app/templates/components/controls/music-control.hbs +++ b/app/templates/components/controls/music-control.hbs @@ -58,13 +58,12 @@ -
- +
{{light-group lightsData=lightsData activeLights=activeLights action='clickLight' apiURL=apiURL noHover=true}} - +
{{range-slider start=threshold orientation="vertical" range=beatOptions.threshold.range slide="thresholdChanged" pips=beatOptions.threshold.pips}} Max. Beat Intensity @@ -79,14 +78,14 @@ {{range-slider start=frequency orientation="vertical" step=beatOptions.frequency.step range=beatOptions.frequency.range connect=true slide="frequencyChanged" pips=beatOptions.frequency.pips}} Beat Frequency Range - +
{{#paper-button raised=true warn=true action="defaultControls"}}Default{{/paper-button}}
- + {{#paper-switch checked=speakerViewed noink=true}} {{speakerLabel}} {{/paper-switch}} {{#liquid-if speakerViewed}}
diff --git a/app/templates/components/modals/light-control-modal.hbs b/app/templates/components/modals/light-control-modal.hbs deleted file mode 100644 index ed24538..0000000 --- a/app/templates/components/modals/light-control-modal.hbs +++ /dev/null @@ -1,8 +0,0 @@ -{{#if isShowingLightsModal}} - {{#modal-dialog close="close" - alignment="center" - translucentOverlay=true}} - TODO - - {{/modal-dialog}} -{{/if}} \ No newline at end of file diff --git a/bower.json b/bower.json index e0ecec9..fbb7978 100644 --- a/bower.json +++ b/bower.json @@ -2,6 +2,7 @@ "name": "huegasm", "dependencies": { "bootstrap-sass": "~3.3.5", + "colorspaces.js": "https://github.com/boronine/colorspaces.js.git#~0.1.4", "ember": "~2.0.2", "ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3", "ember-cli-test-loader": "ember-cli-test-loader#0.1.3", @@ -11,12 +12,14 @@ "ember-qunit-notifications": "0.0.7", "ember-resolver": "~0.1.18", "hammerjs": "~2.0.4", + "hue-color-converter": "https://github.com/Q42/hue-color-converter", "JavaScript-ID3-Reader": "https://github.com/aadsm/JavaScript-ID3-Reader.git", "jquery": "~2.1.4", "jquery-mousewheel": "~3.1.13", "loader.js": "ember-cli/loader.js#3.2.0", "nouislider": "^8.0.1", - "qunit": "~1.18.0" + "qunit": "~1.18.0", + "tinyColorPicker": "https://github.com/PitPik/tinyColorPicker.git" }, "resolutions": { "ember": "~2.0.2", diff --git a/ember-cli-build.js b/ember-cli-build.js index 0994cce..94e32be 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -10,6 +10,9 @@ module.exports = function(defaults) { app.import('bower_components/bootstrap-sass/assets/javascripts/bootstrap/tooltip.js'); app.import('bower_components/JavaScript-ID3-Reader/dist/id3-minimized.js'); app.import('bower_components/jquery-mousewheel/jquery.mousewheel.js'); + app.import('bower_components/tinyColorPicker/colors.js'); + app.import('bower_components/tinyColorPicker/jqColorPicker.js'); + app.import('bower_components/colorspaces.js/colorspaces.js'); // Use `app.import` to add additional libraries to the generated // output files. diff --git a/tests/integration/components/modals/light-control-modal-test.js b/tests/integration/components/modals/light-control-modal-test.js deleted file mode 100644 index b33b3db..0000000 --- a/tests/integration/components/modals/light-control-modal-test.js +++ /dev/null @@ -1,26 +0,0 @@ -import { moduleForComponent, test } from 'ember-qunit'; -import hbs from 'htmlbars-inline-precompile'; - -moduleForComponent('modals/light-control-modal', 'Integration | Component | modals/light control modal', { - integration: true -}); - -test('it renders', function(assert) { - assert.expect(2); - - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.on('myAction', function(val) { ... }); - - this.render(hbs`{{modals/light-control-modal}}`); - - assert.equal(this.$().text().trim(), ''); - - // Template block usage: - this.render(hbs` - {{#modals/light-control-modal}} - template block text - {{/modals/light-control-modal}} - `); - - assert.equal(this.$().text().trim(), 'template block text'); -}); diff --git a/vendor/dancer.js b/vendor/dancer.js index 164de84..875d14a 100644 --- a/vendor/dancer.js +++ b/vendor/dancer.js @@ -476,7 +476,12 @@ }; function connectContext () { - this.source = this.context.createMediaElementSource( this.audio ); + try{ + this.source = this.context.createMediaElementSource( this.audio ); + } catch(err){ + return; + } + this.source.connect( this.proc ); this.source.connect( this.gain ); //this.source.connect( this.filter );