From 4e0d362c968d20923019c4cae3c35c7cbd8e1338 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sat, 15 Dec 2018 13:33:29 -0800 Subject: [PATCH] Move extracting the zip to the epic/store --- src/Readme.js | 131 ++++++++++++++++++++++++------------ src/redux/actionCreators.js | 4 ++ src/redux/epics.js | 27 +++++++- src/redux/store.js | 14 +++- 4 files changed, 126 insertions(+), 50 deletions(-) diff --git a/src/Readme.js b/src/Readme.js index 9341c029..d2777f2f 100644 --- a/src/Readme.js +++ b/src/Readme.js @@ -1,66 +1,109 @@ import React from "react"; -import JSZip from "jszip"; +import { connect } from "react-redux"; import { switchMap } from "rxjs/operators"; -import { from, empty } from "rxjs"; +import { from } from "rxjs"; import Disposable from "./Disposable"; -export default class Readme extends React.Component { +class Readme extends React.Component { constructor(props) { super(props); this._disposable = new Disposable(); - this.state = { readmeText: null }; + this.state = { focusedFile: null }; } - componentDidMount() { - this._fetchReadme(); - } + componentDidMount() {} - componentDidUpdate(_, oldState) { - if (this.state.skinUrl != oldState.skinUrl) { - this._fetchReadme(); - } - } + componentDidUpdate(_, oldState) {} componentWillUnmount() { this._disposable.dispose(); } - _fetchReadme() { - this._disposable.add( - from(fetch(this.props.skinUrl)) - .pipe( - switchMap(response => response.blob()), - switchMap(blob => JSZip.loadAsync(blob)), - switchMap(zip => { - const readme = zip.file("readme.txt"); - if (readme == null) { - return empty(); - } - return readme.async("string"); - }) - ) - .subscribe(text => { - console.log(text); - // this.setState({ readmeText: text }); - }) - ); + async _focusFile(fileName) { + if (this.props.zip == null) { + return; + } + + const file = await this.props.zip.file(fileName); + const type = fileName + .split(".") + .pop() + .toLowerCase(); + const methodFromType = { + txt: "string", + bmp: "blob", + cur: "blob" + }; + let content = await file.async(methodFromType[type]); + this.setState({ focusedFile: { fileName, type, content } }); + } + + _renderFocusedFile() { + if (this.state.focusedFile == null) { + return; + } + + switch (this.state.focusedFile.type) { + case "txt": + return ( + + ); + case "bmp": + case "cur": + const mimeType = `image/cur`; + const content = URL.createObjectURL( + new Blob([this.state.focusedFile.content], { type: mimeType }) + ); + return ; + } } render() { return ( - this.state.readmeText && ( -
-          {this.state.readmeText}
-        
- ) +
+ +
{this._renderFocusedFile()}
+
); } } + +function mapStateToProps(state) { + return { + zip: state.skinZip + }; +} + +export default connect(mapStateToProps)(Readme); diff --git a/src/redux/actionCreators.js b/src/redux/actionCreators.js index b1acb2ce..4332e203 100644 --- a/src/redux/actionCreators.js +++ b/src/redux/actionCreators.js @@ -17,3 +17,7 @@ export function requestedRandomSkin() { export function gotNewMatchingHashes(matchingHashes) { return { type: "GOT_NEW_MATCHING_HASHES", matchingHashes }; } + +export function loadedSkinZip(zip) { + return { type: "LOADED_SKIN_ZIP", zip }; +} diff --git a/src/redux/epics.js b/src/redux/epics.js index 694b90f0..fe845962 100644 --- a/src/redux/epics.js +++ b/src/redux/epics.js @@ -1,8 +1,9 @@ import { combineEpics } from "redux-observable"; -import { of, from } from "rxjs"; +import { of, from, empty } from "rxjs"; import * as Actions from "./actionCreators"; import * as Selectors from "./selectors"; -import { filter, switchMap, map } from "rxjs/operators"; +import * as Utils from "../utils"; +import { filter, switchMap, map, ignoreElements, tap } from "rxjs/operators"; import { search } from "../algolia"; const urlChangedEpic = actions => @@ -20,6 +21,21 @@ const urlChangedEpic = actions => }) ); +const selectedSkinEpic = actions => + actions.pipe( + filter(action => action.type === "SELECTED_SKIN"), + switchMap(action => { + return from(fetch(Utils.skinUrlFromHash(action.hash))).pipe( + switchMap(response => response.blob()), + switchMap(async blob => { + const JSZip = await import("jszip"); + return JSZip.loadAsync(blob); + }), + map(zip => Actions.loadedSkinZip(zip)) + ); + }) + ); + const searchEpic = actions => actions.pipe( filter(action => action.type === "SEARCH_QUERY_CHANGED"), @@ -44,4 +60,9 @@ const randomSkinEpic = (actions, states) => return Actions.selectedSkin(Selectors.getRandomSkinHash(states.value)); }) ); -export default combineEpics(searchEpic, urlChangedEpic, randomSkinEpic); +export default combineEpics( + searchEpic, + urlChangedEpic, + selectedSkinEpic, + randomSkinEpic +); diff --git a/src/redux/store.js b/src/redux/store.js index 00a54bcb..6b639c08 100644 --- a/src/redux/store.js +++ b/src/redux/store.js @@ -7,7 +7,8 @@ const defaultState = { searchQuery: null, selectedSkinHash: null, selectedSkinPosition: null, - matchingHashes: null + matchingHashes: null, + skinZip: null }; function reducer(state = defaultState, action) { @@ -16,13 +17,15 @@ function reducer(state = defaultState, action) { return { ...state, selectedSkinHash: action.hash, - selectedSkinPosition: action.position + selectedSkinPosition: action.position, + skinZip: null }; case "CLOSE_MODAL": return { ...state, selectedSkinHash: null, - selectedSkinPosition: null + selectedSkinPosition: null, + skinZip: null }; case "SEARCH_QUERY_CHANGED": return { @@ -36,6 +39,11 @@ function reducer(state = defaultState, action) { ...state, matchingHashes: action.matchingHashes }; + case "LOADED_SKIN_ZIP": + return { + ...state, + skinZip: action.zip + }; default: return state; }