import classNames from 'classnames'; import { connect } from 'react-redux'; import { FormattedMessage, injectIntl } from 'react-intl'; import PropTypes from 'prop-types'; import React from 'react'; import bindAll from 'lodash.bindall'; import Button from '../button/button.jsx'; import loadingIcon from './share-loading.svg'; import styles from './share-button.css'; const getProjectThumbnail = () => new Promise(resolve => { window.vm.renderer.requestSnapshot(uri => { resolve(uri); }); }); const getProjectUri = () => new Promise(resolve => { window.vm.saveProjectSb3().then(blob => new Promise(resolve => { const reader = new FileReader(); reader.onload = element => { resolve(element.target.result); }; reader.readAsDataURL(blob); })) .then(resolve); }); //サーバーダウンチェック const isUploadAvailable = async () => { let res = null; try { res = await fetch('https://projects.penguinmod.com/api/v1/projects/canuploadprojects').then(res => res.json()); } catch { // failed to fetch entirely return false; } return res.canUpload; }; class ShareButton extends React.Component { constructor(props) { super(props); bindAll(this, [ 'handleMessageEvent', 'wrapperEventHandler', 'onUploadProject' ]); this.state = { loading: false, imageUri: '' }; } componentDidMount() { window.addEventListener('message', this.wrapperEventHandler); } componentWillUnmount() { window.removeEventListener('message', this.wrapperEventHandler); } wrapperEventHandler(e) { this.handleMessageEvent(e); } async handleMessageEvent(e) { if (!e.origin.startsWith(`https://penguinmod.com`)) { return; } if (!e.data.p4) { return; } const packagerData = e.data.p4; if (packagerData.type !== 'validate') { return; } const imageUri = this.state.imageUri; e.source.postMessage({ p4: { type: 'image', uri: imageUri } }, e.origin); const projectUri = await getProjectUri(); e.source.postMessage({ p4: { type: 'project', uri: projectUri } }, e.origin); e.source.postMessage({ p4: { type: 'finished' } }, e.origin); } async onUploadProject() { if (this.state.loading) return; if (!window.vm) return; if (!window.vm.runtime) return; if (!window.vm.renderer) return; // get the project thumbnail await new Promise((resolve) => { getProjectThumbnail().then(dataUrl => { this.setState({ imageUri: dataUrl }); resolve(); }); window.vm.renderer.draw(); // force the callback to run setTimeout(() => { window.vm.renderer.draw(); // force the callback to run }, 50); setTimeout(() => { window.vm.renderer.draw(); // force the callback to run }, 100); }); this.setState({ loading: true }); isUploadAvailable().then(available => { this.setState({ loading: false }); if (!available) { // error? console.warn('Project Server did not respond. Uploading is not available.'); alert('Uploading is currently unavailable. Please wait for the server to be restored.'); return; } const isEdit = this.props.usernameLoggedIn && this.props.extraProjectInfo?.author === this.props.username; let editPiece = ''; let remixPiece = ''; const id = location.hash.replace('#', ''); if (this.props.extraProjectInfo?.isRemix) { remixPiece = `&remix=${id}`; } let targetPage = 'upload'; if (isEdit) { targetPage = 'edit'; editPiece = `&id=${id}`; } const url = location.origin; //最終的なURL window.open(`https://penguinmod.com/${targetPage}?name=${this.props.projectTitle}${editPiece}${remixPiece}&external=${url}`, '_blank'); }); } render() { const isRemix = this.props.extraProjectInfo?.isRemix; const isEdit = this.props.usernameLoggedIn && this.props.extraProjectInfo?.author === this.props.username; return ( ); } } ShareButton.propTypes = { className: PropTypes.string, isShared: PropTypes.bool, projectTitle: PropTypes.string, extraProjectInfo: PropTypes.shape({ accepted: PropTypes.bool, isRemix: PropTypes.bool, remixId: PropTypes.number, tooLarge: PropTypes.bool, author: PropTypes.string, releaseDate: PropTypes.shape(Date), isUpdated: PropTypes.bool }), username: PropTypes.string, usernameLoggedIn: PropTypes.bool }; const mapStateToProps = state => ({ projectTitle: state.scratchGui.projectTitle, extraProjectInfo: state.scratchGui.tw.extraProjectInfo, username: state.scratchGui.tw.username, usernameLoggedIn: state.scratchGui.tw.usernameLoggedIn }); // eslint-disable-next-line no-unused-vars const mapDispatchToProps = dispatch => ({}); export default injectIntl(connect( mapStateToProps, mapDispatchToProps )(ShareButton));