Groundwork for crossfading now playing artwork; Initial Setup pre-fill from queryParams
This commit is contained in:
@ -16,7 +16,7 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="#121212" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="#121212" />
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
<meta name="theme-color" content="#222222" />
|
<meta name="theme-color" content="#222222" />
|
||||||
|
|
||||||
<!-- Icons -->
|
<!-- Icons -->
|
||||||
<link rel="apple-touch-startup-image" href="/iris/assets/app-icon_512.png" />
|
<link rel="apple-touch-startup-image" href="/iris/assets/app-icon_512.png" />
|
||||||
<link rel="apple-touch-icon" sizes="192x192" href="/iris/assets/app-icon_192.png" />
|
<link rel="apple-touch-icon" sizes="192x192" href="/iris/assets/app-icon_192.png" />
|
||||||
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
<!-- Loading screen styles -->
|
<!-- Loading screen styles -->
|
||||||
<style>
|
<style>
|
||||||
html {
|
html {
|
||||||
background-color: #121212;
|
background-color: #121212;
|
||||||
}
|
}
|
||||||
@keyframes loader {
|
@keyframes loader {
|
||||||
@ -52,7 +52,7 @@
|
|||||||
#app-loading::before {
|
#app-loading::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: block;
|
display: block;
|
||||||
content: '';
|
content: '';
|
||||||
height: 100%;
|
height: 100%;
|
||||||
animation-name: loader;
|
animation-name: loader;
|
||||||
background: #444444;
|
background: #444444;
|
||||||
@ -104,17 +104,22 @@
|
|||||||
var version = "VERSION_HERE";
|
var version = "VERSION_HERE";
|
||||||
|
|
||||||
// Construct the script tag
|
// Construct the script tag
|
||||||
var js = document.createElement("script");
|
var js = document.createElement("script");
|
||||||
js.type = "application/javascript";
|
js.type = "application/javascript";
|
||||||
|
|
||||||
// Construct our css tag
|
// Construct our css tag
|
||||||
var css = document.createElement("link");
|
var css = document.createElement("link");
|
||||||
css.rel = "stylesheet";
|
css.rel = "stylesheet";
|
||||||
|
|
||||||
// Check for test mode. This is toggled under Settings > Debug > Test mode
|
// Check for test mode. This is toggled under Settings > Debug > Test mode
|
||||||
try {
|
try {
|
||||||
var ui = JSON.parse(localStorage.getItem('ui') );
|
var ui = JSON.parse(localStorage.getItem('ui') );
|
||||||
var test_mode = (typeof(ui) !== 'undefined' && ui && typeof(ui.test_mode) !== 'undefined' && ui.test_mode);
|
var test_mode = (
|
||||||
|
typeof(ui) !== 'undefined'
|
||||||
|
&& ui
|
||||||
|
&& typeof(ui.test_mode) !== 'undefined'
|
||||||
|
&& ui.test_mode
|
||||||
|
);
|
||||||
} catch(error){
|
} catch(error){
|
||||||
console.error(error);
|
console.error(error);
|
||||||
var test_mode = false;
|
var test_mode = false;
|
||||||
|
|||||||
@ -77,10 +77,7 @@ export class App extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const {
|
const {
|
||||||
location: {
|
|
||||||
search,
|
|
||||||
},
|
|
||||||
history,
|
history,
|
||||||
snapcast_enabled,
|
snapcast_enabled,
|
||||||
allow_reporting,
|
allow_reporting,
|
||||||
@ -111,20 +108,7 @@ export class App extends React.Component {
|
|||||||
}
|
}
|
||||||
coreActions.getBroadcasts();
|
coreActions.getBroadcasts();
|
||||||
|
|
||||||
// Check for url-parsed configuration values
|
if (!initial_setup_complete) {
|
||||||
const customHost = helpers.queryString('host', search);
|
|
||||||
const customPort = helpers.queryString('port', search);
|
|
||||||
if (customHost && customPort) {
|
|
||||||
mopidyActions.set({ host: customHost, port: customPort });
|
|
||||||
uiActions.set({ initial_setup_complete: true });
|
|
||||||
|
|
||||||
// Allow 100ms for the action above to complete before we re-route
|
|
||||||
setTimeout(() => {
|
|
||||||
history.push('/');
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
// Just show default initial setup for fresh installs
|
|
||||||
} else if (!initial_setup_complete) {
|
|
||||||
history.push('/initial-setup');
|
history.push('/initial-setup');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ export default class Parallax extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
loaded: false,
|
loaded: false,
|
||||||
url: null,
|
url: null,
|
||||||
|
outgoingUrl: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ export default class Parallax extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (nextProps.image != this.state.url) {
|
if (nextProps.image !== this.state.url) {
|
||||||
this.loadImage(nextProps.image);
|
this.loadImage(nextProps.image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,26 +54,26 @@ export default class Parallax extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let class_name = 'parallax preserve-3d';
|
const {
|
||||||
if (this.props.blur) {
|
blur,
|
||||||
class_name += ' parallax--blur';
|
fixedHeight,
|
||||||
}
|
animate = true,
|
||||||
if (this.state.loaded) {
|
} = this.props;
|
||||||
class_name += ' parallax--loaded';
|
const {
|
||||||
}
|
loaded,
|
||||||
if (this.props.fixedHeight) {
|
url,
|
||||||
class_name += ' parallax--fixed-height';
|
} = this.state;
|
||||||
} else {
|
|
||||||
class_name += ' parallax--flexible-height';
|
|
||||||
}
|
|
||||||
|
|
||||||
let style = {};
|
let className = 'parallax preserve-3d';
|
||||||
if (this.state.loaded && this.state.url) {
|
className += ` parallax--${fixedHeight ? 'fixed' : 'flexible'}-height`;
|
||||||
style = { backgroundImage: `url("${this.state.url}")` };
|
if (blur) className += ' parallax--blur';
|
||||||
}
|
if (loaded) className += ' parallax--loaded';
|
||||||
|
if (animate) className += ' parallax--animate';
|
||||||
|
|
||||||
|
const style = loaded && url ? { backgroundImage: `url("${url}")` } : {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={class_name}>
|
<div className={className}>
|
||||||
<div className="parallax__layer preserve-3d">
|
<div className="parallax__layer preserve-3d">
|
||||||
<div className="parallax__image" style={style} />
|
<div className="parallax__image" style={style} />
|
||||||
<div className="parallax__overlay" />
|
<div className="parallax__overlay" />
|
||||||
|
|||||||
@ -233,7 +233,7 @@ class Queue extends React.Component {
|
|||||||
<Icon name="play_arrow" type="material" />
|
<Icon name="play_arrow" type="material" />
|
||||||
Now playing
|
Now playing
|
||||||
</Header>
|
</Header>
|
||||||
<Parallax blur image={current_track_image} />
|
<Parallax image={current_track_image} blur />
|
||||||
<div className="content-wrapper">
|
<div className="content-wrapper">
|
||||||
<div className="current-track">
|
<div className="current-track">
|
||||||
{this.renderArtwork(current_track_image)}
|
{this.renderArtwork(current_track_image)}
|
||||||
|
|||||||
@ -15,16 +15,35 @@ class InitialSetup extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
const {
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
username,
|
||||||
|
allow_reporting,
|
||||||
|
} = props;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
username: this.props.username,
|
username,
|
||||||
allow_reporting: this.props.allow_reporting,
|
allow_reporting,
|
||||||
host: this.props.host,
|
host,
|
||||||
port: this.props.port,
|
port,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.uiActions.setWindowTitle('Welcome to Iris');
|
const {
|
||||||
|
location: {
|
||||||
|
search,
|
||||||
|
},
|
||||||
|
uiActions,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
// Check for url-parsed configuration values
|
||||||
|
const customHost = helpers.queryString('host', search);
|
||||||
|
const customPort = helpers.queryString('port', search);
|
||||||
|
|
||||||
|
this.setState({ host: customHost, port: customPort });
|
||||||
|
uiActions.setWindowTitle('Welcome to Iris');
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(e) {
|
handleSubmit(e) {
|
||||||
@ -49,7 +68,7 @@ class InitialSetup extends React.Component {
|
|||||||
this.setState({ saving: true });
|
this.setState({ saving: true });
|
||||||
|
|
||||||
// Wait a jiffy to allow changes to apply to store
|
// Wait a jiffy to allow changes to apply to store
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// We've changed a connection setting, so need to reload
|
// We've changed a connection setting, so need to reload
|
||||||
if (self.state.host !== self.props.host || self.state.port !== self.props.port) {
|
if (self.state.host !== self.props.host || self.state.port !== self.props.port) {
|
||||||
window.location = '/';
|
window.location = '/';
|
||||||
@ -78,7 +97,7 @@ class InitialSetup extends React.Component {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
onChange={(e) => this.setState({ username: e.target.value.replace(/\W/g, '') })}
|
onChange={(e) => this.setState({ username: e.target.value.replace(/\W/g, '') })}
|
||||||
value={this.state.username}
|
value={this.state.username}
|
||||||
/>
|
/>
|
||||||
<div className="description">
|
<div className="description">
|
||||||
A non-unique string used to identify this client (no special characters)
|
A non-unique string used to identify this client (no special characters)
|
||||||
@ -92,7 +111,7 @@ class InitialSetup extends React.Component {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
onChange={(e) => this.setState({ host: e.target.value })}
|
onChange={(e) => this.setState({ host: e.target.value })}
|
||||||
value={this.state.host}
|
value={this.state.host}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -102,12 +121,12 @@ class InitialSetup extends React.Component {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
onChange={(e) => this.setState({ port: e.target.value })}
|
onChange={(e) => this.setState({ port: e.target.value })}
|
||||||
value={this.state.port}
|
value={this.state.port}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{helpers.isHosted() ? null : (
|
{helpers.isHosted() ? null : (
|
||||||
<div className="field checkbox">
|
<div className="field checkbox">
|
||||||
<div className="input">
|
<div className="input">
|
||||||
<label>
|
<label>
|
||||||
@ -115,21 +134,21 @@ class InitialSetup extends React.Component {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
name="allow_reporting"
|
name="allow_reporting"
|
||||||
checked={this.state.allow_reporting}
|
checked={this.state.allow_reporting}
|
||||||
onChange={(e) => this.setState({ allow_reporting: !this.state.allow_reporting })}
|
onChange={(e) => this.setState({ allow_reporting: !this.state.allow_reporting })}
|
||||||
/>
|
/>
|
||||||
<span className="label">
|
<span className="label">
|
||||||
Allow reporting of anonymous usage statistics
|
Allow reporting of anonymous usage statistics
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<p className="description">
|
<p className="description">
|
||||||
This anonymous usage data is important in identifying errors and potential features that make Iris better for everyone. Want to know more? Read the
|
This anonymous usage data is important in identifying errors and potential features that make Iris better for everyone. Want to know more? Read the
|
||||||
<a href="https://github.com/jaedb/Iris/wiki/Terms-of-use#privacy-policy" target="_blank">privacy policy</a>
|
<a href="https://github.com/jaedb/Iris/wiki/Terms-of-use#privacy-policy" target="_blank">privacy policy</a>
|
||||||
{!this.state.allow_reporting ? <span className="red-text"> Are you sure you don't want to support this?</span> : null}
|
{!this.state.allow_reporting ? <span className="red-text"> Are you sure you don't want to support this?</span> : null}
|
||||||
.
|
.
|
||||||
{' '}
|
{' '}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="actions centered-text">
|
<div className="actions centered-text">
|
||||||
@ -158,4 +177,4 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(InitialSetup);
|
export default connect(mapStateToProps, mapDispatchToProps)(InitialSetup);
|
||||||
|
|||||||
@ -27,7 +27,6 @@ $parallax: 'parallax';
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__image {
|
&__image {
|
||||||
@include animate(0.5s);
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10px;
|
top: -10px;
|
||||||
left: -10px;
|
left: -10px;
|
||||||
@ -40,6 +39,12 @@ $parallax: 'parallax';
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--animate {
|
||||||
|
.#{$parallax}__image {
|
||||||
|
@include animate(0.5s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__overlay {
|
&__overlay {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
Reference in New Issue
Block a user