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;
}