working on the music controls
This commit is contained in:
parent
eb518c4898
commit
b2eb2ede21
22 changed files with 534 additions and 305 deletions
|
|
@ -2,7 +2,8 @@
|
|||
"predef": [
|
||||
"document",
|
||||
"window",
|
||||
"-Promise"
|
||||
"-Promise",
|
||||
"Dancer"
|
||||
],
|
||||
"browser": true,
|
||||
"boss": true,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ export default Em.Component.extend({
|
|||
updateGroupsData: true,
|
||||
groupsData: null,
|
||||
lightsData: null,
|
||||
activeLights: Em.A(),
|
||||
|
||||
activeLights: [],
|
||||
|
||||
apiURL: function(){
|
||||
return 'http://' + this.get('bridgeIp') + '/api/' + this.get('bridgeUsername');
|
||||
|
|
@ -41,7 +42,7 @@ export default Em.Component.extend({
|
|||
},
|
||||
|
||||
tabList: ["Lights", "Scenes", "Music"],
|
||||
selectedTab: 0,
|
||||
selectedTab: 2,
|
||||
tabData: function(){
|
||||
var tabData = [], selectedTab = this.get('selectedTab');
|
||||
|
||||
|
|
@ -73,16 +74,6 @@ export default Em.Component.extend({
|
|||
|
||||
Em.$.get(this.get('apiURL') + '/lights', function (result, status) {
|
||||
if (status === 'success' && JSON.stringify(self.get('lightsData')) !== JSON.stringify(result) ) {
|
||||
if(self.get('activeLights').length === 0){
|
||||
var ids = [];
|
||||
for (let key in result) {
|
||||
if(result.hasOwnProperty(key) && result[key].state.reachable){
|
||||
ids.push(key);
|
||||
}
|
||||
}
|
||||
self.set('activeLights', ids);
|
||||
}
|
||||
|
||||
self.set('lightsData', result);
|
||||
} else if(status !== 'success') {
|
||||
// something went terribly wrong ( user got unauthenticated? ) and we'll need to start all over
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export default Em.Component.extend({
|
|||
|
||||
tagName: null,
|
||||
|
||||
groupIdSelection: '0',
|
||||
groupIdSelection: null,
|
||||
|
||||
actions: {
|
||||
selectGroup: function(selection){
|
||||
|
|
@ -58,8 +58,20 @@ export default Em.Component.extend({
|
|||
}
|
||||
});
|
||||
|
||||
if(!Em.isNone(groupIdSelection)){
|
||||
localStorage.setItem('huegasm.selectedGroup', groupIdSelection);
|
||||
|
||||
if(!Em.isNone(groupIdSelection) && !Em.isEmpty(lights)){
|
||||
this.set('activeLights', lights);
|
||||
}
|
||||
}.observes('groupIdSelection')
|
||||
}.observes('groupIdSelection', 'groupsArrData'),
|
||||
|
||||
didInsertElement: function(){
|
||||
var selectGroup = '0', storageItem = localStorage.getItem('huegasm.selectedGroup');
|
||||
|
||||
if(storageItem){
|
||||
selectGroup = storageItem;
|
||||
}
|
||||
|
||||
this.set('groupIdSelection', selectGroup);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,13 +4,16 @@ export default Em.Component.extend({
|
|||
|
||||
classNames: ['innerControlFrame'],
|
||||
|
||||
activeLights: [],
|
||||
lightsData: null,
|
||||
|
||||
lightsDataIntervalHandle: null,
|
||||
|
||||
modalData: null,
|
||||
isShowingLightsModal: false,
|
||||
isShowingAddGroupsModal: false,
|
||||
actions: {
|
||||
selectLight: function(id, data){
|
||||
clickLight: function(id, data){
|
||||
if(this.get('isShowingLightsModal')){
|
||||
this.set('modalData', {data:data, id:id});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,54 @@
|
|||
import Em from 'ember';
|
||||
|
||||
export default Em.Component.extend({
|
||||
|
||||
apiURL: null,
|
||||
|
||||
|
||||
|
||||
lightsData: null,
|
||||
activeLights: null,
|
||||
|
||||
|
||||
didInsertElement: function () {
|
||||
var dancer = new Dancer(),
|
||||
self = this,
|
||||
briOff = function(i){
|
||||
Em.$.ajax(self.get('apiURL') + '/lights/' + i + '/state', {
|
||||
data: JSON.stringify({'on': 1, 'transitiontime': 0}),
|
||||
contentType: 'application/json',
|
||||
type: 'PUT'
|
||||
});
|
||||
},
|
||||
kick = dancer.createKick({
|
||||
threshold : 0.45,
|
||||
frequency: [0, 3],
|
||||
onKick: function ( mag ) {
|
||||
|
||||
if(self.get('paused') === false){
|
||||
for(let i=1; i <= 1; i++){
|
||||
Em.$.ajax(self.get('apiURL') + '/lights/' + i + '/state', {
|
||||
data: JSON.stringify({'bri': 254, 'transitiontime': 0}),
|
||||
contentType: 'application/json',
|
||||
type: 'PUT'
|
||||
});
|
||||
|
||||
setTimeout(briOff, 50, i);
|
||||
}
|
||||
|
||||
self.set('paused', true);
|
||||
|
||||
setTimeout(function(){ self.set('paused', false); }, 150);
|
||||
|
||||
console.log('Kick at ' + mag);
|
||||
}
|
||||
|
||||
}
|
||||
}),
|
||||
a = new Audio();
|
||||
|
||||
kick.on();
|
||||
|
||||
audio_file.onchange = function(){
|
||||
var files = this.files;
|
||||
var file = URL.createObjectURL(files[0]);
|
||||
a.src = file;
|
||||
dancer.load(a);
|
||||
|
||||
dancer.play();
|
||||
};
|
||||
},
|
||||
|
||||
paused: false
|
||||
});
|
||||
|
|
|
|||
27
app/components/controls/music-control/music-player.js
Normal file
27
app/components/controls/music-control/music-player.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import Em from 'ember';
|
||||
|
||||
export default Em.Component.extend({
|
||||
classNames: ['container-fluid'],
|
||||
|
||||
actions: {
|
||||
play: function(){
|
||||
|
||||
},
|
||||
next : function(){
|
||||
|
||||
},
|
||||
previous: function(){
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
status: null,
|
||||
|
||||
playButton: function(){
|
||||
if(this.get('status') === 'paused'){
|
||||
return 'pause';
|
||||
} else {
|
||||
return 'play-arrow';
|
||||
}
|
||||
}.property('status')
|
||||
});
|
||||
|
|
@ -7,6 +7,7 @@ export default Em.Component.extend({
|
|||
|
||||
init: function(){
|
||||
this._super();
|
||||
|
||||
if(localStorage.getItem('huegasm.bridgeIp')){
|
||||
this.set('bridgeIp', localStorage.getItem('huegasm.bridgeIp'));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,13 @@ export default Em.Component.extend({
|
|||
selectedLights: [],
|
||||
|
||||
onIsShowingAddGroupsModalChange: function(){
|
||||
this.set('selectedLights', []);
|
||||
if(this.get('isShowingAddGroupsModal')){
|
||||
|
||||
}
|
||||
this.setProperties({
|
||||
selectedLights: [],
|
||||
groupName: null
|
||||
});
|
||||
}.observes('isShowingAddGroupsModal'),
|
||||
|
||||
saveDisabled: function(){
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ export default Em.Component.extend({
|
|||
this.sendAction();
|
||||
},
|
||||
delete: function(){
|
||||
Em.$.ajax(this.get('apiURL') + '/groups/' + this.get('groupId'), {
|
||||
var groupId = this.get('groupId');
|
||||
|
||||
Em.$.ajax(this.get('apiURL') + '/groups/' + groupId, {
|
||||
contentType: 'application/json',
|
||||
type: 'DELETE'
|
||||
});
|
||||
|
|
@ -18,6 +20,10 @@ export default Em.Component.extend({
|
|||
}
|
||||
}
|
||||
|
||||
if(groupId === this.get('groupIdSelection')){
|
||||
this.set('groupIdSelection', '0');
|
||||
}
|
||||
|
||||
this.setProperties({
|
||||
updateGroupsData: true,
|
||||
groupsData: newGroupsData
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
{{content-for 'head'}}
|
||||
|
||||
<link href='http://fonts.googleapis.com/css?family=Slabo+27px' rel='stylesheet' type='text/css'>
|
||||
<link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="shortcut icon" href="assets/images/favicon.ico" type="image/x-icon" />
|
||||
|
||||
<link rel="stylesheet" href="assets/vendor.css">
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ var Router = Ember.Router.extend({
|
|||
});
|
||||
|
||||
Router.map(function() {
|
||||
this.route('404', {path:'/*path'});
|
||||
});
|
||||
|
||||
export default Router;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
@import 'ember-modal-dialog/ember-modal-structure';
|
||||
@import 'ember-modal-dialog/ember-modal-appearance';
|
||||
|
||||
body, html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// BRIDGE FINDER
|
||||
#pressButtonBridgeImg {
|
||||
width: 200px;
|
||||
margin: 0 auto 0 auto;
|
||||
|
|
@ -17,10 +14,43 @@ body, html {
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
md-list {
|
||||
md-content {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
// BRIDGE CONTROLS
|
||||
.navigation {
|
||||
margin: 0 auto 0 auto;
|
||||
padding: 30px 0 30px 0;
|
||||
}
|
||||
|
||||
.navigationItem {
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
font-family: 'Slabo 27px', serif;
|
||||
font-size: 18px;
|
||||
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;
|
||||
}
|
||||
|
||||
// LIGHT GROUP
|
||||
.lightGroup {
|
||||
margin: 0 auto 0 auto;
|
||||
}
|
||||
|
||||
.hueLight {
|
||||
margin-right: 10px;
|
||||
border-radius: 20px;
|
||||
|
|
@ -54,7 +84,7 @@ md-icon {
|
|||
}
|
||||
|
||||
md-icon.menu {
|
||||
margin: 10px 16px 0 0;
|
||||
margin: 30px 0 0 16px;
|
||||
}
|
||||
|
||||
.addButton {
|
||||
|
|
@ -70,6 +100,7 @@ md-icon.menu {
|
|||
|
||||
.sideNavTitle {
|
||||
margin-left: 16px;
|
||||
font-family: 'Slabo 27px', serif;
|
||||
}
|
||||
|
||||
md-toolbar {
|
||||
|
|
@ -77,20 +108,85 @@ md-toolbar {
|
|||
}
|
||||
|
||||
.innerControlFrame {
|
||||
background-color: mintcream;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
// GROUP CONTROL
|
||||
.groupRow.selectedRow {
|
||||
background-color: lightgrey !important;
|
||||
background-color: #7F7F7F !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.groupRow:hover {
|
||||
background-color: #E6E6E6;
|
||||
background-color: #c3c3c3;
|
||||
}
|
||||
|
||||
.groupRow.selectedRow .groupSelect {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.groupSelect {
|
||||
padding: 10px 0 10px 0;
|
||||
cursor: pointer;
|
||||
width: 70%;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
}
|
||||
|
||||
.groupRow:hover * .close {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.groupRow:hover * .close {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.selectedRow * .close {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.selectedRow.groupRow * .close:hover {
|
||||
color: darken(white, 20%) !important;
|
||||
}
|
||||
|
||||
.groupRow * .close:hover {
|
||||
color: darken(#333333, 20%) !important;
|
||||
}
|
||||
|
||||
.close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: rgb(51, 51, 51);
|
||||
display: none;
|
||||
opacity: 1;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
// MUSIC CONTROL
|
||||
#playListContainer {
|
||||
height: 600px;
|
||||
width: 200px;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.playerControllIcon {
|
||||
color: white !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.playerControllIcon:hover {
|
||||
color: darken(white, 20%) !important;
|
||||
}
|
||||
|
||||
#playerArea {
|
||||
height: 200px;
|
||||
background-color: black;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#playlist {
|
||||
height: 200px;
|
||||
background-color: grey;
|
||||
display: inline-block;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,22 @@
|
|||
{{#liquid-if lightsData}}
|
||||
|
||||
{{#paper-nav-container open=drawerOpen class="ember-app"}}
|
||||
|
||||
{{#paper-sidenav class="md-sidenav-left md-whiteframe-z2" flex-layout="column" flex=true}}
|
||||
|
||||
{{controls/group-control lightsData=lightsData groupsData=groupsData activeLights=activeLights apiURL=apiURL updateGroupsData=updateGroupsData}}
|
||||
{{/paper-sidenav}}
|
||||
|
||||
{{#paper-sidenav-toggle class="menu-sidenav-toggle"}}
|
||||
{{paper-icon icon="menu" size="lg"}}
|
||||
{{/paper-sidenav-toggle}}
|
||||
|
||||
{{#paper-content flex-layout="column" flex=true}}
|
||||
<ul class="nav nav-tabs">
|
||||
<div class="navigation">
|
||||
{{#each tabData as |tab|}}
|
||||
<li role="presentation" class="{{if tab.selected "active" ""}}"><a
|
||||
href="#" {{action "changeTab" tab.name}}>{{tab.name}}</a></li>
|
||||
<span class="navigationItem {{if tab.selected "active" ""}}" {{action "changeTab" tab.name}}>{{tab.name}}</span>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{{#liquid-if lightsTabSelected class="tabSwitch"}}
|
||||
{{controls/light-control apiURL=apiURL lightsData=lightsData activeLights=activeLights}}
|
||||
|
|
@ -18,13 +29,9 @@
|
|||
{{#liquid-if musicTabSelected class="tabSwitch"}}
|
||||
{{controls/music-control apiURL=apiURL lightsData=lightsData activeLights=activeLights}}
|
||||
{{/liquid-if}}
|
||||
|
||||
{{/paper-content}}
|
||||
|
||||
{{#paper-sidenav-toggle class="menu-sidenav-toggle"}}
|
||||
{{paper-icon icon="menu" size="lg"}}
|
||||
{{/paper-sidenav-toggle}}
|
||||
|
||||
{{#paper-sidenav class="md-sidenav-right md-whiteframe-z2" flex-layout="column" flex=true}}
|
||||
{{controls/group-control lightsData=lightsData groupsData=groupsData activeLights=activeLights apiURL=apiURL updateGroupsData=updateGroupsData}}
|
||||
{{/paper-sidenav}}
|
||||
{{/paper-nav-container}}
|
||||
|
||||
{{/liquid-if}}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
{{#paper-list}}
|
||||
{{#each groupsArrData as |group|}}
|
||||
{{#paper-item class=group.rowClass}}
|
||||
<div class="groupSelect" {{action "selectGroup" group.data.key}}>{{group.name}}</div> {{#if group.deletable}}<span title="Remove Group" class="removeButton" {{action "toggleConfirmDeleteGroupsModal" group.name group.data.key}}>{{paper-icon icon="remove"}}</span>{{/if}}
|
||||
<div class="groupSelect" {{action "selectGroup" group.data.key}}>{{group.name}}</div> {{#if group.deletable}}<span title="Remove Group" class="removeButton" {{action "toggleConfirmDeleteGroupsModal" group.name group.data.key}}>{{paper-icon icon="close"}}</span>{{/if}}
|
||||
{{/paper-item}}
|
||||
{{/each}}
|
||||
{{/paper-list}}
|
||||
|
|
@ -13,4 +13,4 @@
|
|||
{{modals/add-group-modal lightsData=lightsData groupsData=groupsData isShowingAddGroupsModal=isShowingAddGroupsModal apiURL=apiURL updateGroupsData=updateGroupsData
|
||||
action="toggleAddGroupsModal"}}
|
||||
|
||||
{{modals/confirm-delete-modal groupName=deleteGroupName groupId=deleteGroupId groupsData=groupsData isShowingConfirmDeleteModal=isShowingConfirmDeleteModal apiURL=apiURL updateGroupsData=updateGroupsData action="toggleConfirmDeleteGroupsModal"}}
|
||||
{{modals/confirm-delete-modal groupName=deleteGroupName groupId=deleteGroupId groupsData=groupsData isShowingConfirmDeleteModal=isShowingConfirmDeleteModal apiURL=apiURL updateGroupsData=updateGroupsData groupIdSelection=groupIdSelection action="toggleConfirmDeleteGroupsModal"}}
|
||||
|
|
@ -22,6 +22,6 @@
|
|||
{{#paper-switch checked=strobeOn}} {{strobeOnTxt}} {{/paper-switch}}
|
||||
{{/paper-item}}
|
||||
|
||||
{{modals/light-control-modal modalData=modalData apiURL=apiURL action="selectLight" isShowingLightsModal=isShowingLightsModal}}
|
||||
{{modals/light-control-modal modalData=modalData apiURL=apiURL action="clickLight" isShowingLightsModal=isShowingLightsModal}}
|
||||
|
||||
{{/paper-list}}
|
||||
|
|
@ -1,9 +1 @@
|
|||
{{#paper-list}}
|
||||
|
||||
{{#paper-item class="item"}}
|
||||
{{paper-icon icon="music-note"}}
|
||||
<p>Music</p>
|
||||
{{#paper-button raised=true primary=true}}UPLOAD{{/paper-button}}
|
||||
{{/paper-item}}
|
||||
|
||||
{{/paper-list}}
|
||||
{{controls/music-control/music-player}}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<div class="row">
|
||||
<div id="playerArea" class="col-lg-8 col-xs-12">
|
||||
|
||||
<div id="playerControls">
|
||||
{{paper-icon icon="skip-previous" action="previous" class="playerControllIcon"}}
|
||||
{{paper-icon icon=playButton action="play" class="playerControllIcon"}}
|
||||
{{paper-icon icon="skip-next" action="pause" class="playerControllIcon"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="playlist" class="col-lg-4 col-xs-12">
|
||||
<input id="audio_file" type="file" accept="audio/*" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
export default function(){
|
||||
this.transition(
|
||||
this.hasClass('tabSwitch'),
|
||||
this.use('crossFade')
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ module.exports = function(environment) {
|
|||
'connect-src': "'self' *",
|
||||
'img-src': "'self' data:",
|
||||
'media-src': "'self'",
|
||||
'style-src': "'self' 'unsafe-inline'",
|
||||
'style-src': "'self' 'unsafe-inline' fonts.googleapis.com",
|
||||
'object-src': "'self'",
|
||||
'frame-src': "'self'"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ module.exports = function(defaults) {
|
|||
// Add options here
|
||||
});
|
||||
|
||||
app.import('bower_components/bootstrap-sass/assets/javascripts/bootstrap/collapse.js');
|
||||
|
||||
app.import('vendor/dancer.js');
|
||||
// Use `app.import` to add additional libraries to the generated
|
||||
// output files.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('controls/music-control/music-player', 'Integration | Component | controls/music control/music player', {
|
||||
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`{{controls/music-control/music-player}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#controls/music-control/music-player}}
|
||||
template block text
|
||||
{{/controls/music-control/music-player}}
|
||||
`);
|
||||
|
||||
assert.equal(this.$().text().trim(), 'template block text');
|
||||
});
|
||||
18
vendor/dancer.js
vendored
18
vendor/dancer.js
vendored
|
|
@ -189,7 +189,7 @@
|
|||
|
||||
function update () {
|
||||
for (var i in this.sections) {
|
||||
if ( this.sections[ i ].condition() )
|
||||
if (this.sections[i].condition && this.sections[i].condition() )
|
||||
this.sections[i].callback.call(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -342,9 +342,7 @@
|
|||
}
|
||||
},
|
||||
maxAmplitude : function ( frequency ) {
|
||||
var
|
||||
max = 0,
|
||||
fft = this.dancer.getSpectrum();
|
||||
var max = 0, fft = this.dancer.getSpectrum();
|
||||
|
||||
// Sloppy array check
|
||||
if ( !frequency.length ) {
|
||||
|
|
@ -369,11 +367,15 @@
|
|||
SAMPLE_RATE = 44100;
|
||||
|
||||
var adapter = function ( dancer ) {
|
||||
var context = new AudioContext(), filter = context.createBiquadFilter();
|
||||
|
||||
filter.type = "lowpass";
|
||||
filter.frequency.value = 440;
|
||||
|
||||
this.dancer = dancer;
|
||||
this.audio = new Audio();
|
||||
this.context = window.AudioContext ?
|
||||
new window.AudioContext() :
|
||||
new window.webkitAudioContext();
|
||||
this.context = context;
|
||||
this.filter = filter;
|
||||
};
|
||||
|
||||
adapter.prototype = {
|
||||
|
|
@ -477,8 +479,10 @@
|
|||
this.source = this.context.createMediaElementSource( this.audio );
|
||||
this.source.connect( this.proc );
|
||||
this.source.connect( this.gain );
|
||||
//this.source.connect( this.filter );
|
||||
this.gain.connect( this.context.destination );
|
||||
this.proc.connect( this.context.destination );
|
||||
//this.filter.connect( this.context.destination );
|
||||
|
||||
this.isLoaded = true;
|
||||
this.progress = 1;
|
||||
|
|
|
|||
Reference in a new issue