@fountain-ui/lab 2.0.0-beta.50 → 2.0.0-beta.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/commonjs/ComicViewer/ComicViewer.js +31 -65
- package/build/commonjs/ComicViewer/ComicViewer.js.map +1 -1
- package/build/commonjs/ComicViewer/ComicViewerProps.js.map +1 -1
- package/build/commonjs/ComicViewer/ViewerItem.js +2 -0
- package/build/commonjs/ComicViewer/ViewerItem.js.map +1 -1
- package/build/commonjs/ComicViewer/index.js.map +1 -1
- package/build/module/ComicViewer/ComicViewer.js +31 -64
- package/build/module/ComicViewer/ComicViewer.js.map +1 -1
- package/build/module/ComicViewer/ComicViewerProps.js.map +1 -1
- package/build/module/ComicViewer/ViewerItem.js +2 -0
- package/build/module/ComicViewer/ViewerItem.js.map +1 -1
- package/build/module/ComicViewer/index.js.map +1 -1
- package/build/typescript/ComicViewer/ComicViewerProps.d.ts +6 -6
- package/build/typescript/ComicViewer/ViewerItem.d.ts +4 -0
- package/build/typescript/ComicViewer/index.d.ts +1 -1
- package/package.json +2 -2
- package/src/ComicViewer/ComicViewer.tsx +39 -72
- package/src/ComicViewer/ComicViewerProps.ts +7 -7
- package/src/ComicViewer/ViewerItem.tsx +7 -0
- package/src/ComicViewer/index.ts +1 -1
|
@@ -11,8 +11,6 @@ var _reactNative = require("react-native");
|
|
|
11
11
|
|
|
12
12
|
var R = _interopRequireWildcard(require("ramda"));
|
|
13
13
|
|
|
14
|
-
var _core = require("@fountain-ui/core");
|
|
15
|
-
|
|
16
14
|
var _ViewerItem = _interopRequireDefault(require("./ViewerItem"));
|
|
17
15
|
|
|
18
16
|
var _FastScroll = _interopRequireDefault(require("./FastScroll"));
|
|
@@ -31,10 +29,14 @@ const getHeightAccum = heights => R.mapAccum(appender, 0, heights);
|
|
|
31
29
|
|
|
32
30
|
const keyExtractor = item => String(item.index);
|
|
33
31
|
|
|
34
|
-
const createInitialImageState =
|
|
35
|
-
isNewUrlIncoming: false,
|
|
32
|
+
const createInitialImageState = image => ({
|
|
36
33
|
totalErrorCount: 0,
|
|
37
|
-
dimension
|
|
34
|
+
dimension: image.dimension,
|
|
35
|
+
tryRenderingMillis: 0,
|
|
36
|
+
urlState: {
|
|
37
|
+
url: image.url,
|
|
38
|
+
validity: 'unknown'
|
|
39
|
+
}
|
|
38
40
|
});
|
|
39
41
|
|
|
40
42
|
const mapImageStateToItemState = (index, imageState, autoHandleErrorCount) => {
|
|
@@ -43,6 +45,7 @@ const mapImageStateToItemState = (index, imageState, autoHandleErrorCount) => {
|
|
|
43
45
|
return {
|
|
44
46
|
index,
|
|
45
47
|
url: (_imageState$urlState = imageState.urlState) === null || _imageState$urlState === void 0 ? void 0 : _imageState$urlState.url,
|
|
48
|
+
imageKey: `${imageState.tryRenderingMillis}-${index}`,
|
|
46
49
|
reloadButtonVisible: ((_imageState$urlState2 = imageState.urlState) === null || _imageState$urlState2 === void 0 ? void 0 : _imageState$urlState2.validity) !== 'valid' && imageState.totalErrorCount >= autoHandleErrorCount,
|
|
47
50
|
dimension: imageState.dimension
|
|
48
51
|
};
|
|
@@ -57,11 +60,10 @@ function ComicViewer(props) {
|
|
|
57
60
|
debounceMillis = 100,
|
|
58
61
|
autoHandleErrorCount = 3,
|
|
59
62
|
fastScrollOptions,
|
|
60
|
-
getUrlByIndex,
|
|
61
63
|
initialNumToRender = 1,
|
|
62
64
|
initialScrollPercentage = 0,
|
|
63
65
|
itemVisiblePercentThreshold = 0,
|
|
64
|
-
|
|
66
|
+
intrinsicImages,
|
|
65
67
|
maxContentWidth = MAXIMUM_WIDTH,
|
|
66
68
|
onItemPress,
|
|
67
69
|
onScroll,
|
|
@@ -76,7 +78,7 @@ function ComicViewer(props) {
|
|
|
76
78
|
const flatListRef = (0, _react.useRef)(null);
|
|
77
79
|
const maybeLoadableItemsIndexRange = (0, _react.useRef)([-1, 0]);
|
|
78
80
|
const actualImageWidth = Math.min(viewportWidth, maxContentWidth);
|
|
79
|
-
const initialImageStates = (0, _react.useMemo)(() => R.map(createInitialImageState,
|
|
81
|
+
const initialImageStates = (0, _react.useMemo)(() => R.map(createInitialImageState, intrinsicImages), []);
|
|
80
82
|
const imageStatesRef = (0, _react.useRef)(initialImageStates);
|
|
81
83
|
|
|
82
84
|
const mapImageStatesToItemStates = imageStates => {
|
|
@@ -87,13 +89,13 @@ function ComicViewer(props) {
|
|
|
87
89
|
return mapImageStatesToItemStates(imageStatesRef.current);
|
|
88
90
|
});
|
|
89
91
|
const renderedDimensions = (0, _react.useMemo)(() => {
|
|
90
|
-
return mapIndexed((
|
|
91
|
-
const height =
|
|
92
|
+
return mapIndexed((intrinsicImage, index) => {
|
|
93
|
+
const height = intrinsicImage.dimension.height * actualImageWidth / intrinsicImage.dimension.width + (index === 0 ? invisiblePaddingTop : 0);
|
|
92
94
|
return {
|
|
93
95
|
width: actualImageWidth,
|
|
94
96
|
height: isNaN(height) ? 0 : height
|
|
95
97
|
};
|
|
96
|
-
},
|
|
98
|
+
}, intrinsicImages);
|
|
97
99
|
}, [actualImageWidth]);
|
|
98
100
|
const layoutFromDimensions = (0, _react.useCallback)(() => {
|
|
99
101
|
const itemHeights = R.map(dimension => dimension.height, renderedDimensions);
|
|
@@ -129,54 +131,28 @@ function ComicViewer(props) {
|
|
|
129
131
|
});
|
|
130
132
|
};
|
|
131
133
|
|
|
132
|
-
const
|
|
133
|
-
const
|
|
134
|
-
var _state$urlState;
|
|
135
|
-
|
|
136
|
-
const state = imageStatesRef.current[index];
|
|
137
|
-
return !state.isNewUrlIncoming && (R.isNil(state.urlState) || ((_state$urlState = state.urlState) === null || _state$urlState === void 0 ? void 0 : _state$urlState.validity) === 'invalid');
|
|
138
|
-
}, indexes);
|
|
134
|
+
const updateItems = indexes => {
|
|
135
|
+
const tryRenderingMillis = new Date().getTime();
|
|
139
136
|
updateImageState((imageState, i) => {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
} : imageState;
|
|
143
|
-
});
|
|
137
|
+
const urlState = imageState.urlState;
|
|
138
|
+
const shouldRerender = R.includes(i, R.defaultTo([], indexes));
|
|
144
139
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (newUrl !== undefined && (urlState === null || urlState === void 0 ? void 0 : urlState.validity) !== 'valid') {
|
|
152
|
-
return { ...imageState,
|
|
153
|
-
urlState: {
|
|
154
|
-
url: newUrl,
|
|
155
|
-
validity: 'unknown'
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
}
|
|
140
|
+
if (shouldRerender && (urlState === null || urlState === void 0 ? void 0 : urlState.validity) !== 'valid') {
|
|
141
|
+
return { ...imageState,
|
|
142
|
+
tryRenderingMillis
|
|
143
|
+
};
|
|
144
|
+
}
|
|
159
145
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
} catch (e) {// ignore
|
|
163
|
-
} finally {
|
|
164
|
-
updateImageState((imageState, i) => {
|
|
165
|
-
return R.includes(i, filteredIndexes) ? { ...imageState,
|
|
166
|
-
isNewUrlIncoming: false
|
|
167
|
-
} : imageState;
|
|
168
|
-
});
|
|
169
|
-
}
|
|
146
|
+
return imageState;
|
|
147
|
+
});
|
|
170
148
|
};
|
|
171
149
|
|
|
172
|
-
const
|
|
150
|
+
const renderMaybeLoadableItems = () => {
|
|
173
151
|
const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;
|
|
174
152
|
const affectedIndexes = R.range(startIndex, endIndex);
|
|
175
|
-
|
|
153
|
+
updateItems(affectedIndexes);
|
|
176
154
|
};
|
|
177
155
|
|
|
178
|
-
const ignoreDebounce = (0, _react.useRef)(true);
|
|
179
|
-
const loadItemsDebounce = (0, _core.useDebounce)(loadMaybeLoadableItems, debounceMillis);
|
|
180
156
|
const onViewableItemsChanged = (0, _react.useRef)(_ref => {
|
|
181
157
|
var _R$head, _R$last;
|
|
182
158
|
|
|
@@ -194,14 +170,7 @@ function ComicViewer(props) {
|
|
|
194
170
|
const startIndex = R.max(firstViewableIndex - NUMBER_OF_ADJACENT_ITEM, 0);
|
|
195
171
|
const endIndex = R.min(lastViewableItemIndex + NUMBER_OF_ADJACENT_ITEM, itemStates.length - 1);
|
|
196
172
|
maybeLoadableItemsIndexRange.current = [startIndex, endIndex + 1];
|
|
197
|
-
|
|
198
|
-
if (ignoreDebounce.current) {
|
|
199
|
-
loadMaybeLoadableItems();
|
|
200
|
-
ignoreDebounce.current = false;
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
loadItemsDebounce();
|
|
173
|
+
renderMaybeLoadableItems();
|
|
205
174
|
});
|
|
206
175
|
const handleScroll = (0, _react.useCallback)(event => {
|
|
207
176
|
var _fastScrollRef$curren;
|
|
@@ -232,7 +201,7 @@ function ComicViewer(props) {
|
|
|
232
201
|
updateImageState((imageState, i) => {
|
|
233
202
|
const urlState = imageState.urlState;
|
|
234
203
|
|
|
235
|
-
if (i === index
|
|
204
|
+
if (i === index) {
|
|
236
205
|
return { ...imageState,
|
|
237
206
|
totalErrorCount: imageState.totalErrorCount + 1,
|
|
238
207
|
urlState: { ...urlState,
|
|
@@ -251,17 +220,13 @@ function ComicViewer(props) {
|
|
|
251
220
|
const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;
|
|
252
221
|
|
|
253
222
|
if (index >= startIndex || index < endIndex) {
|
|
254
|
-
|
|
223
|
+
renderMaybeLoadableItems();
|
|
255
224
|
}
|
|
256
225
|
};
|
|
257
226
|
|
|
258
227
|
const handleReloadPress = () => {
|
|
259
228
|
onReloadPress && onReloadPress();
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (index >= startIndex || index < endIndex) {
|
|
263
|
-
loadUrlByIndex([index]);
|
|
264
|
-
}
|
|
229
|
+
updateItems([index]);
|
|
265
230
|
};
|
|
266
231
|
|
|
267
232
|
const onLoad = () => {
|
|
@@ -286,6 +251,7 @@ function ComicViewer(props) {
|
|
|
286
251
|
onPress: onItemPress,
|
|
287
252
|
onReloadPress: handleReloadPress,
|
|
288
253
|
url: item.url,
|
|
254
|
+
imageKey: item.imageKey,
|
|
289
255
|
invisiblePaddingTop: index === 0 ? invisiblePaddingTop : 0,
|
|
290
256
|
width: ((_renderedDimensions$i = renderedDimensions[index]) === null || _renderedDimensions$i === void 0 ? void 0 : _renderedDimensions$i.width) ?? 0,
|
|
291
257
|
height: ((_renderedDimensions$i2 = renderedDimensions[index]) === null || _renderedDimensions$i2 === void 0 ? void 0 : _renderedDimensions$i2.height) ?? 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["appender","left","right","getHeightAccum","heights","R","mapAccum","keyExtractor","item","String","index","createInitialImageState","dimension","isNewUrlIncoming","totalErrorCount","mapImageStateToItemState","imageState","autoHandleErrorCount","url","urlState","reloadButtonVisible","validity","mapIndexed","addIndex","map","MAXIMUM_WIDTH","NUMBER_OF_ADJACENT_ITEM","ComicViewer","props","debounceMillis","fastScrollOptions","getUrlByIndex","initialNumToRender","initialScrollPercentage","itemVisiblePercentThreshold","intrinsicDimensions","maxContentWidth","onItemPress","onScroll","onError","onReloadPress","viewportWidth","invisiblePaddingTop","windowSize","otherProps","fastScrollRef","ref","flatListRef","useRef","maybeLoadableItemsIndexRange","actualImageWidth","Math","min","initialImageStates","useMemo","imageStatesRef","mapImageStatesToItemStates","imageStates","image","itemStates","setItemStates","useState","current","renderedDimensions","intrinsicDimension","height","width","isNaN","layoutFromDimensions","useCallback","itemHeights","totalHeight","heightAccum","itemOffsets","prepend","getItemLayout","data","length","offset","viewabilityConfig","updateImageState","updateFunction","prevImageStates","newImageStates","prevItemStates","newItemStates","equals","loadUrlByIndex","indexes","filteredIndexes","filter","state","isNil","i","includes","urls","newUrl","get","undefined","e","loadMaybeLoadableItems","startIndex","endIndex","affectedIndexes","range","ignoreDebounce","loadItemsDebounce","useDebounce","onViewableItemsChanged","viewableItems","orderedViewableItems","sort","a","b","firstViewableIndex","head","lastViewableItemIndex","last","max","handleScroll","event","onContentScroll","scrollContentToOffset","scrollToOffset","animated","renderItem","handleError","handleReloadPress","onLoad","useEffect","floor"],"sources":["ComicViewer.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { FlatList, ListRenderItem, NativeScrollEvent, NativeSyntheticEvent, ViewToken } from 'react-native';\nimport * as R from 'ramda';\nimport { useDebounce } from '@fountain-ui/core';\nimport { default as ComicViewerProps, Dimension } from './ComicViewerProps';\nimport ViewerItem from './ViewerItem';\nimport FastScroll from './FastScroll';\n\nconst appender = (left: number, right: number): [number, number] => [left + right, left + right];\nconst getHeightAccum = (heights: number[]): [number, number[]] => R.mapAccum(appender, 0, heights);\n\nconst keyExtractor = <T, >(item: ItemState) => String(item.index);\n\ninterface UrlState {\n url: string;\n validity: 'valid' | 'invalid' | 'unknown';\n}\n\ninterface ImageState {\n urlState?: UrlState;\n isNewUrlIncoming: boolean;\n totalErrorCount: number;\n dimension: Dimension;\n}\n\ninterface ItemState {\n index: number;\n url?: string;\n reloadButtonVisible: boolean;\n dimension: Dimension;\n}\n\nconst createInitialImageState = (dimension: Dimension): ImageState => ({\n isNewUrlIncoming: false,\n totalErrorCount: 0,\n dimension,\n});\n\nconst mapImageStateToItemState = (\n index: number,\n imageState: ImageState,\n autoHandleErrorCount: number,\n): ItemState => ({\n index,\n url: imageState.urlState?.url,\n reloadButtonVisible: (imageState.urlState?.validity !== 'valid') && imageState.totalErrorCount >= autoHandleErrorCount,\n dimension: imageState.dimension,\n});\n\nconst mapIndexed = R.addIndex<Dimension>(R.map);\n\nconst MAXIMUM_WIDTH = 720;\n\nconst NUMBER_OF_ADJACENT_ITEM = 5;\n\nexport default function ComicViewer(props: ComicViewerProps) {\n const {\n debounceMillis = 100,\n autoHandleErrorCount = 3,\n fastScrollOptions,\n getUrlByIndex,\n initialNumToRender = 1,\n initialScrollPercentage = 0,\n itemVisiblePercentThreshold = 0,\n intrinsicDimensions,\n maxContentWidth = MAXIMUM_WIDTH,\n onItemPress,\n onScroll,\n onError,\n onReloadPress,\n viewportWidth,\n invisiblePaddingTop = 0,\n windowSize = 3,\n ...otherProps\n } = props;\n\n const fastScrollRef = fastScrollOptions?.ref;\n\n const flatListRef = useRef<FlatList>(null);\n\n const maybeLoadableItemsIndexRange = useRef<[number, number]>([-1, 0]);\n\n const actualImageWidth = Math.min(viewportWidth, maxContentWidth);\n\n const initialImageStates = useMemo<Array<ImageState>>(() => R.map(createInitialImageState, intrinsicDimensions), []);\n const imageStatesRef = useRef<Array<ImageState>>(initialImageStates);\n\n const mapImageStatesToItemStates = (imageStates: Array<ImageState>): Array<ItemState> => {\n return imageStates.map((image, index) => mapImageStateToItemState(\n index, image, autoHandleErrorCount,\n ));\n };\n\n const [itemStates, setItemStates] = useState<Array<ItemState>>(() => {\n return mapImageStatesToItemStates(imageStatesRef.current);\n });\n\n const renderedDimensions = useMemo<Array<Dimension>>(() => {\n return mapIndexed((intrinsicDimension, index) => {\n const height = (intrinsicDimension.height * actualImageWidth) / intrinsicDimension.width + (index === 0 ? invisiblePaddingTop : 0);\n\n return {\n width: actualImageWidth,\n height: isNaN(height) ? 0 : height,\n };\n }, intrinsicDimensions);\n }, [actualImageWidth]);\n\n const layoutFromDimensions = useCallback(() => {\n const itemHeights = R.map(dimension => dimension.height, renderedDimensions);\n const [totalHeight, heightAccum] = getHeightAccum(itemHeights);\n const itemOffsets = R.prepend(0, heightAccum);\n\n const getItemLayout = (data: any, index: number) => ({\n index,\n length: itemHeights[index],\n offset: itemOffsets[index],\n });\n\n return {\n totalHeight,\n getItemLayout,\n };\n }, [renderedDimensions]);\n\n const { totalHeight, getItemLayout } = layoutFromDimensions();\n\n const viewabilityConfig = useMemo(() => ({\n itemVisiblePercentThreshold,\n }), [itemVisiblePercentThreshold]);\n\n const updateImageState = (updateFunction: (prev: ImageState, index: number) => ImageState) => {\n const prevImageStates = imageStatesRef.current;\n const newImageStates = prevImageStates.map(updateFunction);\n\n imageStatesRef.current = newImageStates;\n\n setItemStates(prevItemStates => {\n const newItemStates = mapImageStatesToItemStates(newImageStates);\n\n return R.equals(prevItemStates, newItemStates) ? prevItemStates : newItemStates;\n });\n };\n\n const loadUrlByIndex = async (indexes: number[]) => {\n const filteredIndexes = R.filter(index => {\n const state = imageStatesRef.current[index];\n\n return !state.isNewUrlIncoming\n && (R.isNil(state.urlState) || state.urlState?.validity === 'invalid');\n }, indexes);\n\n updateImageState((imageState, i) => {\n return R.includes(i, filteredIndexes)\n ? { ...imageState, isNewUrlIncoming: true }\n : imageState;\n });\n\n try {\n const urls = await getUrlByIndex(filteredIndexes);\n\n updateImageState((imageState, i) => {\n const newUrl = urls?.get(i);\n const urlState = imageState.urlState;\n\n if (newUrl !== undefined && urlState?.validity !== 'valid') {\n return {\n ...imageState,\n urlState: {\n url: newUrl,\n validity: 'unknown',\n },\n };\n }\n\n return imageState;\n });\n } catch (e) {\n // ignore\n } finally {\n updateImageState((imageState, i) => {\n return R.includes(i, filteredIndexes)\n ? { ...imageState, isNewUrlIncoming: false }\n : imageState;\n });\n }\n };\n\n const loadMaybeLoadableItems = () => {\n const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;\n const affectedIndexes = R.range(startIndex, endIndex);\n\n loadUrlByIndex(affectedIndexes);\n };\n\n const ignoreDebounce = useRef(true);\n const loadItemsDebounce = useDebounce(loadMaybeLoadableItems, debounceMillis);\n\n const onViewableItemsChanged = useRef(({ viewableItems }: { viewableItems: Array<ViewToken> }) => {\n const orderedViewableItems = R.sort((a, b) => (a.index || 0) - (b.index || 0), viewableItems);\n\n const firstViewableIndex = R.head(orderedViewableItems)?.index;\n const lastViewableItemIndex = R.last(orderedViewableItems)?.index;\n\n if (R.isNil(firstViewableIndex) || R.isNil(lastViewableItemIndex)) {\n return;\n }\n\n const startIndex = R.max(firstViewableIndex - NUMBER_OF_ADJACENT_ITEM, 0);\n const endIndex = R.min(lastViewableItemIndex + NUMBER_OF_ADJACENT_ITEM, itemStates.length - 1);\n\n maybeLoadableItemsIndexRange.current = [startIndex, endIndex + 1];\n\n if (ignoreDebounce.current) {\n loadMaybeLoadableItems();\n\n ignoreDebounce.current = false;\n return;\n }\n\n loadItemsDebounce();\n });\n\n const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {\n fastScrollRef?.current?.onContentScroll(event);\n\n onScroll?.(event);\n }, [onScroll]);\n\n const scrollContentToOffset = (offset: number) => {\n flatListRef.current?.scrollToOffset({\n offset,\n animated: false,\n });\n };\n\n const renderItem: ListRenderItem<ItemState> = useCallback(({ item, index }) => {\n const handleError = () => {\n onError && onError();\n\n updateImageState((imageState, i) => {\n const urlState = imageState.urlState;\n\n if (i === index && urlState !== undefined) {\n return {\n ...imageState,\n totalErrorCount: imageState.totalErrorCount + 1,\n urlState: {\n ...urlState,\n validity: 'invalid',\n },\n };\n }\n\n return imageState;\n });\n\n if (item.reloadButtonVisible) {\n return;\n }\n\n const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;\n if (index >= startIndex || index < endIndex) {\n loadItemsDebounce();\n }\n };\n\n const handleReloadPress = () => {\n onReloadPress && onReloadPress();\n\n const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;\n if (index >= startIndex || index < endIndex) {\n loadUrlByIndex([index]);\n }\n };\n\n const onLoad = () => {\n updateImageState((imageState, i) => {\n const urlState = imageState.urlState;\n\n if (i === index && urlState !== undefined) {\n return {\n ...imageState,\n urlState: {\n ...urlState,\n validity: 'valid',\n },\n };\n }\n\n return imageState;\n });\n };\n\n return (\n <ViewerItem\n onError={handleError}\n onLoad={onLoad}\n onPress={onItemPress}\n onReloadPress={handleReloadPress}\n url={item.url}\n invisiblePaddingTop={index === 0 ? invisiblePaddingTop : 0}\n width={renderedDimensions[index]?.width ?? 0}\n height={renderedDimensions[index]?.height ?? 0}\n reloadButtonVisible={item.reloadButtonVisible}\n />\n );\n }, [onItemPress, renderedDimensions]);\n\n useEffect(() => {\n const offset = Math.floor((initialScrollPercentage / 100) * totalHeight);\n\n if (flatListRef.current) {\n flatListRef.current.scrollToOffset({ offset, animated: false });\n }\n }, []);\n\n return (\n <React.Fragment>\n <FlatList\n data={itemStates}\n getItemLayout={getItemLayout}\n initialNumToRender={initialNumToRender}\n keyExtractor={keyExtractor}\n onViewableItemsChanged={onViewableItemsChanged.current}\n ref={flatListRef}\n renderItem={renderItem}\n viewabilityConfig={viewabilityConfig}\n windowSize={windowSize}\n onScroll={handleScroll}\n {...otherProps}\n />\n\n <FastScroll\n {...fastScrollOptions}\n contentLength={totalHeight}\n scrollContentToOffset={scrollContentToOffset}\n />\n </React.Fragment>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["appender","left","right","getHeightAccum","heights","R","mapAccum","keyExtractor","item","String","index","createInitialImageState","image","totalErrorCount","dimension","tryRenderingMillis","urlState","url","validity","mapImageStateToItemState","imageState","autoHandleErrorCount","imageKey","reloadButtonVisible","mapIndexed","addIndex","map","MAXIMUM_WIDTH","NUMBER_OF_ADJACENT_ITEM","ComicViewer","props","debounceMillis","fastScrollOptions","initialNumToRender","initialScrollPercentage","itemVisiblePercentThreshold","intrinsicImages","maxContentWidth","onItemPress","onScroll","onError","onReloadPress","viewportWidth","invisiblePaddingTop","windowSize","otherProps","fastScrollRef","ref","flatListRef","useRef","maybeLoadableItemsIndexRange","actualImageWidth","Math","min","initialImageStates","useMemo","imageStatesRef","mapImageStatesToItemStates","imageStates","itemStates","setItemStates","useState","current","renderedDimensions","intrinsicImage","height","width","isNaN","layoutFromDimensions","useCallback","itemHeights","totalHeight","heightAccum","itemOffsets","prepend","getItemLayout","data","length","offset","viewabilityConfig","updateImageState","updateFunction","prevImageStates","newImageStates","prevItemStates","newItemStates","equals","updateItems","indexes","Date","getTime","i","shouldRerender","includes","defaultTo","renderMaybeLoadableItems","startIndex","endIndex","affectedIndexes","range","onViewableItemsChanged","viewableItems","orderedViewableItems","sort","a","b","firstViewableIndex","head","lastViewableItemIndex","last","isNil","max","handleScroll","event","onContentScroll","scrollContentToOffset","scrollToOffset","animated","renderItem","handleError","handleReloadPress","onLoad","undefined","useEffect","floor"],"sources":["ComicViewer.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { FlatList, ListRenderItem, NativeScrollEvent, NativeSyntheticEvent, ViewToken } from 'react-native';\nimport * as R from 'ramda';\nimport { default as ComicViewerProps, Dimension, IntrinsicImage } from './ComicViewerProps';\nimport ViewerItem from './ViewerItem';\nimport FastScroll from './FastScroll';\n\nconst appender = (left: number, right: number): [number, number] => [left + right, left + right];\nconst getHeightAccum = (heights: number[]): [number, number[]] => R.mapAccum(appender, 0, heights);\n\nconst keyExtractor = <T, >(item: ItemState) => String(item.index);\n\ninterface UrlState {\n url: string;\n validity: 'valid' | 'invalid' | 'unknown';\n}\n\ninterface ImageState {\n urlState: UrlState;\n totalErrorCount: number;\n dimension: Dimension;\n tryRenderingMillis: number;\n}\n\ninterface ItemState {\n index: number;\n url?: string;\n imageKey: string;\n reloadButtonVisible: boolean;\n dimension: Dimension;\n}\n\nconst createInitialImageState = (image: IntrinsicImage): ImageState => ({\n totalErrorCount: 0,\n dimension: image.dimension,\n tryRenderingMillis: 0,\n urlState: {\n url: image.url,\n validity: 'unknown',\n },\n});\n\nconst mapImageStateToItemState = (\n index: number,\n imageState: ImageState,\n autoHandleErrorCount: number,\n): ItemState => ({\n index,\n url: imageState.urlState?.url,\n imageKey: `${imageState.tryRenderingMillis}-${index}`,\n reloadButtonVisible: (imageState.urlState?.validity !== 'valid') && imageState.totalErrorCount >= autoHandleErrorCount,\n dimension: imageState.dimension,\n});\n\nconst mapIndexed = R.addIndex<IntrinsicImage>(R.map);\n\nconst MAXIMUM_WIDTH = 720;\n\nconst NUMBER_OF_ADJACENT_ITEM = 5;\n\nexport default function ComicViewer(props: ComicViewerProps) {\n const {\n debounceMillis = 100,\n autoHandleErrorCount = 3,\n fastScrollOptions,\n initialNumToRender = 1,\n initialScrollPercentage = 0,\n itemVisiblePercentThreshold = 0,\n intrinsicImages,\n maxContentWidth = MAXIMUM_WIDTH,\n onItemPress,\n onScroll,\n onError,\n onReloadPress,\n viewportWidth,\n invisiblePaddingTop = 0,\n windowSize = 3,\n ...otherProps\n } = props;\n\n const fastScrollRef = fastScrollOptions?.ref;\n\n const flatListRef = useRef<FlatList>(null);\n\n const maybeLoadableItemsIndexRange = useRef<[number, number]>([-1, 0]);\n\n const actualImageWidth = Math.min(viewportWidth, maxContentWidth);\n\n const initialImageStates = useMemo<Array<ImageState>>(() => R.map(createInitialImageState, intrinsicImages), []);\n\n const imageStatesRef = useRef<Array<ImageState>>(initialImageStates);\n\n const mapImageStatesToItemStates = (imageStates: Array<ImageState>): Array<ItemState> => {\n return imageStates.map((image, index) => mapImageStateToItemState(\n index, image, autoHandleErrorCount,\n ));\n };\n\n const [itemStates, setItemStates] = useState<Array<ItemState>>(() => {\n return mapImageStatesToItemStates(imageStatesRef.current);\n });\n\n const renderedDimensions = useMemo<Array<Dimension>>(() => {\n return mapIndexed((intrinsicImage, index) => {\n const height = (intrinsicImage.dimension.height * actualImageWidth) / intrinsicImage.dimension.width + (index === 0 ? invisiblePaddingTop : 0);\n\n return {\n width: actualImageWidth,\n height: isNaN(height) ? 0 : height,\n };\n }, intrinsicImages);\n }, [actualImageWidth]);\n\n const layoutFromDimensions = useCallback(() => {\n const itemHeights = R.map(dimension => dimension.height, renderedDimensions);\n const [totalHeight, heightAccum] = getHeightAccum(itemHeights);\n const itemOffsets = R.prepend(0, heightAccum);\n\n const getItemLayout = (data: any, index: number) => ({\n index,\n length: itemHeights[index],\n offset: itemOffsets[index],\n });\n\n return {\n totalHeight,\n getItemLayout,\n };\n }, [renderedDimensions]);\n\n const { totalHeight, getItemLayout } = layoutFromDimensions();\n\n const viewabilityConfig = useMemo(() => ({\n itemVisiblePercentThreshold,\n }), [itemVisiblePercentThreshold]);\n\n const updateImageState = (updateFunction: (prev: ImageState, index: number) => ImageState) => {\n const prevImageStates = imageStatesRef.current;\n const newImageStates = prevImageStates.map(updateFunction);\n\n imageStatesRef.current = newImageStates;\n\n setItemStates(prevItemStates => {\n const newItemStates = mapImageStatesToItemStates(newImageStates);\n\n return R.equals(prevItemStates, newItemStates) ? prevItemStates : newItemStates;\n });\n };\n\n const updateItems = (indexes: number[]) => {\n const tryRenderingMillis = new Date().getTime();\n\n updateImageState((imageState, i) => {\n const urlState = imageState.urlState;\n const shouldRerender = R.includes(i, R.defaultTo([], indexes));\n\n if (shouldRerender && urlState?.validity !== 'valid') {\n return {\n ...imageState,\n tryRenderingMillis,\n };\n }\n\n return imageState;\n });\n };\n\n const renderMaybeLoadableItems = () => {\n const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;\n const affectedIndexes = R.range(startIndex, endIndex);\n\n updateItems(affectedIndexes);\n };\n\n const onViewableItemsChanged = useRef(({ viewableItems }: { viewableItems: Array<ViewToken> }) => {\n const orderedViewableItems = R.sort((a, b) => (a.index || 0) - (b.index || 0), viewableItems);\n\n const firstViewableIndex = R.head(orderedViewableItems)?.index;\n const lastViewableItemIndex = R.last(orderedViewableItems)?.index;\n\n if (R.isNil(firstViewableIndex) || R.isNil(lastViewableItemIndex)) {\n return;\n }\n\n const startIndex = R.max(firstViewableIndex - NUMBER_OF_ADJACENT_ITEM, 0);\n const endIndex = R.min(lastViewableItemIndex + NUMBER_OF_ADJACENT_ITEM, itemStates.length - 1);\n\n maybeLoadableItemsIndexRange.current = [startIndex, endIndex + 1];\n\n renderMaybeLoadableItems();\n });\n\n const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {\n fastScrollRef?.current?.onContentScroll(event);\n\n onScroll?.(event);\n }, [onScroll]);\n\n const scrollContentToOffset = (offset: number) => {\n flatListRef.current?.scrollToOffset({\n offset,\n animated: false,\n });\n };\n\n const renderItem: ListRenderItem<ItemState> = useCallback(({ item, index }) => {\n const handleError = () => {\n onError && onError();\n\n updateImageState((imageState, i) => {\n const urlState = imageState.urlState;\n\n if (i === index) {\n return {\n ...imageState,\n totalErrorCount: imageState.totalErrorCount + 1,\n urlState: {\n ...urlState,\n validity: 'invalid',\n },\n };\n }\n\n return imageState;\n });\n\n if (item.reloadButtonVisible) {\n return;\n }\n\n const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;\n if (index >= startIndex || index < endIndex) {\n renderMaybeLoadableItems();\n }\n };\n\n const handleReloadPress = () => {\n onReloadPress && onReloadPress();\n\n updateItems([index]);\n };\n\n const onLoad = () => {\n updateImageState((imageState, i) => {\n const urlState = imageState.urlState;\n\n if (i === index && urlState !== undefined) {\n return {\n ...imageState,\n urlState: {\n ...urlState,\n validity: 'valid',\n },\n };\n }\n\n return imageState;\n });\n };\n\n return (\n <ViewerItem\n onError={handleError}\n onLoad={onLoad}\n onPress={onItemPress}\n onReloadPress={handleReloadPress}\n url={item.url}\n imageKey={item.imageKey}\n invisiblePaddingTop={index === 0 ? invisiblePaddingTop : 0}\n width={renderedDimensions[index]?.width ?? 0}\n height={renderedDimensions[index]?.height ?? 0}\n reloadButtonVisible={item.reloadButtonVisible}\n />\n );\n }, [onItemPress, renderedDimensions]);\n\n useEffect(() => {\n const offset = Math.floor((initialScrollPercentage / 100) * totalHeight);\n\n if (flatListRef.current) {\n flatListRef.current.scrollToOffset({ offset, animated: false });\n }\n }, []);\n\n return (\n <React.Fragment>\n <FlatList\n data={itemStates}\n getItemLayout={getItemLayout}\n initialNumToRender={initialNumToRender}\n keyExtractor={keyExtractor}\n onViewableItemsChanged={onViewableItemsChanged.current}\n ref={flatListRef}\n renderItem={renderItem}\n viewabilityConfig={viewabilityConfig}\n windowSize={windowSize}\n onScroll={handleScroll}\n {...otherProps}\n />\n\n <FastScroll\n {...fastScrollOptions}\n contentLength={totalHeight}\n scrollContentToOffset={scrollContentToOffset}\n />\n </React.Fragment>\n );\n};\n"],"mappings":";;;;;;;AAAA;;AACA;;AACA;;AAEA;;AACA;;;;;;;;;;AAEA,MAAMA,QAAQ,GAAG,CAACC,IAAD,EAAeC,KAAf,KAAmD,CAACD,IAAI,GAAGC,KAAR,EAAeD,IAAI,GAAGC,KAAtB,CAApE;;AACA,MAAMC,cAAc,GAAIC,OAAD,IAA2CC,CAAC,CAACC,QAAF,CAAWN,QAAX,EAAqB,CAArB,EAAwBI,OAAxB,CAAlE;;AAEA,MAAMG,YAAY,GAASC,IAAN,IAA0BC,MAAM,CAACD,IAAI,CAACE,KAAN,CAArD;;AAsBA,MAAMC,uBAAuB,GAAIC,KAAD,KAAwC;EACpEC,eAAe,EAAE,CADmD;EAEpEC,SAAS,EAAEF,KAAK,CAACE,SAFmD;EAGpEC,kBAAkB,EAAE,CAHgD;EAIpEC,QAAQ,EAAE;IACNC,GAAG,EAAEL,KAAK,CAACK,GADL;IAENC,QAAQ,EAAE;EAFJ;AAJ0D,CAAxC,CAAhC;;AAUA,MAAMC,wBAAwB,GAAG,CAC7BT,KAD6B,EAE7BU,UAF6B,EAG7BC,oBAH6B;EAAA;;EAAA,OAIhB;IACbX,KADa;IAEbO,GAAG,0BAAEG,UAAU,CAACJ,QAAb,yDAAE,qBAAqBC,GAFb;IAGbK,QAAQ,EAAG,GAAEF,UAAU,CAACL,kBAAmB,IAAGL,KAAM,EAHvC;IAIba,mBAAmB,EAAG,0BAAAH,UAAU,CAACJ,QAAX,gFAAqBE,QAArB,MAAkC,OAAnC,IAA+CE,UAAU,CAACP,eAAX,IAA8BQ,oBAJrF;IAKbP,SAAS,EAAEM,UAAU,CAACN;EALT,CAJgB;AAAA,CAAjC;;AAYA,MAAMU,UAAU,GAAGnB,CAAC,CAACoB,QAAF,CAA2BpB,CAAC,CAACqB,GAA7B,CAAnB;AAEA,MAAMC,aAAa,GAAG,GAAtB;AAEA,MAAMC,uBAAuB,GAAG,CAAhC;;AAEe,SAASC,WAAT,CAAqBC,KAArB,EAA8C;EACzD,MAAM;IACFC,cAAc,GAAG,GADf;IAEFV,oBAAoB,GAAG,CAFrB;IAGFW,iBAHE;IAIFC,kBAAkB,GAAG,CAJnB;IAKFC,uBAAuB,GAAG,CALxB;IAMFC,2BAA2B,GAAG,CAN5B;IAOFC,eAPE;IAQFC,eAAe,GAAGV,aARhB;IASFW,WATE;IAUFC,QAVE;IAWFC,OAXE;IAYFC,aAZE;IAaFC,aAbE;IAcFC,mBAAmB,GAAG,CAdpB;IAeFC,UAAU,GAAG,CAfX;IAgBF,GAAGC;EAhBD,IAiBFf,KAjBJ;EAmBA,MAAMgB,aAAa,GAAGd,iBAAH,aAAGA,iBAAH,uBAAGA,iBAAiB,CAAEe,GAAzC;EAEA,MAAMC,WAAW,GAAG,IAAAC,aAAA,EAAiB,IAAjB,CAApB;EAEA,MAAMC,4BAA4B,GAAG,IAAAD,aAAA,EAAyB,CAAC,CAAC,CAAF,EAAK,CAAL,CAAzB,CAArC;EAEA,MAAME,gBAAgB,GAAGC,IAAI,CAACC,GAAL,CAASX,aAAT,EAAwBL,eAAxB,CAAzB;EAEA,MAAMiB,kBAAkB,GAAG,IAAAC,cAAA,EAA2B,MAAMlD,CAAC,CAACqB,GAAF,CAAMf,uBAAN,EAA+ByB,eAA/B,CAAjC,EAAkF,EAAlF,CAA3B;EAEA,MAAMoB,cAAc,GAAG,IAAAP,aAAA,EAA0BK,kBAA1B,CAAvB;;EAEA,MAAMG,0BAA0B,GAAIC,WAAD,IAAsD;IACrF,OAAOA,WAAW,CAAChC,GAAZ,CAAgB,CAACd,KAAD,EAAQF,KAAR,KAAkBS,wBAAwB,CAC7DT,KAD6D,EACtDE,KADsD,EAC/CS,oBAD+C,CAA1D,CAAP;EAGH,CAJD;;EAMA,MAAM,CAACsC,UAAD,EAAaC,aAAb,IAA8B,IAAAC,eAAA,EAA2B,MAAM;IACjE,OAAOJ,0BAA0B,CAACD,cAAc,CAACM,OAAhB,CAAjC;EACH,CAFmC,CAApC;EAIA,MAAMC,kBAAkB,GAAG,IAAAR,cAAA,EAA0B,MAAM;IACvD,OAAO/B,UAAU,CAAC,CAACwC,cAAD,EAAiBtD,KAAjB,KAA2B;MACzC,MAAMuD,MAAM,GAAID,cAAc,CAAClD,SAAf,CAAyBmD,MAAzB,GAAkCd,gBAAnC,GAAuDa,cAAc,CAAClD,SAAf,CAAyBoD,KAAhF,IAAyFxD,KAAK,KAAK,CAAV,GAAciC,mBAAd,GAAoC,CAA7H,CAAf;MAEA,OAAO;QACHuB,KAAK,EAAEf,gBADJ;QAEHc,MAAM,EAAEE,KAAK,CAACF,MAAD,CAAL,GAAgB,CAAhB,GAAoBA;MAFzB,CAAP;IAIH,CAPgB,EAOd7B,eAPc,CAAjB;EAQH,CAT0B,EASxB,CAACe,gBAAD,CATwB,CAA3B;EAWA,MAAMiB,oBAAoB,GAAG,IAAAC,kBAAA,EAAY,MAAM;IAC3C,MAAMC,WAAW,GAAGjE,CAAC,CAACqB,GAAF,CAAMZ,SAAS,IAAIA,SAAS,CAACmD,MAA7B,EAAqCF,kBAArC,CAApB;IACA,MAAM,CAACQ,WAAD,EAAcC,WAAd,IAA6BrE,cAAc,CAACmE,WAAD,CAAjD;IACA,MAAMG,WAAW,GAAGpE,CAAC,CAACqE,OAAF,CAAU,CAAV,EAAaF,WAAb,CAApB;;IAEA,MAAMG,aAAa,GAAG,CAACC,IAAD,EAAYlE,KAAZ,MAA+B;MACjDA,KADiD;MAEjDmE,MAAM,EAAEP,WAAW,CAAC5D,KAAD,CAF8B;MAGjDoE,MAAM,EAAEL,WAAW,CAAC/D,KAAD;IAH8B,CAA/B,CAAtB;;IAMA,OAAO;MACH6D,WADG;MAEHI;IAFG,CAAP;EAIH,CAf4B,EAe1B,CAACZ,kBAAD,CAf0B,CAA7B;EAiBA,MAAM;IAAEQ,WAAF;IAAeI;EAAf,IAAiCP,oBAAoB,EAA3D;EAEA,MAAMW,iBAAiB,GAAG,IAAAxB,cAAA,EAAQ,OAAO;IACrCpB;EADqC,CAAP,CAAR,EAEtB,CAACA,2BAAD,CAFsB,CAA1B;;EAIA,MAAM6C,gBAAgB,GAAIC,cAAD,IAAqE;IAC1F,MAAMC,eAAe,GAAG1B,cAAc,CAACM,OAAvC;IACA,MAAMqB,cAAc,GAAGD,eAAe,CAACxD,GAAhB,CAAoBuD,cAApB,CAAvB;IAEAzB,cAAc,CAACM,OAAf,GAAyBqB,cAAzB;IAEAvB,aAAa,CAACwB,cAAc,IAAI;MAC5B,MAAMC,aAAa,GAAG5B,0BAA0B,CAAC0B,cAAD,CAAhD;MAEA,OAAO9E,CAAC,CAACiF,MAAF,CAASF,cAAT,EAAyBC,aAAzB,IAA0CD,cAA1C,GAA2DC,aAAlE;IACH,CAJY,CAAb;EAKH,CAXD;;EAaA,MAAME,WAAW,GAAIC,OAAD,IAAuB;IACvC,MAAMzE,kBAAkB,GAAG,IAAI0E,IAAJ,GAAWC,OAAX,EAA3B;IAEAV,gBAAgB,CAAC,CAAC5D,UAAD,EAAauE,CAAb,KAAmB;MAChC,MAAM3E,QAAQ,GAAGI,UAAU,CAACJ,QAA5B;MACA,MAAM4E,cAAc,GAAGvF,CAAC,CAACwF,QAAF,CAAWF,CAAX,EAActF,CAAC,CAACyF,SAAF,CAAY,EAAZ,EAAgBN,OAAhB,CAAd,CAAvB;;MAEA,IAAII,cAAc,IAAI,CAAA5E,QAAQ,SAAR,IAAAA,QAAQ,WAAR,YAAAA,QAAQ,CAAEE,QAAV,MAAuB,OAA7C,EAAsD;QAClD,OAAO,EACH,GAAGE,UADA;UAEHL;QAFG,CAAP;MAIH;;MAED,OAAOK,UAAP;IACH,CAZe,CAAhB;EAaH,CAhBD;;EAkBA,MAAM2E,wBAAwB,GAAG,MAAM;IACnC,MAAM,CAACC,UAAD,EAAaC,QAAb,IAAyB/C,4BAA4B,CAACY,OAA5D;IACA,MAAMoC,eAAe,GAAG7F,CAAC,CAAC8F,KAAF,CAAQH,UAAR,EAAoBC,QAApB,CAAxB;IAEAV,WAAW,CAACW,eAAD,CAAX;EACH,CALD;;EAOA,MAAME,sBAAsB,GAAG,IAAAnD,aAAA,EAAO,QAA4D;IAAA;;IAAA,IAA3D;MAAEoD;IAAF,CAA2D;IAC9F,MAAMC,oBAAoB,GAAGjG,CAAC,CAACkG,IAAF,CAAO,CAACC,CAAD,EAAIC,CAAJ,KAAU,CAACD,CAAC,CAAC9F,KAAF,IAAW,CAAZ,KAAkB+F,CAAC,CAAC/F,KAAF,IAAW,CAA7B,CAAjB,EAAkD2F,aAAlD,CAA7B;IAEA,MAAMK,kBAAkB,cAAGrG,CAAC,CAACsG,IAAF,CAAOL,oBAAP,CAAH,4CAAG,QAA8B5F,KAAzD;IACA,MAAMkG,qBAAqB,cAAGvG,CAAC,CAACwG,IAAF,CAAOP,oBAAP,CAAH,4CAAG,QAA8B5F,KAA5D;;IAEA,IAAIL,CAAC,CAACyG,KAAF,CAAQJ,kBAAR,KAA+BrG,CAAC,CAACyG,KAAF,CAAQF,qBAAR,CAAnC,EAAmE;MAC/D;IACH;;IAED,MAAMZ,UAAU,GAAG3F,CAAC,CAAC0G,GAAF,CAAML,kBAAkB,GAAG9E,uBAA3B,EAAoD,CAApD,CAAnB;IACA,MAAMqE,QAAQ,GAAG5F,CAAC,CAACgD,GAAF,CAAMuD,qBAAqB,GAAGhF,uBAA9B,EAAuD+B,UAAU,CAACkB,MAAX,GAAoB,CAA3E,CAAjB;IAEA3B,4BAA4B,CAACY,OAA7B,GAAuC,CAACkC,UAAD,EAAaC,QAAQ,GAAG,CAAxB,CAAvC;IAEAF,wBAAwB;EAC3B,CAhB8B,CAA/B;EAkBA,MAAMiB,YAAY,GAAG,IAAA3C,kBAAA,EAAa4C,KAAD,IAAoD;IAAA;;IACjFnE,aAAa,SAAb,IAAAA,aAAa,WAAb,qCAAAA,aAAa,CAAEgB,OAAf,gFAAwBoD,eAAxB,CAAwCD,KAAxC;IAEA1E,QAAQ,SAAR,IAAAA,QAAQ,WAAR,YAAAA,QAAQ,CAAG0E,KAAH,CAAR;EACH,CAJoB,EAIlB,CAAC1E,QAAD,CAJkB,CAArB;;EAMA,MAAM4E,qBAAqB,GAAIrC,MAAD,IAAoB;IAAA;;IAC9C,wBAAA9B,WAAW,CAACc,OAAZ,8EAAqBsD,cAArB,CAAoC;MAChCtC,MADgC;MAEhCuC,QAAQ,EAAE;IAFsB,CAApC;EAIH,CALD;;EAOA,MAAMC,UAAqC,GAAG,IAAAjD,kBAAA,EAAY,SAAqB;IAAA;;IAAA,IAApB;MAAE7D,IAAF;MAAQE;IAAR,CAAoB;;IAC3E,MAAM6G,WAAW,GAAG,MAAM;MACtB/E,OAAO,IAAIA,OAAO,EAAlB;MAEAwC,gBAAgB,CAAC,CAAC5D,UAAD,EAAauE,CAAb,KAAmB;QAChC,MAAM3E,QAAQ,GAAGI,UAAU,CAACJ,QAA5B;;QAEA,IAAI2E,CAAC,KAAKjF,KAAV,EAAiB;UACb,OAAO,EACH,GAAGU,UADA;YAEHP,eAAe,EAAEO,UAAU,CAACP,eAAX,GAA6B,CAF3C;YAGHG,QAAQ,EAAE,EACN,GAAGA,QADG;cAENE,QAAQ,EAAE;YAFJ;UAHP,CAAP;QAQH;;QAED,OAAOE,UAAP;MACH,CAfe,CAAhB;;MAiBA,IAAIZ,IAAI,CAACe,mBAAT,EAA8B;QAC1B;MACH;;MAED,MAAM,CAACyE,UAAD,EAAaC,QAAb,IAAyB/C,4BAA4B,CAACY,OAA5D;;MACA,IAAIpD,KAAK,IAAIsF,UAAT,IAAuBtF,KAAK,GAAGuF,QAAnC,EAA6C;QACzCF,wBAAwB;MAC3B;IACJ,CA5BD;;IA8BA,MAAMyB,iBAAiB,GAAG,MAAM;MAC5B/E,aAAa,IAAIA,aAAa,EAA9B;MAEA8C,WAAW,CAAC,CAAC7E,KAAD,CAAD,CAAX;IACH,CAJD;;IAMA,MAAM+G,MAAM,GAAG,MAAM;MACjBzC,gBAAgB,CAAC,CAAC5D,UAAD,EAAauE,CAAb,KAAmB;QAChC,MAAM3E,QAAQ,GAAGI,UAAU,CAACJ,QAA5B;;QAEA,IAAI2E,CAAC,KAAKjF,KAAN,IAAeM,QAAQ,KAAK0G,SAAhC,EAA2C;UACvC,OAAO,EACH,GAAGtG,UADA;YAEHJ,QAAQ,EAAE,EACN,GAAGA,QADG;cAENE,QAAQ,EAAE;YAFJ;UAFP,CAAP;QAOH;;QAED,OAAOE,UAAP;MACH,CAde,CAAhB;IAeH,CAhBD;;IAkBA,oBACI,6BAAC,mBAAD;MACI,OAAO,EAAEmG,WADb;MAEI,MAAM,EAAEE,MAFZ;MAGI,OAAO,EAAEnF,WAHb;MAII,aAAa,EAAEkF,iBAJnB;MAKI,GAAG,EAAEhH,IAAI,CAACS,GALd;MAMI,QAAQ,EAAET,IAAI,CAACc,QANnB;MAOI,mBAAmB,EAAEZ,KAAK,KAAK,CAAV,GAAciC,mBAAd,GAAoC,CAP7D;MAQI,KAAK,EAAE,0BAAAoB,kBAAkB,CAACrD,KAAD,CAAlB,gFAA2BwD,KAA3B,KAAoC,CAR/C;MASI,MAAM,EAAE,2BAAAH,kBAAkB,CAACrD,KAAD,CAAlB,kFAA2BuD,MAA3B,KAAqC,CATjD;MAUI,mBAAmB,EAAEzD,IAAI,CAACe;IAV9B,EADJ;EAcH,CArE6C,EAqE3C,CAACe,WAAD,EAAcyB,kBAAd,CArE2C,CAA9C;EAuEA,IAAA4D,gBAAA,EAAU,MAAM;IACZ,MAAM7C,MAAM,GAAG1B,IAAI,CAACwE,KAAL,CAAY1F,uBAAuB,GAAG,GAA3B,GAAkCqC,WAA7C,CAAf;;IAEA,IAAIvB,WAAW,CAACc,OAAhB,EAAyB;MACrBd,WAAW,CAACc,OAAZ,CAAoBsD,cAApB,CAAmC;QAAEtC,MAAF;QAAUuC,QAAQ,EAAE;MAApB,CAAnC;IACH;EACJ,CAND,EAMG,EANH;EAQA,oBACI,6BAAC,cAAD,CAAO,QAAP,qBACI,6BAAC,qBAAD;IACI,IAAI,EAAE1D,UADV;IAEI,aAAa,EAAEgB,aAFnB;IAGI,kBAAkB,EAAE1C,kBAHxB;IAII,YAAY,EAAE1B,YAJlB;IAKI,sBAAsB,EAAE6F,sBAAsB,CAACtC,OALnD;IAMI,GAAG,EAAEd,WANT;IAOI,UAAU,EAAEsE,UAPhB;IAQI,iBAAiB,EAAEvC,iBARvB;IASI,UAAU,EAAEnC,UAThB;IAUI,QAAQ,EAAEoE;EAVd,GAWQnE,UAXR,EADJ,eAeI,6BAAC,mBAAD,eACQb,iBADR;IAEI,aAAa,EAAEuC,WAFnB;IAGI,qBAAqB,EAAE4C;EAH3B,GAfJ,CADJ;AAuBH;;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["ComicViewerProps.ts"],"sourcesContent":["import React from 'react';\nimport { ComponentProps } from '@fountain-ui/core';\nimport { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';\nimport { FastScrollOptions } from './FastScrollProps';\n\nexport interface Dimension {\n width: number;\n height: number;\n}\n\nexport default interface ComicViewerProps extends ComponentProps <{\n /**\n * Delay Time to call the error handler.\n * @default 100\n */\n debounceMillis?: number;\n\n /**\n * How many times handle onError directly when item error occur\n * @default 3\n */\n autoHandleErrorCount?: number;\n\n /**\n * How many items to render in the initial batch.\n * @default 1\n */\n initialNumToRender?: number;\n\n /**\n * Start at initialScrollPercentage.\n * If over 100, scroll to end.\n * @default 0\n */\n initialScrollPercentage?: number;\n\n /**\n * The value for FlatList viewabilityConfig.itemVisiblePercentThreshold.\n * @default 0\n */\n itemVisiblePercentThreshold?: number;\n\n /**\n * Dimensions of each Image considering viewport.\n */\n
|
|
1
|
+
{"version":3,"names":[],"sources":["ComicViewerProps.ts"],"sourcesContent":["import React from 'react';\nimport { ComponentProps } from '@fountain-ui/core';\nimport { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';\nimport { FastScrollOptions } from './FastScrollProps';\n\nexport interface Dimension {\n width: number;\n height: number;\n}\n\nexport interface IntrinsicImage {\n dimension: Dimension;\n url: string;\n}\n\nexport default interface ComicViewerProps extends ComponentProps <{\n /**\n * Delay Time to call the error handler.\n * @default 100\n */\n debounceMillis?: number;\n\n /**\n * How many times handle onError directly when item error occur\n * @default 3\n */\n autoHandleErrorCount?: number;\n\n /**\n * How many items to render in the initial batch.\n * @default 1\n */\n initialNumToRender?: number;\n\n /**\n * Start at initialScrollPercentage.\n * If over 100, scroll to end.\n * @default 0\n */\n initialScrollPercentage?: number;\n\n /**\n * The value for FlatList viewabilityConfig.itemVisiblePercentThreshold.\n * @default 0\n */\n itemVisiblePercentThreshold?: number;\n\n /**\n * Dimensions and url info of each Image considering viewport.\n */\n intrinsicImages: Array<IntrinsicImage>;\n\n /**\n * Need invisible paddingTop viewer vertically expanded.\n * @default 0\n */\n invisiblePaddingTop?: number;\n\n /**\n * Max value of contents image width size.\n * @default 720\n */\n maxContentWidth?: number;\n\n /**\n * Width of viewport.\n */\n viewportWidth: number;\n\n /**\n * The value for FlatList windowSize.\n * @default 3\n */\n windowSize?: number;\n\n /**\n * Options for fastscroll component.\n */\n fastScrollOptions: FastScrollOptions;\n\n /**\n * Handle scroll event.\n * @param event Scroll event.\n */\n onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;\n\n /**\n * Handle item press event.\n */\n onItemPress?: () => void;\n\n /**\n * Handle image loading fail event.\n */\n onError?: () => void;\n\n /**\n * Handle reload button press event.\n */\n onReloadPress?: () => void;\n\n /**\n * Component for comic viewer footer.\n */\n ListFooterComponent?: React.ReactElement;\n}> {}\n"],"mappings":""}
|
|
@@ -22,6 +22,7 @@ function ViewerItem(props) {
|
|
|
22
22
|
height,
|
|
23
23
|
url,
|
|
24
24
|
width,
|
|
25
|
+
imageKey,
|
|
25
26
|
invisiblePaddingTop,
|
|
26
27
|
onError,
|
|
27
28
|
onLoad,
|
|
@@ -57,6 +58,7 @@ function ViewerItem(props) {
|
|
|
57
58
|
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
58
59
|
style: styles.view
|
|
59
60
|
}, /*#__PURE__*/_react.default.createElement(_core.Image, {
|
|
61
|
+
key: imageKey,
|
|
60
62
|
cache: 'web',
|
|
61
63
|
disableDrag: true,
|
|
62
64
|
disableLongClick: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["ViewerItem","props","height","url","width","invisiblePaddingTop","onError","onLoad","onPress","onReloadPress","reloadButtonVisible","styles","view","paddingTop","image","error","placeholder","uri","EncodedTile","css","alignSelf"],"sources":["ViewerItem.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, TouchableWithoutFeedback, View } from 'react-native';\nimport { css, Image as FuiImage, ImageProps } from '@fountain-ui/core';\nimport ReloadButton from './ReloadButton';\nimport EncodedTile from './EncodedTile';\n\nexport interface ViewerItemProps {\n /**\n * Image width.\n */\n width: number;\n\n /**\n * Image height.\n */\n height: number;\n\n /**\n * Need invisible paddingTop viewer vertically expanded.\n */\n invisiblePaddingTop: number;\n\n /**\n * Image sourceUrl for displaying.\n */\n url?: string;\n\n /**\n * Error handler.\n */\n onError?: ImageProps['onError'];\n\n /**\n * Load handler.\n */\n onLoad?: ImageProps['onLoad'];\n\n /**\n * Handle Reload button press event.\n */\n onReloadPress?: ImageProps['onError'];\n\n /**\n * Handle item press event.\n */\n onPress?: () => void;\n\n /**\n * If true, reload button visible.\n * @default false\n */\n reloadButtonVisible?: boolean;\n}\n\nexport default function ViewerItem(props: ViewerItemProps) {\n const {\n height,\n url,\n width,\n invisiblePaddingTop,\n onError,\n onLoad,\n onPress,\n onReloadPress,\n reloadButtonVisible = false,\n } = props;\n\n const styles = {\n view: {\n height,\n width: '100%',\n paddingTop: invisiblePaddingTop,\n },\n image: {\n height: height - invisiblePaddingTop,\n width,\n },\n };\n\n const error = reloadButtonVisible ? <ReloadButton onPress={onReloadPress}/> : null;\n\n const placeholder = <Image\n source={{ uri: EncodedTile }}\n resizeMode={'cover'}\n style={styles.image}\n />;\n\n return (\n <TouchableWithoutFeedback onPress={onPress}>\n <View style={styles.view}>\n <FuiImage\n cache={'web'}\n disableDrag={true}\n disableLongClick={true}\n disableOutline={true}\n error={error}\n onError={onError}\n onLoad={onLoad}\n loading={'eager'}\n placeholder={placeholder}\n source={{ uri: url }}\n square={true}\n style={css([\n { alignSelf: 'center' },\n styles.image,\n ])}\n />\n </View>\n </TouchableWithoutFeedback>\n );\n};\n"],"mappings":";;;;;;;AAAA;;AACA;;AACA;;AACA;;AACA;;;;
|
|
1
|
+
{"version":3,"names":["ViewerItem","props","height","url","width","imageKey","invisiblePaddingTop","onError","onLoad","onPress","onReloadPress","reloadButtonVisible","styles","view","paddingTop","image","error","placeholder","uri","EncodedTile","css","alignSelf"],"sources":["ViewerItem.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, TouchableWithoutFeedback, View } from 'react-native';\nimport { css, Image as FuiImage, ImageProps } from '@fountain-ui/core';\nimport ReloadButton from './ReloadButton';\nimport EncodedTile from './EncodedTile';\n\nexport interface ViewerItemProps {\n /**\n * Image width.\n */\n width: number;\n\n /**\n * Image height.\n */\n height: number;\n\n /**\n * Need invisible paddingTop viewer vertically expanded.\n */\n invisiblePaddingTop: number;\n\n /**\n * Image sourceUrl for displaying.\n */\n url?: string;\n\n /**\n * Error handler.\n */\n onError?: ImageProps['onError'];\n\n /**\n * Load handler.\n */\n onLoad?: ImageProps['onLoad'];\n\n /**\n * Handle Reload button press event.\n */\n onReloadPress?: ImageProps['onError'];\n\n /**\n * Handle item press event.\n */\n onPress?: () => void;\n\n /**\n * If true, reload button visible.\n * @default false\n */\n reloadButtonVisible?: boolean;\n\n /**\n * FuiImage key for trigger image rerender.\n */\n imageKey: string;\n}\n\nexport default function ViewerItem(props: ViewerItemProps) {\n const {\n height,\n url,\n width,\n imageKey,\n invisiblePaddingTop,\n onError,\n onLoad,\n onPress,\n onReloadPress,\n reloadButtonVisible = false,\n } = props;\n\n const styles = {\n view: {\n height,\n width: '100%',\n paddingTop: invisiblePaddingTop,\n },\n image: {\n height: height - invisiblePaddingTop,\n width,\n },\n };\n\n const error = reloadButtonVisible ? <ReloadButton onPress={onReloadPress}/> : null;\n\n const placeholder = <Image\n source={{ uri: EncodedTile }}\n resizeMode={'cover'}\n style={styles.image}\n />;\n\n return (\n <TouchableWithoutFeedback onPress={onPress}>\n <View style={styles.view}>\n <FuiImage\n key={imageKey}\n cache={'web'}\n disableDrag={true}\n disableLongClick={true}\n disableOutline={true}\n error={error}\n onError={onError}\n onLoad={onLoad}\n loading={'eager'}\n placeholder={placeholder}\n source={{ uri: url }}\n square={true}\n style={css([\n { alignSelf: 'center' },\n styles.image,\n ])}\n />\n </View>\n </TouchableWithoutFeedback>\n );\n};\n"],"mappings":";;;;;;;AAAA;;AACA;;AACA;;AACA;;AACA;;;;AAuDe,SAASA,UAAT,CAAoBC,KAApB,EAA4C;EACvD,MAAM;IACFC,MADE;IAEFC,GAFE;IAGFC,KAHE;IAIFC,QAJE;IAKFC,mBALE;IAMFC,OANE;IAOFC,MAPE;IAQFC,OARE;IASFC,aATE;IAUFC,mBAAmB,GAAG;EAVpB,IAWFV,KAXJ;EAaA,MAAMW,MAAM,GAAG;IACXC,IAAI,EAAE;MACFX,MADE;MAEFE,KAAK,EAAE,MAFL;MAGFU,UAAU,EAAER;IAHV,CADK;IAMXS,KAAK,EAAE;MACHb,MAAM,EAAEA,MAAM,GAAGI,mBADd;MAEHF;IAFG;EANI,CAAf;EAYA,MAAMY,KAAK,GAAGL,mBAAmB,gBAAG,6BAAC,qBAAD;IAAc,OAAO,EAAED;EAAvB,EAAH,GAA6C,IAA9E;;EAEA,MAAMO,WAAW,gBAAG,6BAAC,kBAAD;IAChB,MAAM,EAAE;MAAEC,GAAG,EAAEC;IAAP,CADQ;IAEhB,UAAU,EAAE,OAFI;IAGhB,KAAK,EAAEP,MAAM,CAACG;EAHE,EAApB;;EAMA,oBACI,6BAAC,qCAAD;IAA0B,OAAO,EAAEN;EAAnC,gBACI,6BAAC,iBAAD;IAAM,KAAK,EAAEG,MAAM,CAACC;EAApB,gBACI,6BAAC,WAAD;IACI,GAAG,EAAER,QADT;IAEI,KAAK,EAAE,KAFX;IAGI,WAAW,EAAE,IAHjB;IAII,gBAAgB,EAAE,IAJtB;IAKI,cAAc,EAAE,IALpB;IAMI,KAAK,EAAEW,KANX;IAOI,OAAO,EAAET,OAPb;IAQI,MAAM,EAAEC,MARZ;IASI,OAAO,EAAE,OATb;IAUI,WAAW,EAAES,WAVjB;IAWI,MAAM,EAAE;MAAEC,GAAG,EAAEf;IAAP,CAXZ;IAYI,MAAM,EAAE,IAZZ;IAaI,KAAK,EAAE,IAAAiB,SAAA,EAAI,CACP;MAAEC,SAAS,EAAE;IAAb,CADO,EAEPT,MAAM,CAACG,KAFA,CAAJ;EAbX,EADJ,CADJ,CADJ;AAwBH;;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["index.ts"],"sourcesContent":["export { default } from './ComicViewer';\nexport type { Dimension, default as ComicViewerProps } from './ComicViewerProps';\nexport type { ViewerItemProps } from './ViewerItem';\nexport type {\n AbsolutePosition,\n FastScrollInstance,\n FastScrollOptions,\n VisibleDurations,\n} from './FastScrollProps';\n"],"mappings":";;;;;;;;;;;;AAAA"}
|
|
1
|
+
{"version":3,"names":[],"sources":["index.ts"],"sourcesContent":["export { default } from './ComicViewer';\nexport type { Dimension, IntrinsicImage, default as ComicViewerProps } from './ComicViewerProps';\nexport type { ViewerItemProps } from './ViewerItem';\nexport type {\n AbsolutePosition,\n FastScrollInstance,\n FastScrollOptions,\n VisibleDurations,\n} from './FastScrollProps';\n"],"mappings":";;;;;;;;;;;;AAAA"}
|
|
@@ -3,7 +3,6 @@ function _extends() { _extends = Object.assign ? Object.assign.bind() : function
|
|
|
3
3
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import { FlatList } from 'react-native';
|
|
5
5
|
import * as R from 'ramda';
|
|
6
|
-
import { useDebounce } from '@fountain-ui/core';
|
|
7
6
|
import ViewerItem from './ViewerItem';
|
|
8
7
|
import FastScroll from './FastScroll';
|
|
9
8
|
|
|
@@ -13,10 +12,14 @@ const getHeightAccum = heights => R.mapAccum(appender, 0, heights);
|
|
|
13
12
|
|
|
14
13
|
const keyExtractor = item => String(item.index);
|
|
15
14
|
|
|
16
|
-
const createInitialImageState =
|
|
17
|
-
isNewUrlIncoming: false,
|
|
15
|
+
const createInitialImageState = image => ({
|
|
18
16
|
totalErrorCount: 0,
|
|
19
|
-
dimension
|
|
17
|
+
dimension: image.dimension,
|
|
18
|
+
tryRenderingMillis: 0,
|
|
19
|
+
urlState: {
|
|
20
|
+
url: image.url,
|
|
21
|
+
validity: 'unknown'
|
|
22
|
+
}
|
|
20
23
|
});
|
|
21
24
|
|
|
22
25
|
const mapImageStateToItemState = (index, imageState, autoHandleErrorCount) => {
|
|
@@ -25,6 +28,7 @@ const mapImageStateToItemState = (index, imageState, autoHandleErrorCount) => {
|
|
|
25
28
|
return {
|
|
26
29
|
index,
|
|
27
30
|
url: (_imageState$urlState = imageState.urlState) === null || _imageState$urlState === void 0 ? void 0 : _imageState$urlState.url,
|
|
31
|
+
imageKey: `${imageState.tryRenderingMillis}-${index}`,
|
|
28
32
|
reloadButtonVisible: ((_imageState$urlState2 = imageState.urlState) === null || _imageState$urlState2 === void 0 ? void 0 : _imageState$urlState2.validity) !== 'valid' && imageState.totalErrorCount >= autoHandleErrorCount,
|
|
29
33
|
dimension: imageState.dimension
|
|
30
34
|
};
|
|
@@ -38,11 +42,10 @@ export default function ComicViewer(props) {
|
|
|
38
42
|
debounceMillis = 100,
|
|
39
43
|
autoHandleErrorCount = 3,
|
|
40
44
|
fastScrollOptions,
|
|
41
|
-
getUrlByIndex,
|
|
42
45
|
initialNumToRender = 1,
|
|
43
46
|
initialScrollPercentage = 0,
|
|
44
47
|
itemVisiblePercentThreshold = 0,
|
|
45
|
-
|
|
48
|
+
intrinsicImages,
|
|
46
49
|
maxContentWidth = MAXIMUM_WIDTH,
|
|
47
50
|
onItemPress,
|
|
48
51
|
onScroll,
|
|
@@ -57,7 +60,7 @@ export default function ComicViewer(props) {
|
|
|
57
60
|
const flatListRef = useRef(null);
|
|
58
61
|
const maybeLoadableItemsIndexRange = useRef([-1, 0]);
|
|
59
62
|
const actualImageWidth = Math.min(viewportWidth, maxContentWidth);
|
|
60
|
-
const initialImageStates = useMemo(() => R.map(createInitialImageState,
|
|
63
|
+
const initialImageStates = useMemo(() => R.map(createInitialImageState, intrinsicImages), []);
|
|
61
64
|
const imageStatesRef = useRef(initialImageStates);
|
|
62
65
|
|
|
63
66
|
const mapImageStatesToItemStates = imageStates => {
|
|
@@ -68,13 +71,13 @@ export default function ComicViewer(props) {
|
|
|
68
71
|
return mapImageStatesToItemStates(imageStatesRef.current);
|
|
69
72
|
});
|
|
70
73
|
const renderedDimensions = useMemo(() => {
|
|
71
|
-
return mapIndexed((
|
|
72
|
-
const height =
|
|
74
|
+
return mapIndexed((intrinsicImage, index) => {
|
|
75
|
+
const height = intrinsicImage.dimension.height * actualImageWidth / intrinsicImage.dimension.width + (index === 0 ? invisiblePaddingTop : 0);
|
|
73
76
|
return {
|
|
74
77
|
width: actualImageWidth,
|
|
75
78
|
height: isNaN(height) ? 0 : height
|
|
76
79
|
};
|
|
77
|
-
},
|
|
80
|
+
}, intrinsicImages);
|
|
78
81
|
}, [actualImageWidth]);
|
|
79
82
|
const layoutFromDimensions = useCallback(() => {
|
|
80
83
|
const itemHeights = R.map(dimension => dimension.height, renderedDimensions);
|
|
@@ -110,54 +113,28 @@ export default function ComicViewer(props) {
|
|
|
110
113
|
});
|
|
111
114
|
};
|
|
112
115
|
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
var _state$urlState;
|
|
116
|
-
|
|
117
|
-
const state = imageStatesRef.current[index];
|
|
118
|
-
return !state.isNewUrlIncoming && (R.isNil(state.urlState) || ((_state$urlState = state.urlState) === null || _state$urlState === void 0 ? void 0 : _state$urlState.validity) === 'invalid');
|
|
119
|
-
}, indexes);
|
|
116
|
+
const updateItems = indexes => {
|
|
117
|
+
const tryRenderingMillis = new Date().getTime();
|
|
120
118
|
updateImageState((imageState, i) => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
} : imageState;
|
|
124
|
-
});
|
|
119
|
+
const urlState = imageState.urlState;
|
|
120
|
+
const shouldRerender = R.includes(i, R.defaultTo([], indexes));
|
|
125
121
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (newUrl !== undefined && (urlState === null || urlState === void 0 ? void 0 : urlState.validity) !== 'valid') {
|
|
133
|
-
return { ...imageState,
|
|
134
|
-
urlState: {
|
|
135
|
-
url: newUrl,
|
|
136
|
-
validity: 'unknown'
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
}
|
|
122
|
+
if (shouldRerender && (urlState === null || urlState === void 0 ? void 0 : urlState.validity) !== 'valid') {
|
|
123
|
+
return { ...imageState,
|
|
124
|
+
tryRenderingMillis
|
|
125
|
+
};
|
|
126
|
+
}
|
|
140
127
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
} catch (e) {// ignore
|
|
144
|
-
} finally {
|
|
145
|
-
updateImageState((imageState, i) => {
|
|
146
|
-
return R.includes(i, filteredIndexes) ? { ...imageState,
|
|
147
|
-
isNewUrlIncoming: false
|
|
148
|
-
} : imageState;
|
|
149
|
-
});
|
|
150
|
-
}
|
|
128
|
+
return imageState;
|
|
129
|
+
});
|
|
151
130
|
};
|
|
152
131
|
|
|
153
|
-
const
|
|
132
|
+
const renderMaybeLoadableItems = () => {
|
|
154
133
|
const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;
|
|
155
134
|
const affectedIndexes = R.range(startIndex, endIndex);
|
|
156
|
-
|
|
135
|
+
updateItems(affectedIndexes);
|
|
157
136
|
};
|
|
158
137
|
|
|
159
|
-
const ignoreDebounce = useRef(true);
|
|
160
|
-
const loadItemsDebounce = useDebounce(loadMaybeLoadableItems, debounceMillis);
|
|
161
138
|
const onViewableItemsChanged = useRef(_ref => {
|
|
162
139
|
var _R$head, _R$last;
|
|
163
140
|
|
|
@@ -175,14 +152,7 @@ export default function ComicViewer(props) {
|
|
|
175
152
|
const startIndex = R.max(firstViewableIndex - NUMBER_OF_ADJACENT_ITEM, 0);
|
|
176
153
|
const endIndex = R.min(lastViewableItemIndex + NUMBER_OF_ADJACENT_ITEM, itemStates.length - 1);
|
|
177
154
|
maybeLoadableItemsIndexRange.current = [startIndex, endIndex + 1];
|
|
178
|
-
|
|
179
|
-
if (ignoreDebounce.current) {
|
|
180
|
-
loadMaybeLoadableItems();
|
|
181
|
-
ignoreDebounce.current = false;
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
loadItemsDebounce();
|
|
155
|
+
renderMaybeLoadableItems();
|
|
186
156
|
});
|
|
187
157
|
const handleScroll = useCallback(event => {
|
|
188
158
|
var _fastScrollRef$curren;
|
|
@@ -213,7 +183,7 @@ export default function ComicViewer(props) {
|
|
|
213
183
|
updateImageState((imageState, i) => {
|
|
214
184
|
const urlState = imageState.urlState;
|
|
215
185
|
|
|
216
|
-
if (i === index
|
|
186
|
+
if (i === index) {
|
|
217
187
|
return { ...imageState,
|
|
218
188
|
totalErrorCount: imageState.totalErrorCount + 1,
|
|
219
189
|
urlState: { ...urlState,
|
|
@@ -232,17 +202,13 @@ export default function ComicViewer(props) {
|
|
|
232
202
|
const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;
|
|
233
203
|
|
|
234
204
|
if (index >= startIndex || index < endIndex) {
|
|
235
|
-
|
|
205
|
+
renderMaybeLoadableItems();
|
|
236
206
|
}
|
|
237
207
|
};
|
|
238
208
|
|
|
239
209
|
const handleReloadPress = () => {
|
|
240
210
|
onReloadPress && onReloadPress();
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (index >= startIndex || index < endIndex) {
|
|
244
|
-
loadUrlByIndex([index]);
|
|
245
|
-
}
|
|
211
|
+
updateItems([index]);
|
|
246
212
|
};
|
|
247
213
|
|
|
248
214
|
const onLoad = () => {
|
|
@@ -267,6 +233,7 @@ export default function ComicViewer(props) {
|
|
|
267
233
|
onPress: onItemPress,
|
|
268
234
|
onReloadPress: handleReloadPress,
|
|
269
235
|
url: item.url,
|
|
236
|
+
imageKey: item.imageKey,
|
|
270
237
|
invisiblePaddingTop: index === 0 ? invisiblePaddingTop : 0,
|
|
271
238
|
width: ((_renderedDimensions$i = renderedDimensions[index]) === null || _renderedDimensions$i === void 0 ? void 0 : _renderedDimensions$i.width) ?? 0,
|
|
272
239
|
height: ((_renderedDimensions$i2 = renderedDimensions[index]) === null || _renderedDimensions$i2 === void 0 ? void 0 : _renderedDimensions$i2.height) ?? 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","useCallback","useEffect","useMemo","useRef","useState","FlatList","R","useDebounce","ViewerItem","FastScroll","appender","left","right","getHeightAccum","heights","mapAccum","keyExtractor","item","String","index","createInitialImageState","dimension","isNewUrlIncoming","totalErrorCount","mapImageStateToItemState","imageState","autoHandleErrorCount","url","urlState","reloadButtonVisible","validity","mapIndexed","addIndex","map","MAXIMUM_WIDTH","NUMBER_OF_ADJACENT_ITEM","ComicViewer","props","debounceMillis","fastScrollOptions","getUrlByIndex","initialNumToRender","initialScrollPercentage","itemVisiblePercentThreshold","intrinsicDimensions","maxContentWidth","onItemPress","onScroll","onError","onReloadPress","viewportWidth","invisiblePaddingTop","windowSize","otherProps","fastScrollRef","ref","flatListRef","maybeLoadableItemsIndexRange","actualImageWidth","Math","min","initialImageStates","imageStatesRef","mapImageStatesToItemStates","imageStates","image","itemStates","setItemStates","current","renderedDimensions","intrinsicDimension","height","width","isNaN","layoutFromDimensions","itemHeights","totalHeight","heightAccum","itemOffsets","prepend","getItemLayout","data","length","offset","viewabilityConfig","updateImageState","updateFunction","prevImageStates","newImageStates","prevItemStates","newItemStates","equals","loadUrlByIndex","indexes","filteredIndexes","filter","state","isNil","i","includes","urls","newUrl","get","undefined","e","loadMaybeLoadableItems","startIndex","endIndex","affectedIndexes","range","ignoreDebounce","loadItemsDebounce","onViewableItemsChanged","viewableItems","orderedViewableItems","sort","a","b","firstViewableIndex","head","lastViewableItemIndex","last","max","handleScroll","event","onContentScroll","scrollContentToOffset","scrollToOffset","animated","renderItem","handleError","handleReloadPress","onLoad","floor"],"sources":["ComicViewer.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { FlatList, ListRenderItem, NativeScrollEvent, NativeSyntheticEvent, ViewToken } from 'react-native';\nimport * as R from 'ramda';\nimport { useDebounce } from '@fountain-ui/core';\nimport { default as ComicViewerProps, Dimension } from './ComicViewerProps';\nimport ViewerItem from './ViewerItem';\nimport FastScroll from './FastScroll';\n\nconst appender = (left: number, right: number): [number, number] => [left + right, left + right];\nconst getHeightAccum = (heights: number[]): [number, number[]] => R.mapAccum(appender, 0, heights);\n\nconst keyExtractor = <T, >(item: ItemState) => String(item.index);\n\ninterface UrlState {\n url: string;\n validity: 'valid' | 'invalid' | 'unknown';\n}\n\ninterface ImageState {\n urlState?: UrlState;\n isNewUrlIncoming: boolean;\n totalErrorCount: number;\n dimension: Dimension;\n}\n\ninterface ItemState {\n index: number;\n url?: string;\n reloadButtonVisible: boolean;\n dimension: Dimension;\n}\n\nconst createInitialImageState = (dimension: Dimension): ImageState => ({\n isNewUrlIncoming: false,\n totalErrorCount: 0,\n dimension,\n});\n\nconst mapImageStateToItemState = (\n index: number,\n imageState: ImageState,\n autoHandleErrorCount: number,\n): ItemState => ({\n index,\n url: imageState.urlState?.url,\n reloadButtonVisible: (imageState.urlState?.validity !== 'valid') && imageState.totalErrorCount >= autoHandleErrorCount,\n dimension: imageState.dimension,\n});\n\nconst mapIndexed = R.addIndex<Dimension>(R.map);\n\nconst MAXIMUM_WIDTH = 720;\n\nconst NUMBER_OF_ADJACENT_ITEM = 5;\n\nexport default function ComicViewer(props: ComicViewerProps) {\n const {\n debounceMillis = 100,\n autoHandleErrorCount = 3,\n fastScrollOptions,\n getUrlByIndex,\n initialNumToRender = 1,\n initialScrollPercentage = 0,\n itemVisiblePercentThreshold = 0,\n intrinsicDimensions,\n maxContentWidth = MAXIMUM_WIDTH,\n onItemPress,\n onScroll,\n onError,\n onReloadPress,\n viewportWidth,\n invisiblePaddingTop = 0,\n windowSize = 3,\n ...otherProps\n } = props;\n\n const fastScrollRef = fastScrollOptions?.ref;\n\n const flatListRef = useRef<FlatList>(null);\n\n const maybeLoadableItemsIndexRange = useRef<[number, number]>([-1, 0]);\n\n const actualImageWidth = Math.min(viewportWidth, maxContentWidth);\n\n const initialImageStates = useMemo<Array<ImageState>>(() => R.map(createInitialImageState, intrinsicDimensions), []);\n const imageStatesRef = useRef<Array<ImageState>>(initialImageStates);\n\n const mapImageStatesToItemStates = (imageStates: Array<ImageState>): Array<ItemState> => {\n return imageStates.map((image, index) => mapImageStateToItemState(\n index, image, autoHandleErrorCount,\n ));\n };\n\n const [itemStates, setItemStates] = useState<Array<ItemState>>(() => {\n return mapImageStatesToItemStates(imageStatesRef.current);\n });\n\n const renderedDimensions = useMemo<Array<Dimension>>(() => {\n return mapIndexed((intrinsicDimension, index) => {\n const height = (intrinsicDimension.height * actualImageWidth) / intrinsicDimension.width + (index === 0 ? invisiblePaddingTop : 0);\n\n return {\n width: actualImageWidth,\n height: isNaN(height) ? 0 : height,\n };\n }, intrinsicDimensions);\n }, [actualImageWidth]);\n\n const layoutFromDimensions = useCallback(() => {\n const itemHeights = R.map(dimension => dimension.height, renderedDimensions);\n const [totalHeight, heightAccum] = getHeightAccum(itemHeights);\n const itemOffsets = R.prepend(0, heightAccum);\n\n const getItemLayout = (data: any, index: number) => ({\n index,\n length: itemHeights[index],\n offset: itemOffsets[index],\n });\n\n return {\n totalHeight,\n getItemLayout,\n };\n }, [renderedDimensions]);\n\n const { totalHeight, getItemLayout } = layoutFromDimensions();\n\n const viewabilityConfig = useMemo(() => ({\n itemVisiblePercentThreshold,\n }), [itemVisiblePercentThreshold]);\n\n const updateImageState = (updateFunction: (prev: ImageState, index: number) => ImageState) => {\n const prevImageStates = imageStatesRef.current;\n const newImageStates = prevImageStates.map(updateFunction);\n\n imageStatesRef.current = newImageStates;\n\n setItemStates(prevItemStates => {\n const newItemStates = mapImageStatesToItemStates(newImageStates);\n\n return R.equals(prevItemStates, newItemStates) ? prevItemStates : newItemStates;\n });\n };\n\n const loadUrlByIndex = async (indexes: number[]) => {\n const filteredIndexes = R.filter(index => {\n const state = imageStatesRef.current[index];\n\n return !state.isNewUrlIncoming\n && (R.isNil(state.urlState) || state.urlState?.validity === 'invalid');\n }, indexes);\n\n updateImageState((imageState, i) => {\n return R.includes(i, filteredIndexes)\n ? { ...imageState, isNewUrlIncoming: true }\n : imageState;\n });\n\n try {\n const urls = await getUrlByIndex(filteredIndexes);\n\n updateImageState((imageState, i) => {\n const newUrl = urls?.get(i);\n const urlState = imageState.urlState;\n\n if (newUrl !== undefined && urlState?.validity !== 'valid') {\n return {\n ...imageState,\n urlState: {\n url: newUrl,\n validity: 'unknown',\n },\n };\n }\n\n return imageState;\n });\n } catch (e) {\n // ignore\n } finally {\n updateImageState((imageState, i) => {\n return R.includes(i, filteredIndexes)\n ? { ...imageState, isNewUrlIncoming: false }\n : imageState;\n });\n }\n };\n\n const loadMaybeLoadableItems = () => {\n const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;\n const affectedIndexes = R.range(startIndex, endIndex);\n\n loadUrlByIndex(affectedIndexes);\n };\n\n const ignoreDebounce = useRef(true);\n const loadItemsDebounce = useDebounce(loadMaybeLoadableItems, debounceMillis);\n\n const onViewableItemsChanged = useRef(({ viewableItems }: { viewableItems: Array<ViewToken> }) => {\n const orderedViewableItems = R.sort((a, b) => (a.index || 0) - (b.index || 0), viewableItems);\n\n const firstViewableIndex = R.head(orderedViewableItems)?.index;\n const lastViewableItemIndex = R.last(orderedViewableItems)?.index;\n\n if (R.isNil(firstViewableIndex) || R.isNil(lastViewableItemIndex)) {\n return;\n }\n\n const startIndex = R.max(firstViewableIndex - NUMBER_OF_ADJACENT_ITEM, 0);\n const endIndex = R.min(lastViewableItemIndex + NUMBER_OF_ADJACENT_ITEM, itemStates.length - 1);\n\n maybeLoadableItemsIndexRange.current = [startIndex, endIndex + 1];\n\n if (ignoreDebounce.current) {\n loadMaybeLoadableItems();\n\n ignoreDebounce.current = false;\n return;\n }\n\n loadItemsDebounce();\n });\n\n const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {\n fastScrollRef?.current?.onContentScroll(event);\n\n onScroll?.(event);\n }, [onScroll]);\n\n const scrollContentToOffset = (offset: number) => {\n flatListRef.current?.scrollToOffset({\n offset,\n animated: false,\n });\n };\n\n const renderItem: ListRenderItem<ItemState> = useCallback(({ item, index }) => {\n const handleError = () => {\n onError && onError();\n\n updateImageState((imageState, i) => {\n const urlState = imageState.urlState;\n\n if (i === index && urlState !== undefined) {\n return {\n ...imageState,\n totalErrorCount: imageState.totalErrorCount + 1,\n urlState: {\n ...urlState,\n validity: 'invalid',\n },\n };\n }\n\n return imageState;\n });\n\n if (item.reloadButtonVisible) {\n return;\n }\n\n const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;\n if (index >= startIndex || index < endIndex) {\n loadItemsDebounce();\n }\n };\n\n const handleReloadPress = () => {\n onReloadPress && onReloadPress();\n\n const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;\n if (index >= startIndex || index < endIndex) {\n loadUrlByIndex([index]);\n }\n };\n\n const onLoad = () => {\n updateImageState((imageState, i) => {\n const urlState = imageState.urlState;\n\n if (i === index && urlState !== undefined) {\n return {\n ...imageState,\n urlState: {\n ...urlState,\n validity: 'valid',\n },\n };\n }\n\n return imageState;\n });\n };\n\n return (\n <ViewerItem\n onError={handleError}\n onLoad={onLoad}\n onPress={onItemPress}\n onReloadPress={handleReloadPress}\n url={item.url}\n invisiblePaddingTop={index === 0 ? invisiblePaddingTop : 0}\n width={renderedDimensions[index]?.width ?? 0}\n height={renderedDimensions[index]?.height ?? 0}\n reloadButtonVisible={item.reloadButtonVisible}\n />\n );\n }, [onItemPress, renderedDimensions]);\n\n useEffect(() => {\n const offset = Math.floor((initialScrollPercentage / 100) * totalHeight);\n\n if (flatListRef.current) {\n flatListRef.current.scrollToOffset({ offset, animated: false });\n }\n }, []);\n\n return (\n <React.Fragment>\n <FlatList\n data={itemStates}\n getItemLayout={getItemLayout}\n initialNumToRender={initialNumToRender}\n keyExtractor={keyExtractor}\n onViewableItemsChanged={onViewableItemsChanged.current}\n ref={flatListRef}\n renderItem={renderItem}\n viewabilityConfig={viewabilityConfig}\n windowSize={windowSize}\n onScroll={handleScroll}\n {...otherProps}\n />\n\n <FastScroll\n {...fastScrollOptions}\n contentLength={totalHeight}\n scrollContentToOffset={scrollContentToOffset}\n />\n </React.Fragment>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["React","useCallback","useEffect","useMemo","useRef","useState","FlatList","R","ViewerItem","FastScroll","appender","left","right","getHeightAccum","heights","mapAccum","keyExtractor","item","String","index","createInitialImageState","image","totalErrorCount","dimension","tryRenderingMillis","urlState","url","validity","mapImageStateToItemState","imageState","autoHandleErrorCount","imageKey","reloadButtonVisible","mapIndexed","addIndex","map","MAXIMUM_WIDTH","NUMBER_OF_ADJACENT_ITEM","ComicViewer","props","debounceMillis","fastScrollOptions","initialNumToRender","initialScrollPercentage","itemVisiblePercentThreshold","intrinsicImages","maxContentWidth","onItemPress","onScroll","onError","onReloadPress","viewportWidth","invisiblePaddingTop","windowSize","otherProps","fastScrollRef","ref","flatListRef","maybeLoadableItemsIndexRange","actualImageWidth","Math","min","initialImageStates","imageStatesRef","mapImageStatesToItemStates","imageStates","itemStates","setItemStates","current","renderedDimensions","intrinsicImage","height","width","isNaN","layoutFromDimensions","itemHeights","totalHeight","heightAccum","itemOffsets","prepend","getItemLayout","data","length","offset","viewabilityConfig","updateImageState","updateFunction","prevImageStates","newImageStates","prevItemStates","newItemStates","equals","updateItems","indexes","Date","getTime","i","shouldRerender","includes","defaultTo","renderMaybeLoadableItems","startIndex","endIndex","affectedIndexes","range","onViewableItemsChanged","viewableItems","orderedViewableItems","sort","a","b","firstViewableIndex","head","lastViewableItemIndex","last","isNil","max","handleScroll","event","onContentScroll","scrollContentToOffset","scrollToOffset","animated","renderItem","handleError","handleReloadPress","onLoad","undefined","floor"],"sources":["ComicViewer.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { FlatList, ListRenderItem, NativeScrollEvent, NativeSyntheticEvent, ViewToken } from 'react-native';\nimport * as R from 'ramda';\nimport { default as ComicViewerProps, Dimension, IntrinsicImage } from './ComicViewerProps';\nimport ViewerItem from './ViewerItem';\nimport FastScroll from './FastScroll';\n\nconst appender = (left: number, right: number): [number, number] => [left + right, left + right];\nconst getHeightAccum = (heights: number[]): [number, number[]] => R.mapAccum(appender, 0, heights);\n\nconst keyExtractor = <T, >(item: ItemState) => String(item.index);\n\ninterface UrlState {\n url: string;\n validity: 'valid' | 'invalid' | 'unknown';\n}\n\ninterface ImageState {\n urlState: UrlState;\n totalErrorCount: number;\n dimension: Dimension;\n tryRenderingMillis: number;\n}\n\ninterface ItemState {\n index: number;\n url?: string;\n imageKey: string;\n reloadButtonVisible: boolean;\n dimension: Dimension;\n}\n\nconst createInitialImageState = (image: IntrinsicImage): ImageState => ({\n totalErrorCount: 0,\n dimension: image.dimension,\n tryRenderingMillis: 0,\n urlState: {\n url: image.url,\n validity: 'unknown',\n },\n});\n\nconst mapImageStateToItemState = (\n index: number,\n imageState: ImageState,\n autoHandleErrorCount: number,\n): ItemState => ({\n index,\n url: imageState.urlState?.url,\n imageKey: `${imageState.tryRenderingMillis}-${index}`,\n reloadButtonVisible: (imageState.urlState?.validity !== 'valid') && imageState.totalErrorCount >= autoHandleErrorCount,\n dimension: imageState.dimension,\n});\n\nconst mapIndexed = R.addIndex<IntrinsicImage>(R.map);\n\nconst MAXIMUM_WIDTH = 720;\n\nconst NUMBER_OF_ADJACENT_ITEM = 5;\n\nexport default function ComicViewer(props: ComicViewerProps) {\n const {\n debounceMillis = 100,\n autoHandleErrorCount = 3,\n fastScrollOptions,\n initialNumToRender = 1,\n initialScrollPercentage = 0,\n itemVisiblePercentThreshold = 0,\n intrinsicImages,\n maxContentWidth = MAXIMUM_WIDTH,\n onItemPress,\n onScroll,\n onError,\n onReloadPress,\n viewportWidth,\n invisiblePaddingTop = 0,\n windowSize = 3,\n ...otherProps\n } = props;\n\n const fastScrollRef = fastScrollOptions?.ref;\n\n const flatListRef = useRef<FlatList>(null);\n\n const maybeLoadableItemsIndexRange = useRef<[number, number]>([-1, 0]);\n\n const actualImageWidth = Math.min(viewportWidth, maxContentWidth);\n\n const initialImageStates = useMemo<Array<ImageState>>(() => R.map(createInitialImageState, intrinsicImages), []);\n\n const imageStatesRef = useRef<Array<ImageState>>(initialImageStates);\n\n const mapImageStatesToItemStates = (imageStates: Array<ImageState>): Array<ItemState> => {\n return imageStates.map((image, index) => mapImageStateToItemState(\n index, image, autoHandleErrorCount,\n ));\n };\n\n const [itemStates, setItemStates] = useState<Array<ItemState>>(() => {\n return mapImageStatesToItemStates(imageStatesRef.current);\n });\n\n const renderedDimensions = useMemo<Array<Dimension>>(() => {\n return mapIndexed((intrinsicImage, index) => {\n const height = (intrinsicImage.dimension.height * actualImageWidth) / intrinsicImage.dimension.width + (index === 0 ? invisiblePaddingTop : 0);\n\n return {\n width: actualImageWidth,\n height: isNaN(height) ? 0 : height,\n };\n }, intrinsicImages);\n }, [actualImageWidth]);\n\n const layoutFromDimensions = useCallback(() => {\n const itemHeights = R.map(dimension => dimension.height, renderedDimensions);\n const [totalHeight, heightAccum] = getHeightAccum(itemHeights);\n const itemOffsets = R.prepend(0, heightAccum);\n\n const getItemLayout = (data: any, index: number) => ({\n index,\n length: itemHeights[index],\n offset: itemOffsets[index],\n });\n\n return {\n totalHeight,\n getItemLayout,\n };\n }, [renderedDimensions]);\n\n const { totalHeight, getItemLayout } = layoutFromDimensions();\n\n const viewabilityConfig = useMemo(() => ({\n itemVisiblePercentThreshold,\n }), [itemVisiblePercentThreshold]);\n\n const updateImageState = (updateFunction: (prev: ImageState, index: number) => ImageState) => {\n const prevImageStates = imageStatesRef.current;\n const newImageStates = prevImageStates.map(updateFunction);\n\n imageStatesRef.current = newImageStates;\n\n setItemStates(prevItemStates => {\n const newItemStates = mapImageStatesToItemStates(newImageStates);\n\n return R.equals(prevItemStates, newItemStates) ? prevItemStates : newItemStates;\n });\n };\n\n const updateItems = (indexes: number[]) => {\n const tryRenderingMillis = new Date().getTime();\n\n updateImageState((imageState, i) => {\n const urlState = imageState.urlState;\n const shouldRerender = R.includes(i, R.defaultTo([], indexes));\n\n if (shouldRerender && urlState?.validity !== 'valid') {\n return {\n ...imageState,\n tryRenderingMillis,\n };\n }\n\n return imageState;\n });\n };\n\n const renderMaybeLoadableItems = () => {\n const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;\n const affectedIndexes = R.range(startIndex, endIndex);\n\n updateItems(affectedIndexes);\n };\n\n const onViewableItemsChanged = useRef(({ viewableItems }: { viewableItems: Array<ViewToken> }) => {\n const orderedViewableItems = R.sort((a, b) => (a.index || 0) - (b.index || 0), viewableItems);\n\n const firstViewableIndex = R.head(orderedViewableItems)?.index;\n const lastViewableItemIndex = R.last(orderedViewableItems)?.index;\n\n if (R.isNil(firstViewableIndex) || R.isNil(lastViewableItemIndex)) {\n return;\n }\n\n const startIndex = R.max(firstViewableIndex - NUMBER_OF_ADJACENT_ITEM, 0);\n const endIndex = R.min(lastViewableItemIndex + NUMBER_OF_ADJACENT_ITEM, itemStates.length - 1);\n\n maybeLoadableItemsIndexRange.current = [startIndex, endIndex + 1];\n\n renderMaybeLoadableItems();\n });\n\n const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {\n fastScrollRef?.current?.onContentScroll(event);\n\n onScroll?.(event);\n }, [onScroll]);\n\n const scrollContentToOffset = (offset: number) => {\n flatListRef.current?.scrollToOffset({\n offset,\n animated: false,\n });\n };\n\n const renderItem: ListRenderItem<ItemState> = useCallback(({ item, index }) => {\n const handleError = () => {\n onError && onError();\n\n updateImageState((imageState, i) => {\n const urlState = imageState.urlState;\n\n if (i === index) {\n return {\n ...imageState,\n totalErrorCount: imageState.totalErrorCount + 1,\n urlState: {\n ...urlState,\n validity: 'invalid',\n },\n };\n }\n\n return imageState;\n });\n\n if (item.reloadButtonVisible) {\n return;\n }\n\n const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;\n if (index >= startIndex || index < endIndex) {\n renderMaybeLoadableItems();\n }\n };\n\n const handleReloadPress = () => {\n onReloadPress && onReloadPress();\n\n updateItems([index]);\n };\n\n const onLoad = () => {\n updateImageState((imageState, i) => {\n const urlState = imageState.urlState;\n\n if (i === index && urlState !== undefined) {\n return {\n ...imageState,\n urlState: {\n ...urlState,\n validity: 'valid',\n },\n };\n }\n\n return imageState;\n });\n };\n\n return (\n <ViewerItem\n onError={handleError}\n onLoad={onLoad}\n onPress={onItemPress}\n onReloadPress={handleReloadPress}\n url={item.url}\n imageKey={item.imageKey}\n invisiblePaddingTop={index === 0 ? invisiblePaddingTop : 0}\n width={renderedDimensions[index]?.width ?? 0}\n height={renderedDimensions[index]?.height ?? 0}\n reloadButtonVisible={item.reloadButtonVisible}\n />\n );\n }, [onItemPress, renderedDimensions]);\n\n useEffect(() => {\n const offset = Math.floor((initialScrollPercentage / 100) * totalHeight);\n\n if (flatListRef.current) {\n flatListRef.current.scrollToOffset({ offset, animated: false });\n }\n }, []);\n\n return (\n <React.Fragment>\n <FlatList\n data={itemStates}\n getItemLayout={getItemLayout}\n initialNumToRender={initialNumToRender}\n keyExtractor={keyExtractor}\n onViewableItemsChanged={onViewableItemsChanged.current}\n ref={flatListRef}\n renderItem={renderItem}\n viewabilityConfig={viewabilityConfig}\n windowSize={windowSize}\n onScroll={handleScroll}\n {...otherProps}\n />\n\n <FastScroll\n {...fastScrollOptions}\n contentLength={totalHeight}\n scrollContentToOffset={scrollContentToOffset}\n />\n </React.Fragment>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["ComicViewerProps.ts"],"sourcesContent":["import React from 'react';\nimport { ComponentProps } from '@fountain-ui/core';\nimport { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';\nimport { FastScrollOptions } from './FastScrollProps';\n\nexport interface Dimension {\n width: number;\n height: number;\n}\n\nexport default interface ComicViewerProps extends ComponentProps <{\n /**\n * Delay Time to call the error handler.\n * @default 100\n */\n debounceMillis?: number;\n\n /**\n * How many times handle onError directly when item error occur\n * @default 3\n */\n autoHandleErrorCount?: number;\n\n /**\n * How many items to render in the initial batch.\n * @default 1\n */\n initialNumToRender?: number;\n\n /**\n * Start at initialScrollPercentage.\n * If over 100, scroll to end.\n * @default 0\n */\n initialScrollPercentage?: number;\n\n /**\n * The value for FlatList viewabilityConfig.itemVisiblePercentThreshold.\n * @default 0\n */\n itemVisiblePercentThreshold?: number;\n\n /**\n * Dimensions of each Image considering viewport.\n */\n
|
|
1
|
+
{"version":3,"names":[],"sources":["ComicViewerProps.ts"],"sourcesContent":["import React from 'react';\nimport { ComponentProps } from '@fountain-ui/core';\nimport { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';\nimport { FastScrollOptions } from './FastScrollProps';\n\nexport interface Dimension {\n width: number;\n height: number;\n}\n\nexport interface IntrinsicImage {\n dimension: Dimension;\n url: string;\n}\n\nexport default interface ComicViewerProps extends ComponentProps <{\n /**\n * Delay Time to call the error handler.\n * @default 100\n */\n debounceMillis?: number;\n\n /**\n * How many times handle onError directly when item error occur\n * @default 3\n */\n autoHandleErrorCount?: number;\n\n /**\n * How many items to render in the initial batch.\n * @default 1\n */\n initialNumToRender?: number;\n\n /**\n * Start at initialScrollPercentage.\n * If over 100, scroll to end.\n * @default 0\n */\n initialScrollPercentage?: number;\n\n /**\n * The value for FlatList viewabilityConfig.itemVisiblePercentThreshold.\n * @default 0\n */\n itemVisiblePercentThreshold?: number;\n\n /**\n * Dimensions and url info of each Image considering viewport.\n */\n intrinsicImages: Array<IntrinsicImage>;\n\n /**\n * Need invisible paddingTop viewer vertically expanded.\n * @default 0\n */\n invisiblePaddingTop?: number;\n\n /**\n * Max value of contents image width size.\n * @default 720\n */\n maxContentWidth?: number;\n\n /**\n * Width of viewport.\n */\n viewportWidth: number;\n\n /**\n * The value for FlatList windowSize.\n * @default 3\n */\n windowSize?: number;\n\n /**\n * Options for fastscroll component.\n */\n fastScrollOptions: FastScrollOptions;\n\n /**\n * Handle scroll event.\n * @param event Scroll event.\n */\n onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;\n\n /**\n * Handle item press event.\n */\n onItemPress?: () => void;\n\n /**\n * Handle image loading fail event.\n */\n onError?: () => void;\n\n /**\n * Handle reload button press event.\n */\n onReloadPress?: () => void;\n\n /**\n * Component for comic viewer footer.\n */\n ListFooterComponent?: React.ReactElement;\n}> {}\n"],"mappings":""}
|
|
@@ -8,6 +8,7 @@ export default function ViewerItem(props) {
|
|
|
8
8
|
height,
|
|
9
9
|
url,
|
|
10
10
|
width,
|
|
11
|
+
imageKey,
|
|
11
12
|
invisiblePaddingTop,
|
|
12
13
|
onError,
|
|
13
14
|
onLoad,
|
|
@@ -41,6 +42,7 @@ export default function ViewerItem(props) {
|
|
|
41
42
|
}, /*#__PURE__*/React.createElement(View, {
|
|
42
43
|
style: styles.view
|
|
43
44
|
}, /*#__PURE__*/React.createElement(FuiImage, {
|
|
45
|
+
key: imageKey,
|
|
44
46
|
cache: 'web',
|
|
45
47
|
disableDrag: true,
|
|
46
48
|
disableLongClick: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","Image","TouchableWithoutFeedback","View","css","FuiImage","ReloadButton","EncodedTile","ViewerItem","props","height","url","width","invisiblePaddingTop","onError","onLoad","onPress","onReloadPress","reloadButtonVisible","styles","view","paddingTop","image","error","placeholder","uri","alignSelf"],"sources":["ViewerItem.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, TouchableWithoutFeedback, View } from 'react-native';\nimport { css, Image as FuiImage, ImageProps } from '@fountain-ui/core';\nimport ReloadButton from './ReloadButton';\nimport EncodedTile from './EncodedTile';\n\nexport interface ViewerItemProps {\n /**\n * Image width.\n */\n width: number;\n\n /**\n * Image height.\n */\n height: number;\n\n /**\n * Need invisible paddingTop viewer vertically expanded.\n */\n invisiblePaddingTop: number;\n\n /**\n * Image sourceUrl for displaying.\n */\n url?: string;\n\n /**\n * Error handler.\n */\n onError?: ImageProps['onError'];\n\n /**\n * Load handler.\n */\n onLoad?: ImageProps['onLoad'];\n\n /**\n * Handle Reload button press event.\n */\n onReloadPress?: ImageProps['onError'];\n\n /**\n * Handle item press event.\n */\n onPress?: () => void;\n\n /**\n * If true, reload button visible.\n * @default false\n */\n reloadButtonVisible?: boolean;\n}\n\nexport default function ViewerItem(props: ViewerItemProps) {\n const {\n height,\n url,\n width,\n invisiblePaddingTop,\n onError,\n onLoad,\n onPress,\n onReloadPress,\n reloadButtonVisible = false,\n } = props;\n\n const styles = {\n view: {\n height,\n width: '100%',\n paddingTop: invisiblePaddingTop,\n },\n image: {\n height: height - invisiblePaddingTop,\n width,\n },\n };\n\n const error = reloadButtonVisible ? <ReloadButton onPress={onReloadPress}/> : null;\n\n const placeholder = <Image\n source={{ uri: EncodedTile }}\n resizeMode={'cover'}\n style={styles.image}\n />;\n\n return (\n <TouchableWithoutFeedback onPress={onPress}>\n <View style={styles.view}>\n <FuiImage\n cache={'web'}\n disableDrag={true}\n disableLongClick={true}\n disableOutline={true}\n error={error}\n onError={onError}\n onLoad={onLoad}\n loading={'eager'}\n placeholder={placeholder}\n source={{ uri: url }}\n square={true}\n style={css([\n { alignSelf: 'center' },\n styles.image,\n ])}\n />\n </View>\n </TouchableWithoutFeedback>\n );\n};\n"],"mappings":"AAAA,OAAOA,KAAP,MAAkB,OAAlB;AACA,SAASC,KAAT,EAAgBC,wBAAhB,EAA0CC,IAA1C,QAAsD,cAAtD;AACA,SAASC,GAAT,EAAcH,KAAK,IAAII,QAAvB,QAAmD,mBAAnD;AACA,OAAOC,YAAP,MAAyB,gBAAzB;AACA,OAAOC,WAAP,MAAwB,eAAxB;
|
|
1
|
+
{"version":3,"names":["React","Image","TouchableWithoutFeedback","View","css","FuiImage","ReloadButton","EncodedTile","ViewerItem","props","height","url","width","imageKey","invisiblePaddingTop","onError","onLoad","onPress","onReloadPress","reloadButtonVisible","styles","view","paddingTop","image","error","placeholder","uri","alignSelf"],"sources":["ViewerItem.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, TouchableWithoutFeedback, View } from 'react-native';\nimport { css, Image as FuiImage, ImageProps } from '@fountain-ui/core';\nimport ReloadButton from './ReloadButton';\nimport EncodedTile from './EncodedTile';\n\nexport interface ViewerItemProps {\n /**\n * Image width.\n */\n width: number;\n\n /**\n * Image height.\n */\n height: number;\n\n /**\n * Need invisible paddingTop viewer vertically expanded.\n */\n invisiblePaddingTop: number;\n\n /**\n * Image sourceUrl for displaying.\n */\n url?: string;\n\n /**\n * Error handler.\n */\n onError?: ImageProps['onError'];\n\n /**\n * Load handler.\n */\n onLoad?: ImageProps['onLoad'];\n\n /**\n * Handle Reload button press event.\n */\n onReloadPress?: ImageProps['onError'];\n\n /**\n * Handle item press event.\n */\n onPress?: () => void;\n\n /**\n * If true, reload button visible.\n * @default false\n */\n reloadButtonVisible?: boolean;\n\n /**\n * FuiImage key for trigger image rerender.\n */\n imageKey: string;\n}\n\nexport default function ViewerItem(props: ViewerItemProps) {\n const {\n height,\n url,\n width,\n imageKey,\n invisiblePaddingTop,\n onError,\n onLoad,\n onPress,\n onReloadPress,\n reloadButtonVisible = false,\n } = props;\n\n const styles = {\n view: {\n height,\n width: '100%',\n paddingTop: invisiblePaddingTop,\n },\n image: {\n height: height - invisiblePaddingTop,\n width,\n },\n };\n\n const error = reloadButtonVisible ? <ReloadButton onPress={onReloadPress}/> : null;\n\n const placeholder = <Image\n source={{ uri: EncodedTile }}\n resizeMode={'cover'}\n style={styles.image}\n />;\n\n return (\n <TouchableWithoutFeedback onPress={onPress}>\n <View style={styles.view}>\n <FuiImage\n key={imageKey}\n cache={'web'}\n disableDrag={true}\n disableLongClick={true}\n disableOutline={true}\n error={error}\n onError={onError}\n onLoad={onLoad}\n loading={'eager'}\n placeholder={placeholder}\n source={{ uri: url }}\n square={true}\n style={css([\n { alignSelf: 'center' },\n styles.image,\n ])}\n />\n </View>\n </TouchableWithoutFeedback>\n );\n};\n"],"mappings":"AAAA,OAAOA,KAAP,MAAkB,OAAlB;AACA,SAASC,KAAT,EAAgBC,wBAAhB,EAA0CC,IAA1C,QAAsD,cAAtD;AACA,SAASC,GAAT,EAAcH,KAAK,IAAII,QAAvB,QAAmD,mBAAnD;AACA,OAAOC,YAAP,MAAyB,gBAAzB;AACA,OAAOC,WAAP,MAAwB,eAAxB;AAuDA,eAAe,SAASC,UAAT,CAAoBC,KAApB,EAA4C;EACvD,MAAM;IACFC,MADE;IAEFC,GAFE;IAGFC,KAHE;IAIFC,QAJE;IAKFC,mBALE;IAMFC,OANE;IAOFC,MAPE;IAQFC,OARE;IASFC,aATE;IAUFC,mBAAmB,GAAG;EAVpB,IAWFV,KAXJ;EAaA,MAAMW,MAAM,GAAG;IACXC,IAAI,EAAE;MACFX,MADE;MAEFE,KAAK,EAAE,MAFL;MAGFU,UAAU,EAAER;IAHV,CADK;IAMXS,KAAK,EAAE;MACHb,MAAM,EAAEA,MAAM,GAAGI,mBADd;MAEHF;IAFG;EANI,CAAf;EAYA,MAAMY,KAAK,GAAGL,mBAAmB,gBAAG,oBAAC,YAAD;IAAc,OAAO,EAAED;EAAvB,EAAH,GAA6C,IAA9E;EAEA,MAAMO,WAAW,gBAAG,oBAAC,KAAD;IAChB,MAAM,EAAE;MAAEC,GAAG,EAAEnB;IAAP,CADQ;IAEhB,UAAU,EAAE,OAFI;IAGhB,KAAK,EAAEa,MAAM,CAACG;EAHE,EAApB;EAMA,oBACI,oBAAC,wBAAD;IAA0B,OAAO,EAAEN;EAAnC,gBACI,oBAAC,IAAD;IAAM,KAAK,EAAEG,MAAM,CAACC;EAApB,gBACI,oBAAC,QAAD;IACI,GAAG,EAAER,QADT;IAEI,KAAK,EAAE,KAFX;IAGI,WAAW,EAAE,IAHjB;IAII,gBAAgB,EAAE,IAJtB;IAKI,cAAc,EAAE,IALpB;IAMI,KAAK,EAAEW,KANX;IAOI,OAAO,EAAET,OAPb;IAQI,MAAM,EAAEC,MARZ;IASI,OAAO,EAAE,OATb;IAUI,WAAW,EAAES,WAVjB;IAWI,MAAM,EAAE;MAAEC,GAAG,EAAEf;IAAP,CAXZ;IAYI,MAAM,EAAE,IAZZ;IAaI,KAAK,EAAEP,GAAG,CAAC,CACP;MAAEuB,SAAS,EAAE;IAAb,CADO,EAEPP,MAAM,CAACG,KAFA,CAAD;EAbd,EADJ,CADJ,CADJ;AAwBH;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["default"],"sources":["index.ts"],"sourcesContent":["export { default } from './ComicViewer';\nexport type { Dimension, default as ComicViewerProps } from './ComicViewerProps';\nexport type { ViewerItemProps } from './ViewerItem';\nexport type {\n AbsolutePosition,\n FastScrollInstance,\n FastScrollOptions,\n VisibleDurations,\n} from './FastScrollProps';\n"],"mappings":"AAAA,SAASA,OAAT,QAAwB,eAAxB"}
|
|
1
|
+
{"version":3,"names":["default"],"sources":["index.ts"],"sourcesContent":["export { default } from './ComicViewer';\nexport type { Dimension, IntrinsicImage, default as ComicViewerProps } from './ComicViewerProps';\nexport type { ViewerItemProps } from './ViewerItem';\nexport type {\n AbsolutePosition,\n FastScrollInstance,\n FastScrollOptions,\n VisibleDurations,\n} from './FastScrollProps';\n"],"mappings":"AAAA,SAASA,OAAT,QAAwB,eAAxB"}
|
|
@@ -6,6 +6,10 @@ export interface Dimension {
|
|
|
6
6
|
width: number;
|
|
7
7
|
height: number;
|
|
8
8
|
}
|
|
9
|
+
export interface IntrinsicImage {
|
|
10
|
+
dimension: Dimension;
|
|
11
|
+
url: string;
|
|
12
|
+
}
|
|
9
13
|
export default interface ComicViewerProps extends ComponentProps<{
|
|
10
14
|
/**
|
|
11
15
|
* Delay Time to call the error handler.
|
|
@@ -34,9 +38,9 @@ export default interface ComicViewerProps extends ComponentProps<{
|
|
|
34
38
|
*/
|
|
35
39
|
itemVisiblePercentThreshold?: number;
|
|
36
40
|
/**
|
|
37
|
-
* Dimensions of each Image considering viewport.
|
|
41
|
+
* Dimensions and url info of each Image considering viewport.
|
|
38
42
|
*/
|
|
39
|
-
|
|
43
|
+
intrinsicImages: Array<IntrinsicImage>;
|
|
40
44
|
/**
|
|
41
45
|
* Need invisible paddingTop viewer vertically expanded.
|
|
42
46
|
* @default 0
|
|
@@ -60,10 +64,6 @@ export default interface ComicViewerProps extends ComponentProps<{
|
|
|
60
64
|
* Options for fastscroll component.
|
|
61
65
|
*/
|
|
62
66
|
fastScrollOptions: FastScrollOptions;
|
|
63
|
-
/**
|
|
64
|
-
* Get contents urls by indexes.
|
|
65
|
-
*/
|
|
66
|
-
getUrlByIndex: (indexes: Array<number>) => Promise<Map<number, string> | undefined>;
|
|
67
67
|
/**
|
|
68
68
|
* Handle scroll event.
|
|
69
69
|
* @param event Scroll event.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { default } from './ComicViewer';
|
|
2
|
-
export type { Dimension, default as ComicViewerProps } from './ComicViewerProps';
|
|
2
|
+
export type { Dimension, IntrinsicImage, default as ComicViewerProps } from './ComicViewerProps';
|
|
3
3
|
export type { ViewerItemProps } from './ViewerItem';
|
|
4
4
|
export type { AbsolutePosition, FastScrollInstance, FastScrollOptions, VisibleDurations, } from './FastScrollProps';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fountain-ui/lab",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.51",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Fountain-UI Team",
|
|
6
6
|
"description": "Incubator for Fountain-UI React components.",
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "2f2226a8063660b02bca06daef227daa2eea7654"
|
|
74
74
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { FlatList, ListRenderItem, NativeScrollEvent, NativeSyntheticEvent, ViewToken } from 'react-native';
|
|
3
3
|
import * as R from 'ramda';
|
|
4
|
-
import {
|
|
5
|
-
import { default as ComicViewerProps, Dimension } from './ComicViewerProps';
|
|
4
|
+
import { default as ComicViewerProps, Dimension, IntrinsicImage } from './ComicViewerProps';
|
|
6
5
|
import ViewerItem from './ViewerItem';
|
|
7
6
|
import FastScroll from './FastScroll';
|
|
8
7
|
|
|
@@ -17,23 +16,28 @@ interface UrlState {
|
|
|
17
16
|
}
|
|
18
17
|
|
|
19
18
|
interface ImageState {
|
|
20
|
-
urlState
|
|
21
|
-
isNewUrlIncoming: boolean;
|
|
19
|
+
urlState: UrlState;
|
|
22
20
|
totalErrorCount: number;
|
|
23
21
|
dimension: Dimension;
|
|
22
|
+
tryRenderingMillis: number;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
interface ItemState {
|
|
27
26
|
index: number;
|
|
28
27
|
url?: string;
|
|
28
|
+
imageKey: string;
|
|
29
29
|
reloadButtonVisible: boolean;
|
|
30
30
|
dimension: Dimension;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
const createInitialImageState = (
|
|
34
|
-
isNewUrlIncoming: false,
|
|
33
|
+
const createInitialImageState = (image: IntrinsicImage): ImageState => ({
|
|
35
34
|
totalErrorCount: 0,
|
|
36
|
-
dimension,
|
|
35
|
+
dimension: image.dimension,
|
|
36
|
+
tryRenderingMillis: 0,
|
|
37
|
+
urlState: {
|
|
38
|
+
url: image.url,
|
|
39
|
+
validity: 'unknown',
|
|
40
|
+
},
|
|
37
41
|
});
|
|
38
42
|
|
|
39
43
|
const mapImageStateToItemState = (
|
|
@@ -43,11 +47,12 @@ const mapImageStateToItemState = (
|
|
|
43
47
|
): ItemState => ({
|
|
44
48
|
index,
|
|
45
49
|
url: imageState.urlState?.url,
|
|
50
|
+
imageKey: `${imageState.tryRenderingMillis}-${index}`,
|
|
46
51
|
reloadButtonVisible: (imageState.urlState?.validity !== 'valid') && imageState.totalErrorCount >= autoHandleErrorCount,
|
|
47
52
|
dimension: imageState.dimension,
|
|
48
53
|
});
|
|
49
54
|
|
|
50
|
-
const mapIndexed = R.addIndex<
|
|
55
|
+
const mapIndexed = R.addIndex<IntrinsicImage>(R.map);
|
|
51
56
|
|
|
52
57
|
const MAXIMUM_WIDTH = 720;
|
|
53
58
|
|
|
@@ -58,11 +63,10 @@ export default function ComicViewer(props: ComicViewerProps) {
|
|
|
58
63
|
debounceMillis = 100,
|
|
59
64
|
autoHandleErrorCount = 3,
|
|
60
65
|
fastScrollOptions,
|
|
61
|
-
getUrlByIndex,
|
|
62
66
|
initialNumToRender = 1,
|
|
63
67
|
initialScrollPercentage = 0,
|
|
64
68
|
itemVisiblePercentThreshold = 0,
|
|
65
|
-
|
|
69
|
+
intrinsicImages,
|
|
66
70
|
maxContentWidth = MAXIMUM_WIDTH,
|
|
67
71
|
onItemPress,
|
|
68
72
|
onScroll,
|
|
@@ -82,7 +86,8 @@ export default function ComicViewer(props: ComicViewerProps) {
|
|
|
82
86
|
|
|
83
87
|
const actualImageWidth = Math.min(viewportWidth, maxContentWidth);
|
|
84
88
|
|
|
85
|
-
const initialImageStates = useMemo<Array<ImageState>>(() => R.map(createInitialImageState,
|
|
89
|
+
const initialImageStates = useMemo<Array<ImageState>>(() => R.map(createInitialImageState, intrinsicImages), []);
|
|
90
|
+
|
|
86
91
|
const imageStatesRef = useRef<Array<ImageState>>(initialImageStates);
|
|
87
92
|
|
|
88
93
|
const mapImageStatesToItemStates = (imageStates: Array<ImageState>): Array<ItemState> => {
|
|
@@ -96,14 +101,14 @@ export default function ComicViewer(props: ComicViewerProps) {
|
|
|
96
101
|
});
|
|
97
102
|
|
|
98
103
|
const renderedDimensions = useMemo<Array<Dimension>>(() => {
|
|
99
|
-
return mapIndexed((
|
|
100
|
-
const height = (
|
|
104
|
+
return mapIndexed((intrinsicImage, index) => {
|
|
105
|
+
const height = (intrinsicImage.dimension.height * actualImageWidth) / intrinsicImage.dimension.width + (index === 0 ? invisiblePaddingTop : 0);
|
|
101
106
|
|
|
102
107
|
return {
|
|
103
108
|
width: actualImageWidth,
|
|
104
109
|
height: isNaN(height) ? 0 : height,
|
|
105
110
|
};
|
|
106
|
-
},
|
|
111
|
+
}, intrinsicImages);
|
|
107
112
|
}, [actualImageWidth]);
|
|
108
113
|
|
|
109
114
|
const layoutFromDimensions = useCallback(() => {
|
|
@@ -142,60 +147,31 @@ export default function ComicViewer(props: ComicViewerProps) {
|
|
|
142
147
|
});
|
|
143
148
|
};
|
|
144
149
|
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
const state = imageStatesRef.current[index];
|
|
148
|
-
|
|
149
|
-
return !state.isNewUrlIncoming
|
|
150
|
-
&& (R.isNil(state.urlState) || state.urlState?.validity === 'invalid');
|
|
151
|
-
}, indexes);
|
|
150
|
+
const updateItems = (indexes: number[]) => {
|
|
151
|
+
const tryRenderingMillis = new Date().getTime();
|
|
152
152
|
|
|
153
153
|
updateImageState((imageState, i) => {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const newUrl = urls?.get(i);
|
|
164
|
-
const urlState = imageState.urlState;
|
|
165
|
-
|
|
166
|
-
if (newUrl !== undefined && urlState?.validity !== 'valid') {
|
|
167
|
-
return {
|
|
168
|
-
...imageState,
|
|
169
|
-
urlState: {
|
|
170
|
-
url: newUrl,
|
|
171
|
-
validity: 'unknown',
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
}
|
|
154
|
+
const urlState = imageState.urlState;
|
|
155
|
+
const shouldRerender = R.includes(i, R.defaultTo([], indexes));
|
|
156
|
+
|
|
157
|
+
if (shouldRerender && urlState?.validity !== 'valid') {
|
|
158
|
+
return {
|
|
159
|
+
...imageState,
|
|
160
|
+
tryRenderingMillis,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
175
163
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
} catch (e) {
|
|
179
|
-
// ignore
|
|
180
|
-
} finally {
|
|
181
|
-
updateImageState((imageState, i) => {
|
|
182
|
-
return R.includes(i, filteredIndexes)
|
|
183
|
-
? { ...imageState, isNewUrlIncoming: false }
|
|
184
|
-
: imageState;
|
|
185
|
-
});
|
|
186
|
-
}
|
|
164
|
+
return imageState;
|
|
165
|
+
});
|
|
187
166
|
};
|
|
188
167
|
|
|
189
|
-
const
|
|
168
|
+
const renderMaybeLoadableItems = () => {
|
|
190
169
|
const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;
|
|
191
170
|
const affectedIndexes = R.range(startIndex, endIndex);
|
|
192
171
|
|
|
193
|
-
|
|
172
|
+
updateItems(affectedIndexes);
|
|
194
173
|
};
|
|
195
174
|
|
|
196
|
-
const ignoreDebounce = useRef(true);
|
|
197
|
-
const loadItemsDebounce = useDebounce(loadMaybeLoadableItems, debounceMillis);
|
|
198
|
-
|
|
199
175
|
const onViewableItemsChanged = useRef(({ viewableItems }: { viewableItems: Array<ViewToken> }) => {
|
|
200
176
|
const orderedViewableItems = R.sort((a, b) => (a.index || 0) - (b.index || 0), viewableItems);
|
|
201
177
|
|
|
@@ -211,14 +187,7 @@ export default function ComicViewer(props: ComicViewerProps) {
|
|
|
211
187
|
|
|
212
188
|
maybeLoadableItemsIndexRange.current = [startIndex, endIndex + 1];
|
|
213
189
|
|
|
214
|
-
|
|
215
|
-
loadMaybeLoadableItems();
|
|
216
|
-
|
|
217
|
-
ignoreDebounce.current = false;
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
loadItemsDebounce();
|
|
190
|
+
renderMaybeLoadableItems();
|
|
222
191
|
});
|
|
223
192
|
|
|
224
193
|
const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
@@ -241,7 +210,7 @@ export default function ComicViewer(props: ComicViewerProps) {
|
|
|
241
210
|
updateImageState((imageState, i) => {
|
|
242
211
|
const urlState = imageState.urlState;
|
|
243
212
|
|
|
244
|
-
if (i === index
|
|
213
|
+
if (i === index) {
|
|
245
214
|
return {
|
|
246
215
|
...imageState,
|
|
247
216
|
totalErrorCount: imageState.totalErrorCount + 1,
|
|
@@ -261,17 +230,14 @@ export default function ComicViewer(props: ComicViewerProps) {
|
|
|
261
230
|
|
|
262
231
|
const [startIndex, endIndex] = maybeLoadableItemsIndexRange.current;
|
|
263
232
|
if (index >= startIndex || index < endIndex) {
|
|
264
|
-
|
|
233
|
+
renderMaybeLoadableItems();
|
|
265
234
|
}
|
|
266
235
|
};
|
|
267
236
|
|
|
268
237
|
const handleReloadPress = () => {
|
|
269
238
|
onReloadPress && onReloadPress();
|
|
270
239
|
|
|
271
|
-
|
|
272
|
-
if (index >= startIndex || index < endIndex) {
|
|
273
|
-
loadUrlByIndex([index]);
|
|
274
|
-
}
|
|
240
|
+
updateItems([index]);
|
|
275
241
|
};
|
|
276
242
|
|
|
277
243
|
const onLoad = () => {
|
|
@@ -299,6 +265,7 @@ export default function ComicViewer(props: ComicViewerProps) {
|
|
|
299
265
|
onPress={onItemPress}
|
|
300
266
|
onReloadPress={handleReloadPress}
|
|
301
267
|
url={item.url}
|
|
268
|
+
imageKey={item.imageKey}
|
|
302
269
|
invisiblePaddingTop={index === 0 ? invisiblePaddingTop : 0}
|
|
303
270
|
width={renderedDimensions[index]?.width ?? 0}
|
|
304
271
|
height={renderedDimensions[index]?.height ?? 0}
|
|
@@ -8,6 +8,11 @@ export interface Dimension {
|
|
|
8
8
|
height: number;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
export interface IntrinsicImage {
|
|
12
|
+
dimension: Dimension;
|
|
13
|
+
url: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
export default interface ComicViewerProps extends ComponentProps <{
|
|
12
17
|
/**
|
|
13
18
|
* Delay Time to call the error handler.
|
|
@@ -41,9 +46,9 @@ export default interface ComicViewerProps extends ComponentProps <{
|
|
|
41
46
|
itemVisiblePercentThreshold?: number;
|
|
42
47
|
|
|
43
48
|
/**
|
|
44
|
-
* Dimensions of each Image considering viewport.
|
|
49
|
+
* Dimensions and url info of each Image considering viewport.
|
|
45
50
|
*/
|
|
46
|
-
|
|
51
|
+
intrinsicImages: Array<IntrinsicImage>;
|
|
47
52
|
|
|
48
53
|
/**
|
|
49
54
|
* Need invisible paddingTop viewer vertically expanded.
|
|
@@ -73,11 +78,6 @@ export default interface ComicViewerProps extends ComponentProps <{
|
|
|
73
78
|
*/
|
|
74
79
|
fastScrollOptions: FastScrollOptions;
|
|
75
80
|
|
|
76
|
-
/**
|
|
77
|
-
* Get contents urls by indexes.
|
|
78
|
-
*/
|
|
79
|
-
getUrlByIndex: (indexes: Array<number>) => Promise<Map<number, string> | undefined> ;
|
|
80
|
-
|
|
81
81
|
/**
|
|
82
82
|
* Handle scroll event.
|
|
83
83
|
* @param event Scroll event.
|
|
@@ -50,6 +50,11 @@ export interface ViewerItemProps {
|
|
|
50
50
|
* @default false
|
|
51
51
|
*/
|
|
52
52
|
reloadButtonVisible?: boolean;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* FuiImage key for trigger image rerender.
|
|
56
|
+
*/
|
|
57
|
+
imageKey: string;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
export default function ViewerItem(props: ViewerItemProps) {
|
|
@@ -57,6 +62,7 @@ export default function ViewerItem(props: ViewerItemProps) {
|
|
|
57
62
|
height,
|
|
58
63
|
url,
|
|
59
64
|
width,
|
|
65
|
+
imageKey,
|
|
60
66
|
invisiblePaddingTop,
|
|
61
67
|
onError,
|
|
62
68
|
onLoad,
|
|
@@ -89,6 +95,7 @@ export default function ViewerItem(props: ViewerItemProps) {
|
|
|
89
95
|
<TouchableWithoutFeedback onPress={onPress}>
|
|
90
96
|
<View style={styles.view}>
|
|
91
97
|
<FuiImage
|
|
98
|
+
key={imageKey}
|
|
92
99
|
cache={'web'}
|
|
93
100
|
disableDrag={true}
|
|
94
101
|
disableLongClick={true}
|
package/src/ComicViewer/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { default } from './ComicViewer';
|
|
2
|
-
export type { Dimension, default as ComicViewerProps } from './ComicViewerProps';
|
|
2
|
+
export type { Dimension, IntrinsicImage, default as ComicViewerProps } from './ComicViewerProps';
|
|
3
3
|
export type { ViewerItemProps } from './ViewerItem';
|
|
4
4
|
export type {
|
|
5
5
|
AbsolutePosition,
|