Convert Flipper plugin "Fresco" to TypeScript

Summary:
Moves the Fresco plugin to TypeScript, including fixing any typing/nullable warnings following this.

Note that parameters of event handlers previously using the SyntheticInputEvent flow type now accept a parameter of type `any`. This is done since the InputEvent api is not covered by ts bindings, as the interface is deemed experimental and not fully covered by browsers (see https://fettblog.eu/typescript-react/events/#wheres-inputevent for more info)

Reviewed By: passy

Differential Revision: D18201893

fbshipit-source-id: 41d1e5fc1ceaa8f8453c0f5929e754b7c32c0eb8
This commit is contained in:
Gijs Weterings
2019-10-30 08:28:23 -07:00
committed by Facebook Github Bot
parent 7ca230a9c6
commit d0ab63297f
10 changed files with 279 additions and 267 deletions

View File

@@ -7,15 +7,15 @@
* @format
*/
import type {ImageId, ImageData} from './api.js';
import {ImageId, ImageData} from './api.js';
export type ImagesMap = {[imageId: ImageId]: ImageData};
export type ImagesMap = {[imageId in ImageId]: ImageData};
const maxInflightRequests = 10;
export default class ImagePool {
cache: ImagesMap = {};
requested: {[imageId: ImageId]: boolean} = {};
requested: {[imageId in ImageId]: boolean} = {};
queued: Array<ImageId> = [];
inFlightRequests: number = 0;
fetchImage: (imageId: ImageId) => void;
@@ -59,7 +59,8 @@ export default class ImagePool {
delete this.requested[image.imageId];
if (this.queued.length > 0) {
this.fetchImage(this.queued.pop());
const popped = this.queued.pop() as string;
this.fetchImage(popped);
} else {
this.inFlightRequests--;
}

View File

@@ -7,8 +7,8 @@
* @format
*/
import type {ImageId, ImageData, ImagesList} from './api.js';
import type {ImageEventWithId} from './index.js';
import {CacheInfo, ImageId, ImageData, ImagesList} from './api';
import {ImageEventWithId} from './index';
import {
Toolbar,
@@ -24,10 +24,10 @@ import {
ToggleButton,
Text,
} from 'flipper';
import MultipleSelect from './MultipleSelect.js';
import type {ImagesMap} from './ImagePool.js';
import MultipleSelect from './MultipleSelect';
import {ImagesMap} from './ImagePool';
import {clipboard} from 'electron';
import {PureComponent} from 'react';
import React, {ChangeEvent, KeyboardEvent, PureComponent} from 'react';
function formatMB(bytes: number) {
return Math.floor(bytes / (1024 * 1024)) + 'MB';
@@ -37,11 +37,11 @@ function formatKB(bytes: number) {
return Math.floor(bytes / 1024) + 'KB';
}
type ToggleProps = {|
label: string,
onClick?: (newValue: boolean) => void,
toggled: boolean,
|};
type ToggleProps = {
label: string;
onClick?: (newValue: boolean) => void;
toggled: boolean;
};
const ToolbarToggleButton = styled(ToggleButton)(_props => ({
alignSelf: 'center',
@@ -68,31 +68,31 @@ function Toggle(props: ToggleProps) {
}
type ImagesCacheOverviewProps = {
onColdStartChange: (checked: boolean) => void,
coldStartFilter: boolean,
allSurfacesOption: string,
surfaceOptions: Set<string>,
selectedSurfaces: Set<string>,
onChangeSurface: (key: Set<string>) => void,
images: ImagesList,
onClear: (type: string) => void,
onTrimMemory: () => void,
onRefresh: () => void,
onEnableDebugOverlay: (enabled: boolean) => void,
isDebugOverlayEnabled: boolean,
onEnableAutoRefresh: (enabled: boolean) => void,
isAutoRefreshEnabled: boolean,
onImageSelected: (selectedImage: ImageId) => void,
imagesMap: ImagesMap,
events: Array<ImageEventWithId>,
onTrackLeaks: (enabled: boolean) => void,
isLeakTrackingEnabled: boolean,
onColdStartChange: (checked: boolean) => void;
coldStartFilter: boolean;
allSurfacesOption: string;
surfaceOptions: Set<string>;
selectedSurfaces: Set<string>;
onChangeSurface: (key: Set<string>) => void;
images: ImagesList;
onClear: (type: string) => void;
onTrimMemory: () => void;
onRefresh: () => void;
onEnableDebugOverlay: (enabled: boolean) => void;
isDebugOverlayEnabled: boolean;
onEnableAutoRefresh: (enabled: boolean) => void;
isAutoRefreshEnabled: boolean;
onImageSelected: (selectedImage: ImageId) => void;
imagesMap: ImagesMap;
events: Array<ImageEventWithId>;
onTrackLeaks: (enabled: boolean) => void;
isLeakTrackingEnabled: boolean;
};
type ImagesCacheOverviewState = {|
selectedImage: ?ImageId,
size: number,
|};
type ImagesCacheOverviewState = {
selectedImage: ImageId | null;
size: number;
};
const StyledSelect = styled(Select)(props => ({
marginLeft: 6,
@@ -103,8 +103,13 @@ const StyledSelect = styled(Select)(props => ({
export default class ImagesCacheOverview extends PureComponent<
ImagesCacheOverviewProps,
ImagesCacheOverviewState,
ImagesCacheOverviewState
> {
state = {
selectedImage: null,
size: 150,
};
static Container = styled(FlexColumn)({
backgroundColor: colors.white,
});
@@ -121,17 +126,12 @@ export default class ImagesCacheOverview extends PureComponent<
width: '100%',
});
state = {
selectedImage: undefined,
size: 150,
};
onImageSelected = (selectedImage: ImageId) => {
this.setState({selectedImage});
this.props.onImageSelected(selectedImage);
};
onKeyDown = (e: SyntheticKeyboardEvent<*>) => {
onKeyDown = (e: KeyboardEvent) => {
const selectedImage = this.state.selectedImage;
const imagesMap = this.props.imagesMap;
@@ -151,7 +151,7 @@ export default class ImagesCacheOverview extends PureComponent<
this.props.onEnableAutoRefresh(!this.props.isAutoRefreshEnabled);
};
onChangeSize = (e: SyntheticInputEvent<HTMLInputElement>) =>
onChangeSize = (e: ChangeEvent<HTMLInputElement>) =>
this.setState({size: parseInt(e.target.value, 10)});
onSurfaceOptionsChange = (selectedItem: string, checked: boolean) => {
@@ -199,7 +199,7 @@ export default class ImagesCacheOverview extends PureComponent<
<ImagesCacheOverview.Container
grow={true}
onKeyDown={this.onKeyDown}
tabIndex="0">
tabIndex={0}>
<Toolbar position="top">
<Button icon="trash" onClick={this.props.onTrimMemory}>
Trim Memory
@@ -242,18 +242,19 @@ export default class ImagesCacheOverview extends PureComponent<
</Toolbar>
{!hasImages ? (
<ImagesCacheOverview.Empty>
<LoadingIndicator />
<LoadingIndicator size={50} />
</ImagesCacheOverview.Empty>
) : (
<ImagesCacheOverview.Content>
{this.props.images.map((data, index) => {
{this.props.images.map((data: CacheInfo, index: number) => {
const maxSize = data.maxSizeBytes;
const subtitle = maxSize
? formatMB(data.sizeBytes) + ' / ' + formatMB(maxSize)
: formatMB(data.sizeBytes);
const onClear = data.clearKey
? () => this.props.onClear(data.clearKey)
: null;
const onClear =
data.clearKey !== undefined
? () => this.props.onClear(data.clearKey as string)
: undefined;
return (
<ImageGrid
key={index}
@@ -277,15 +278,15 @@ export default class ImagesCacheOverview extends PureComponent<
}
class ImageGrid extends PureComponent<{
title: string,
subtitle: string,
images: Array<ImageId>,
selectedImage: ?ImageId,
onImageSelected: (image: ImageId) => void,
onClear: ?() => void,
imagesMap: ImagesMap,
size: number,
events: Array<ImageEventWithId>,
title: string;
subtitle: string;
images: Array<ImageId>;
selectedImage: ImageId | null;
onImageSelected: (image: ImageId) => void;
onClear: (() => void) | undefined;
imagesMap: ImagesMap;
size: number;
events: Array<ImageEventWithId>;
}> {
static Content = styled('div')({
paddingLeft: 15,
@@ -325,9 +326,9 @@ class ImageGrid extends PureComponent<{
}
class ImageGridHeader extends PureComponent<{
title: string,
subtitle: string,
onClear: ?() => void,
title: string;
subtitle: string;
onClear: (() => void) | undefined;
}> {
static Container = styled(FlexRow)({
color: colors.dark70,
@@ -384,20 +385,20 @@ class ImageGridHeader extends PureComponent<{
}
class ImageItem extends PureComponent<{
imageId: ImageId,
image: ?ImageData,
selected: boolean,
onSelected: (image: ImageId) => void,
size: number,
numberOfRequests: number,
imageId: ImageId;
image: ImageData;
selected: boolean;
onSelected: (image: ImageId) => void;
size: number;
numberOfRequests: number;
}> {
static Container = styled(FlexBox)(({size}) => ({
static Container = styled(FlexBox)((props: {size: number}) => ({
float: 'left',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
height: size,
width: size,
height: props.size,
width: props.size,
borderRadius: 4,
marginRight: 15,
marginBottom: 15,
@@ -415,7 +416,7 @@ class ImageItem extends PureComponent<{
padding: '0 0',
});
static SelectedHighlight = styled('div')(props => ({
static SelectedHighlight = styled('div')((props: {selected: boolean}) => ({
borderColor: colors.highlight,
borderStyle: 'solid',
borderWidth: props.selected ? 3 : 0,
@@ -428,7 +429,8 @@ class ImageItem extends PureComponent<{
top: 0,
}));
static HoverOverlay = styled(FlexColumn)(props => ({
static HoverOverlay = styled(FlexColumn)(
(props: {selected: boolean; size: number}) => ({
alignItems: 'center',
backgroundColor: colors.whiteAlpha80,
bottom: props.selected ? 4 : 0,
@@ -444,7 +446,8 @@ class ImageItem extends PureComponent<{
'&:hover': {
opacity: 1,
},
}));
}),
);
static MemoryLabel = styled('span')({
fontWeight: 600,

View File

@@ -7,8 +7,8 @@
* @format
*/
import type {ImageData} from './api.js';
import type {ImageEventWithId} from './index.js';
import {ImageData} from './api';
import {ImageEventWithId} from './index';
import {
Component,
DataDescription,
@@ -20,10 +20,11 @@ import {
colors,
styled,
} from 'flipper';
import React from 'react';
type ImagesSidebarProps = {
image: ?ImageData,
events: Array<ImageEventWithId>,
image: ImageData;
events: Array<ImageEventWithId>;
};
type ImagesSidebarState = {};
@@ -38,7 +39,7 @@ const WordBreakFlexColumn = styled(FlexColumn)({
export default class ImagesSidebar extends Component<
ImagesSidebarProps,
ImagesSidebarState,
ImagesSidebarState
> {
render() {
return (
@@ -81,7 +82,7 @@ export default class ImagesSidebar extends Component<
}
class EventDetails extends Component<{
event: ImageEventWithId,
event: ImageEventWithId;
}> {
render() {
const {event} = this.props;
@@ -158,9 +159,9 @@ class EventDetails extends Component<{
}
class RequestHeader extends Component<{
event: ImageEventWithId,
event: ImageEventWithId;
}> {
dateString = timestamp => {
dateString = (timestamp: number) => {
const date = new Date(timestamp);
return `${date.toTimeString().split(' ')[0]}.${(
'000' + date.getMilliseconds()

View File

@@ -8,7 +8,7 @@
*/
import {Block, Button, colors, FlexColumn, styled, Glyph} from 'flipper';
import React, {Component} from 'react';
import React, {ChangeEvent, Component} from 'react';
const Container = styled(Block)({
position: 'relative',
@@ -54,26 +54,26 @@ const StyledGlyph = styled(Glyph)({
});
type State = {
visibleList: boolean,
visibleList: boolean;
};
export default class MultipleSelect extends Component<
{
selected: Set<string>,
selected: Set<string>;
options: Set<string>,
options: Set<string>;
onChange: (selectedItem: string, checked: boolean) => void,
onChange: (selectedItem: string, checked: boolean) => void;
label: string,
label: string;
},
State,
State
> {
state = {
visibleList: false,
};
handleOnChange = (event: SyntheticInputEvent<HTMLInputElement>) => {
handleOnChange = (event: ChangeEvent<HTMLInputElement>) => {
const {
target: {value, checked},
} = event;

View File

@@ -7,23 +7,26 @@
* @format
*/
import FrescoPlugin from '../index.js';
import type {PersistedState, ImageEventWithId} from '../index.js';
import type {AndroidCloseableReferenceLeakEvent} from '../api.js';
import type {MetricType} from 'flipper';
import type {Notification} from '../../../plugin.tsx';
import FrescoPlugin from '../index';
import {PersistedState, ImageEventWithId} from '../index';
import {AndroidCloseableReferenceLeakEvent} from '../api';
import {MetricType} from 'flipper';
import {Notification} from '../../../plugin';
import {ImagesMap} from '../ImagePool';
type ScanDisplayTime = {[scan_number: number]: number};
function mockPersistedState(
imageSizes: Array<{
width: number,
height: number,
width: number;
height: number;
}> = [],
viewport: {
width: number,
height: number,
width: number;
height: number;
} = {width: 150, height: 150},
): PersistedState {
const scanDisplayTime = {};
const scanDisplayTime: ScanDisplayTime = {};
scanDisplayTime[1] = 3;
const events: Array<ImageEventWithId> = [
{
@@ -38,16 +41,19 @@ function mockPersistedState(
},
];
const imagesMap = imageSizes.reduce((acc, val, index) => {
const imagesMap = imageSizes.reduce(
(acc, val, index) => {
acc[index] = {
imageId: String(index),
width: val.width,
height: val.height,
sizeBytes: 10,
data: undefined,
data: 'undefined',
};
return acc;
}, {});
},
{} as ImagesMap,
);
return {
surfaceList: new Set(),
@@ -184,9 +190,8 @@ test('the metric reducer with the no viewPort data in events', () => {
const metrics = metricsReducer(persistedState);
return expect(metrics).resolves.toMatchObject({WASTED_BYTES: 0});
});
test('the metric reducer with the multiple events', () => {
const scanDisplayTime = {};
const scanDisplayTime: ScanDisplayTime = {};
scanDisplayTime[1] = 3;
const events: Array<ImageEventWithId> = [
{
@@ -228,22 +233,27 @@ test('the metric reducer with the multiple events', () => {
height: 300,
},
];
const imagesMap = imageSizes.reduce((acc, val, index) => {
const imagesMap = imageSizes.reduce(
(acc, val, index) => {
acc[index] = {
imageId: String(index),
width: val.width,
height: val.height,
sizeBytes: 10,
data: undefined,
data: 'undefined',
};
return acc;
}, {});
},
{} as ImagesMap,
);
const persistedState = {
surfaceList: new Set(),
surfaceList: new Set<string>(),
images: [],
nextEventId: 0,
events,
imagesMap,
closeableReferenceLeaks: [],
isLeakTrackingEnabled: true,
};
const metricsReducer = FrescoPlugin.metricsReducer;
expect(metricsReducer).toBeDefined();
@@ -255,7 +265,7 @@ test('the metric reducer with the multiple events', () => {
test('closeable reference metrics on empty state', () => {
const metricsReducer: (
persistedState: PersistedState,
) => Promise<MetricType> = (FrescoPlugin.metricsReducer: any);
) => Promise<MetricType> = FrescoPlugin.metricsReducer;
const persistedState = mockPersistedState();
const metrics = metricsReducer(persistedState);
return expect(metrics).resolves.toMatchObject({CLOSEABLE_REFERENCE_LEAKS: 0});
@@ -264,7 +274,7 @@ test('closeable reference metrics on empty state', () => {
test('closeable reference metrics on input', () => {
const metricsReducer: (
persistedState: PersistedState,
) => Promise<MetricType> = (FrescoPlugin.metricsReducer: any);
) => Promise<MetricType> = FrescoPlugin.metricsReducer;
const closeableReferenceLeaks: Array<AndroidCloseableReferenceLeakEvent> = [
{
identityHashCode: 'deadbeef',
@@ -288,7 +298,7 @@ test('closeable reference metrics on input', () => {
test('notifications for leaks', () => {
const notificationReducer: (
persistedState: PersistedState,
) => Array<Notification> = (FrescoPlugin.getActiveNotifications: any);
) => Array<Notification> = FrescoPlugin.getActiveNotifications;
const closeableReferenceLeaks: Array<AndroidCloseableReferenceLeakEvent> = [
{
identityHashCode: 'deadbeef',

View File

@@ -1,77 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
export type ImageId = string;
// Listing images
export type CacheInfo = {|
cacheType: string,
clearKey?: null, // set this if this cache level supports clear(<key>)
sizeBytes: number,
maxSizeBytes?: number,
imageIds: Array<ImageId>,
|};
export type ImagesList = Array<CacheInfo>;
// The iOS Flipper api does not support a top-level array, so we wrap it in an object
export type ImagesListResponse = {|
levels: ImagesList,
|};
// listImages() -> ImagesListResponse
// Getting details on a specific image
export type ImageBytes = string;
export type ImageData = {|
imageId: ImageId,
uri?: string,
width: number,
height: number,
sizeBytes: number,
data: ImageBytes,
surface?: string,
|};
// getImage({imageId: string}) -> ImageData
// Subscribing to image events (requests and prefetches)
export type Timestamp = number;
export type ViewportData = {|
width: number,
height: number,
scanDisplayTime: {[scan_number: number]: Timestamp},
|};
export type ImageEvent = {
imageIds: Array<ImageId>,
attribution: Array<string>,
startTime: Timestamp,
endTime: Timestamp,
source: string,
coldStart: boolean,
viewport?: ViewportData, // not set for prefetches
};
// Misc
export type FrescoDebugOverlayEvent = {|
enabled: boolean,
|};
export type AndroidCloseableReferenceLeakEvent = {|
identityHashCode: string,
className: string,
stacktrace: ?string,
|};

View File

@@ -0,0 +1,77 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
export type ImageId = string;
// Listing images
export type CacheInfo = {
cacheType: string;
clearKey?: string; // set this if this cache level supports clear(<key>)
sizeBytes: number;
maxSizeBytes?: number;
imageIds: Array<ImageId>;
};
export type ImagesList = Array<CacheInfo>;
// The iOS Flipper api does not support a top-level array, so we wrap it in an object
export type ImagesListResponse = {
levels: ImagesList;
};
// listImages() -> ImagesListResponse
// Getting details on a specific image
export type ImageBytes = string;
export type ImageData = {
imageId: ImageId;
uri?: string;
width: number;
height: number;
sizeBytes: number;
data: ImageBytes;
surface?: string;
};
// getImage({imageId: string}) -> ImageData
// Subscribing to image events (requests and prefetches)
export type Timestamp = number;
export type ViewportData = {
width: number;
height: number;
scanDisplayTime: {[scan_number: number]: Timestamp};
};
export type ImageEvent = {
imageIds: Array<ImageId>;
attribution: Array<string>;
startTime: Timestamp;
endTime: Timestamp;
source: string;
coldStart: boolean;
viewport?: ViewportData; // not set for prefetches
};
// Misc
export type FrescoDebugOverlayEvent = {
enabled: boolean;
};
export type AndroidCloseableReferenceLeakEvent = {
identityHashCode: string;
className: string;
stacktrace: string | null;
};

View File

@@ -7,7 +7,7 @@
* @format
*/
import type {
import {
ImageId,
ImageData,
ImagesList,
@@ -16,12 +16,12 @@ import type {
FrescoDebugOverlayEvent,
AndroidCloseableReferenceLeakEvent,
CacheInfo,
} from './api.js';
} from './api';
import {Fragment} from 'react';
import type {ImagesMap} from './ImagePool.js';
import type {MetricType, MiddlewareAPI} from 'flipper';
import {ImagesMap} from './ImagePool';
import {MetricType, MiddlewareAPI} from 'flipper';
import React from 'react';
import ImagesCacheOverview from './ImagesCacheOverview.js';
import ImagesCacheOverview from './ImagesCacheOverview';
import {
FlipperPlugin,
FlexRow,
@@ -31,29 +31,29 @@ import {
styled,
isProduction,
} from 'flipper';
import ImagesSidebar from './ImagesSidebar.js';
import ImagePool from './ImagePool.js';
import type {Notification} from '../../plugin.tsx';
import ImagesSidebar from './ImagesSidebar';
import ImagePool from './ImagePool';
import {Notification, BaseAction} from '../../plugin';
export type ImageEventWithId = ImageEvent & {eventId: number};
export type PersistedState = {
surfaceList: Set<string>,
images: ImagesList,
events: Array<ImageEventWithId>,
imagesMap: ImagesMap,
closeableReferenceLeaks: Array<AndroidCloseableReferenceLeakEvent>,
isLeakTrackingEnabled: boolean,
nextEventId: number,
surfaceList: Set<string>;
images: ImagesList;
events: Array<ImageEventWithId>;
imagesMap: ImagesMap;
closeableReferenceLeaks: Array<AndroidCloseableReferenceLeakEvent>;
isLeakTrackingEnabled: boolean;
nextEventId: number;
};
type PluginState = {
selectedSurfaces: Set<string>,
selectedImage: ?ImageId,
isDebugOverlayEnabled: boolean,
isAutoRefreshEnabled: boolean,
images: ImagesList,
coldStartFilter: boolean,
selectedSurfaces: Set<string>;
selectedImage: ImageId | null;
isDebugOverlayEnabled: boolean;
isAutoRefreshEnabled: boolean;
images: ImagesList;
coldStartFilter: boolean;
};
const EmptySidebar = styled(FlexRow)({
@@ -70,23 +70,23 @@ export const InlineFlexRow = styled(FlexRow)({
const surfaceDefaultText = 'SELECT ALL SURFACES';
const debugLog = (...args) => {
const debugLog = (...args: any[]) => {
if (!isProduction()) {
// eslint-disable-next-line no-console
console.log(...args);
}
};
type ImagesMetaData = {|
levels: ImagesListResponse,
events: Array<ImageEventWithId>,
imageDataList: Array<ImageData>,
|};
type ImagesMetaData = {
levels: ImagesListResponse;
events: Array<ImageEventWithId>;
imageDataList: Array<ImageData>;
};
export default class FlipperImagesPlugin extends FlipperPlugin<
PluginState,
*,
PersistedState,
BaseAction,
PersistedState
> {
static defaultPersistedState: PersistedState = {
images: [],
@@ -99,10 +99,10 @@ export default class FlipperImagesPlugin extends FlipperPlugin<
};
static exportPersistedState = (
callClient: (string, ?Object) => Promise<Object>,
persistedState: ?PersistedState,
store: ?MiddlewareAPI,
): Promise<?PersistedState> => {
callClient: (method: string, params?: any) => Promise<any>,
persistedState: PersistedState,
store?: MiddlewareAPI,
): Promise<PersistedState> => {
const defaultPromise = Promise.resolve(persistedState);
if (!persistedState) {
persistedState = FlipperImagesPlugin.defaultPersistedState;
@@ -149,9 +149,9 @@ export default class FlipperImagesPlugin extends FlipperPlugin<
acc.add(id);
});
return acc;
}, new Set());
}, new Set<string>());
const imageDataList: Array<ImageData> = [];
for (const id: string of idSet) {
for (const id of idSet) {
try {
const imageData: ImageData = await callClient('getImage', {
imageId: id,
@@ -173,10 +173,10 @@ export default class FlipperImagesPlugin extends FlipperPlugin<
static persistedStateReducer = (
persistedState: PersistedState,
method: string,
data: Object,
data: AndroidCloseableReferenceLeakEvent | ImageEvent,
): PersistedState => {
if (method == 'closeable_reference_leak_event') {
const event: AndroidCloseableReferenceLeakEvent = data;
const event: AndroidCloseableReferenceLeakEvent = data as AndroidCloseableReferenceLeakEvent;
return {
...persistedState,
closeableReferenceLeaks: persistedState.closeableReferenceLeaks.concat(
@@ -184,8 +184,7 @@ export default class FlipperImagesPlugin extends FlipperPlugin<
),
};
} else if (method == 'events') {
const event: ImageEvent = data;
const event: ImageEvent = data as ImageEvent;
debugLog('Received events', event);
const {surfaceList} = persistedState;
const {attribution} = event;
@@ -267,11 +266,7 @@ export default class FlipperImagesPlugin extends FlipperPlugin<
category: 'closeablereference_leak',
}));
state: PluginState;
imagePool: ImagePool;
nextEventId: number = 1;
state = {
state: PluginState = {
selectedSurfaces: new Set([surfaceDefaultText]),
selectedImage: null,
isDebugOverlayEnabled: false,
@@ -279,6 +274,8 @@ export default class FlipperImagesPlugin extends FlipperPlugin<
images: [],
coldStartFilter: false,
};
imagePool: ImagePool | undefined;
nextEventId: number = 1;
filterImages = (
images: ImagesList,
@@ -340,7 +337,7 @@ export default class FlipperImagesPlugin extends FlipperPlugin<
}
teardown() {
this.imagePool.clear();
this.imagePool ? this.imagePool.clear() : undefined;
}
updateImagesOnUI = (
@@ -365,7 +362,7 @@ export default class FlipperImagesPlugin extends FlipperPlugin<
debugLog('Requesting images list (reason=' + reason + ')');
this.client.call('listImages').then((response: ImagesListResponse) => {
response.levels.forEach(data =>
this.imagePool.fetchImages(data.imageIds),
this.imagePool ? this.imagePool.fetchImages(data.imageIds) : undefined,
);
this.props.setPersistedState({images: response.levels});
this.updateImagesOnUI(
@@ -409,7 +406,7 @@ export default class FlipperImagesPlugin extends FlipperPlugin<
debugLog('<- getImage requested for ' + imageId);
this.client.call('getImage', {imageId}).then((image: ImageData) => {
debugLog('-> getImage ' + imageId + ' returned');
this.imagePool._fetchCompleted(image);
this.imagePool ? this.imagePool._fetchCompleted(image) : undefined;
});
};

View File

@@ -1,7 +1,7 @@
{
"name": "Fresco",
"version": "1.0.0",
"main": "index.js",
"main": "index.tsx",
"license": "MIT",
"keywords": ["flipper-plugin"],
"title": "Images",