Use different wallpaper collection, dedupe images, add loading spinner

main
Jake Dexheimer 7 years ago committed by Michael Fix
parent f79d01ad9b
commit 400a42bf77

@ -120,7 +120,9 @@ export default class extends React.Component {
</div> </div>
<hr /> <hr />
<div className="random-image"> <div className="random-image">
<span>Or use a random unsplash image:</span> <span>
Or use a random <a href="https://unsplash.com/">Unsplash</a> image:
</span>
<RandomImage onChange={this.selectImage} /> <RandomImage onChange={this.selectImage} />
</div> </div>
<style jsx>{` <style jsx>{`
@ -139,6 +141,10 @@ export default class extends React.Component {
margin-bottom: 16px; margin-bottom: 16px;
} }
a {
text-decoration: underline;
}
hr { hr {
border-bottom: none; border-bottom: none;
margin-bottom: 0; margin-bottom: 0;

@ -1,21 +1,30 @@
import React from 'react' import React from 'react'
import axios from 'axios' import axios from 'axios'
import Spinner from 'react-spinner'
import { range, fileToDataURL } from '../lib/util' import { range, fileToDataURL } from '../lib/util'
const RAND_RANGE = 1000000 const RAND_RANGE = 1000000
const UPDATE_SIZE = 10 const UPDATE_SIZE = 20
const WALLPAPER_COLLECTION_ID = 1065396 const WALLPAPER_COLLECTION_ID = 136026
const RANDOM_WALLPAPER_URL = `https://source.unsplash.com/collection/${WALLPAPER_COLLECTION_ID}/240x320` const RANDOM_WALLPAPER_URL = `https://source.unsplash.com/collection/${WALLPAPER_COLLECTION_ID}/240x320`
const largerImage = url => url.replace(/w=\d+/, 'w=1920').replace(/&h=\d+/, '') const largerImage = url => url.replace(/w=\d+/, 'w=1920').replace(/&h=\d+/, '')
const smallerImage = url => url.replace(/w=\d+/, 'w=240') const smallerImage = url => url.replace(/w=\d+/, 'w=240')
const imageUrls = {}
let cache = []
async function getImage() { async function getImage() {
// circumvent browser caching // circumvent browser caching
const sig = Math.floor(Math.random() * RAND_RANGE) const sig = Math.floor(Math.random() * RAND_RANGE)
const res = await axios.get(`${RANDOM_WALLPAPER_URL}?sig=${sig}`, { responseType: 'blob' }) const res = await axios.get(`${RANDOM_WALLPAPER_URL}?sig=${sig}`, { responseType: 'blob' })
// image already in cache?
if (imageUrls[res.request.responseURL]) return
imageUrls[res.request.responseURL] = true
return { return {
url: res.request.responseURL, url: res.request.responseURL,
dataURL: await fileToDataURL(res.data) dataURL: await fileToDataURL(res.data)
@ -25,40 +34,48 @@ async function getImage() {
export default class extends React.Component { export default class extends React.Component {
constructor() { constructor() {
super() super()
this.state = { cache: [] } this.state = { cacheIndex: 0, loading: false }
this.selectImage = this.selectImage.bind(this) this.selectImage = this.selectImage.bind(this)
this.updateCache = this.updateCache.bind(this) this.updateCache = this.updateCache.bind(this)
this.nextImage = this.nextImage.bind(this) this.nextImage = this.nextImage.bind(this)
} }
// update in browser (we require window.FileReader) // fetch images in browser (we require window.FileReader)
componentDidMount() { componentDidMount() {
// clear cache when remounted
cache = []
this.updateCache() this.updateCache()
} }
selectImage() { selectImage() {
this.setState({ loading: true })
axios axios
.get(largerImage(this.state.cache[0].url), { responseType: 'blob' }) .get(largerImage(cache[this.state.cacheIndex].url), { responseType: 'blob' })
.then(res => res.data) .then(res => res.data)
.then(this.props.onChange) .then(this.props.onChange)
.then(() => this.setState({ loading: false }))
} }
updateCache() { updateCache() {
Promise.all(range(UPDATE_SIZE).map(getImage)).then(imgs => this.setState({ loading: true })
this.setState({ cache: this.state.cache.concat(imgs) }) Promise.all(range(UPDATE_SIZE).map(getImage))
) .then(imgs => imgs.filter(img => img)) // remove null
.then(imgs => (cache = cache.concat(imgs)))
.then(() => this.setState({ loading: false }))
} }
nextImage() { nextImage() {
this.setState({ cache: this.state.cache.slice(1) }) if (this.state.loading) return
this.setState({ cacheIndex: this.state.cacheIndex + 1 })
if (this.state.cache.length < 3) { if (this.state.cacheIndex > cache.length - 2) {
this.updateCache() this.updateCache()
} }
} }
render() { render() {
const bgImage = this.state.cache[0] && this.state.cache[0].dataURL const bgImage = cache[this.state.cacheIndex] && cache[this.state.cacheIndex].dataURL
return ( return (
<div className="random-image-container"> <div className="random-image-container">
@ -66,7 +83,7 @@ export default class extends React.Component {
<span onClick={this.selectImage}>Use Image</span> <span onClick={this.selectImage}>Use Image</span>
<span onClick={this.nextImage}>Try Another</span> <span onClick={this.nextImage}>Try Another</span>
</div> </div>
<div className="image" /> <div className="image">{this.state.loading && <Spinner />}</div>
<style jsx>{` <style jsx>{`
.image { .image {
width: 100%; width: 100%;
@ -83,7 +100,8 @@ export default class extends React.Component {
} }
span { span {
cursor: pointer; opacity: ${this.state.loading ? 0.5 : 1};
cursor: ${this.state.loading ? 'not-allowed' : 'pointer'};
user-select: none; user-select: none;
} }
`}</style> `}</style>

Loading…
Cancel
Save