diff --git a/src/Readme.js b/src/Readme.js
index d2777f2f..0df1c9a5 100644
--- a/src/Readme.js
+++ b/src/Readme.js
@@ -1,49 +1,19 @@
import React from "react";
import { connect } from "react-redux";
-import { switchMap } from "rxjs/operators";
-import { from } from "rxjs";
-import Disposable from "./Disposable";
+import * as Actions from "./redux/actionCreators";
class Readme extends React.Component {
- constructor(props) {
- super(props);
- this._disposable = new Disposable();
- this.state = { focusedFile: null };
- }
-
- componentDidMount() {}
-
- componentDidUpdate(_, oldState) {}
-
- componentWillUnmount() {
- this._disposable.dispose();
- }
-
- 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) {
+ if (this.props.focusedFile == null) {
return;
}
- switch (this.state.focusedFile.type) {
+ const { ext, fileName, content } = this.props.focusedFile;
+ if (content == null) {
+ return;
+ }
+
+ switch (ext) {
case "txt":
return (
+ defaultValue={content}
+ />
);
case "bmp":
case "cur":
- const mimeType = `image/cur`;
- const content = URL.createObjectURL(
- new Blob([this.state.focusedFile.content], { type: mimeType })
+ const mimeType = `image/${ext}`;
+ const url = URL.createObjectURL(
+ new Blob([content], { type: mimeType })
);
- return
;
+ return
;
+ default:
+ return null;
}
}
@@ -77,24 +48,22 @@ class Readme extends React.Component {
overflow: "scroll"
}}
>
-
- {this._renderFocusedFile()}
+
+ {this._renderFocusedFile()}
);
}
@@ -102,8 +71,19 @@ class Readme extends React.Component {
function mapStateToProps(state) {
return {
- zip: state.skinZip
+ zip: state.skinZip,
+ focusedFile: state.focusedSkinFile
};
}
-export default connect(mapStateToProps)(Readme);
+function mapDispatchToProps(dispatch) {
+ return {
+ selectSkinFile(fileName) {
+ dispatch(Actions.selectSkinFile(fileName));
+ }
+ };
+}
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(Readme);
diff --git a/src/SkinTable.js b/src/SkinTable.js
index 3ae8f16f..15b05e48 100644
--- a/src/SkinTable.js
+++ b/src/SkinTable.js
@@ -38,8 +38,8 @@ class SkinTable extends React.Component {
_handleResize() {
const { windowWidth, windowHeight } = Utils.getWindowSize();
if (
- windowWidth != this.state.windowWidth ||
- windowHeight != this.state.windowHeight
+ windowWidth !== this.state.windowWidth ||
+ windowHeight !== this.state.windowHeight
) {
this.setState({ windowWidth, windowHeight });
}
diff --git a/src/redux/actionCreators.js b/src/redux/actionCreators.js
index 4332e203..bb5840c3 100644
--- a/src/redux/actionCreators.js
+++ b/src/redux/actionCreators.js
@@ -21,3 +21,16 @@ export function gotNewMatchingHashes(matchingHashes) {
export function loadedSkinZip(zip) {
return { type: "LOADED_SKIN_ZIP", zip };
}
+
+export function selectSkinFile(fileName) {
+ const ext = fileName
+ .split(".")
+ .pop()
+ .toLowerCase();
+
+ return { type: "SELECTED_SKIN_FILE_TO_FOCUS", fileName, ext };
+}
+
+export function gotFocusedSkinFile(content) {
+ return { type: "GOT_FOCUSED_SKIN_FILE", content };
+}
diff --git a/src/redux/epics.js b/src/redux/epics.js
index fe845962..aed29059 100644
--- a/src/redux/epics.js
+++ b/src/redux/epics.js
@@ -3,7 +3,7 @@ import { of, from, empty } from "rxjs";
import * as Actions from "./actionCreators";
import * as Selectors from "./selectors";
import * as Utils from "../utils";
-import { filter, switchMap, map, ignoreElements, tap } from "rxjs/operators";
+import { filter, switchMap, map, tap } from "rxjs/operators";
import { search } from "../algolia";
const urlChangedEpic = actions =>
@@ -36,6 +36,28 @@ const selectedSkinEpic = actions =>
})
);
+const focusedSkinFileEpic = (actions, states) =>
+ actions.pipe(
+ filter(action => action.type === "SELECTED_SKIN_FILE_TO_FOCUS"),
+ switchMap(({ fileName, ext }) => {
+ // TODO: Ensure this is never called with the wrong zip. Should this live in the "got zip" closure?
+ const { skinZip } = states.value;
+ if (skinZip == null) {
+ // TODO: Should this throw?
+ return empty();
+ }
+
+ const methodFromExt = {
+ txt: "string",
+ bmp: "blob",
+ cur: "blob"
+ };
+ return from(skinZip.file(fileName).async(methodFromExt[ext])).pipe(
+ map(content => Actions.gotFocusedSkinFile(content))
+ );
+ })
+ );
+
const searchEpic = actions =>
actions.pipe(
filter(action => action.type === "SEARCH_QUERY_CHANGED"),
@@ -64,5 +86,6 @@ export default combineEpics(
searchEpic,
urlChangedEpic,
selectedSkinEpic,
+ focusedSkinFileEpic,
randomSkinEpic
);
diff --git a/src/redux/store.js b/src/redux/store.js
index 6b639c08..14b204f9 100644
--- a/src/redux/store.js
+++ b/src/redux/store.js
@@ -8,7 +8,8 @@ const defaultState = {
selectedSkinHash: null,
selectedSkinPosition: null,
matchingHashes: null,
- skinZip: null
+ skinZip: null,
+ focusedSkinFile: null
};
function reducer(state = defaultState, action) {
@@ -44,6 +45,24 @@ function reducer(state = defaultState, action) {
...state,
skinZip: action.zip
};
+ case "SELECTED_SKIN_FILE_TO_FOCUS": {
+ return {
+ ...state,
+ focusedSkinFile: {
+ content: null,
+ ext: action.ext,
+ fileName: action.fileName
+ }
+ };
+ }
+ case "GOT_FOCUSED_SKIN_FILE":
+ return {
+ ...state,
+ focusedSkinFile: {
+ ...state.focusedSkinFile,
+ content: action.content
+ }
+ };
default:
return state;
}