Added screenshots to the navigation plugin
Summary: Here I've attempted to add screenshots to the nav plugin. This isn't the most elegant solution, but it might have to do due to limitations on the event handler for navigation being fired when the navigation occurs, and not when all remote content on the view has loaded. With this in mind, I added a 1 second delay for the screenshot. This has its own issues such as navigating within a second away from the page will display the wrong view. If anyone has some suggestions I am open. Another issue faced here was that incoming nav events are now impure as I need to go take a screenshot on each nav event. Therefore, I have removed the the tests which no longer work for the NavPlugin. Reviewed By: danielbuechele Differential Revision: D16915859 fbshipit-source-id: 95db0d1ded2084441d49e1f2e4712c55acf9f1b8
This commit is contained in:
committed by
Facebook Github Bot
parent
7def9bb681
commit
d962bbbfb9
@@ -1,117 +0,0 @@
|
||||
/**
|
||||
* Copyright 2018-present Facebook.
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
import NavigationPlugin from '../';
|
||||
import {DefaultProvider} from '../util/autoCompleteProvider';
|
||||
|
||||
import type {Bookmark, PersistedState, URI} from '../flow-types';
|
||||
|
||||
function constructPersistedStateMock(): PersistedState {
|
||||
return {
|
||||
currentURI: '',
|
||||
appMatchPatterns: [],
|
||||
appMatchPatternsProvider: new DefaultProvider(),
|
||||
bookmarksProvider: new DefaultProvider(),
|
||||
bookmarks: new Map<URI, Bookmark>(),
|
||||
navigationEvents: [],
|
||||
};
|
||||
}
|
||||
|
||||
function constructPersistedStateMockWithEvents(): PersistedState {
|
||||
return {
|
||||
currentURI: '',
|
||||
appMatchPatterns: [],
|
||||
appMatchPatternsProvider: new DefaultProvider(),
|
||||
bookmarksProvider: new DefaultProvider(),
|
||||
bookmarks: new Map<URI, Bookmark>(),
|
||||
navigationEvents: [
|
||||
{
|
||||
uri: 'mock://this_is_a_mock_uri/mock/1',
|
||||
date: DATE_MOCK_2,
|
||||
},
|
||||
{
|
||||
uri: 'mock://this_is_a_mock_uri/mock/2',
|
||||
date: DATE_MOCK_3,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const DATE_MOCK_1 = new Date(2019, 6, 17, 11, 10, 0, 0);
|
||||
const DATE_MOCK_2 = new Date(2019, 6, 18, 11, 10, 0, 0);
|
||||
const DATE_MOCK_3 = new Date(2019, 6, 19, 11, 10, 0, 0);
|
||||
|
||||
const INCOMING_NAV_EVENT = {
|
||||
uri: 'mock://this_is_a_mock_uri/mock',
|
||||
date: DATE_MOCK_1,
|
||||
};
|
||||
|
||||
const INCOMING_UNDEFINED_NAV_EVENT = {
|
||||
date: DATE_MOCK_1,
|
||||
};
|
||||
|
||||
test('add incoming nav event to persisted state', () => {
|
||||
const persistedState = constructPersistedStateMock();
|
||||
const reducer = NavigationPlugin.persistedStateReducer;
|
||||
if (reducer) {
|
||||
const newPersistedState = reducer(
|
||||
persistedState,
|
||||
'nav_event',
|
||||
INCOMING_NAV_EVENT,
|
||||
);
|
||||
expect(newPersistedState.navigationEvents).toEqual([
|
||||
{
|
||||
uri: 'mock://this_is_a_mock_uri/mock',
|
||||
date: DATE_MOCK_1,
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
expect(reducer).not.toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
test('add incoming nav event to persisted state with nav events', () => {
|
||||
const persistedState = constructPersistedStateMockWithEvents();
|
||||
const reducer = NavigationPlugin.persistedStateReducer;
|
||||
if (reducer) {
|
||||
const newPersistedState = reducer(
|
||||
persistedState,
|
||||
'nav_event',
|
||||
INCOMING_NAV_EVENT,
|
||||
);
|
||||
expect(newPersistedState.navigationEvents).toEqual([
|
||||
{
|
||||
uri: 'mock://this_is_a_mock_uri/mock',
|
||||
date: DATE_MOCK_1,
|
||||
},
|
||||
...persistedState.navigationEvents,
|
||||
]);
|
||||
} else {
|
||||
expect(reducer).not.toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
test('add incoming nav event with undefined uri to persisted state', () => {
|
||||
const persistedState = constructPersistedStateMock();
|
||||
const reducer = NavigationPlugin.persistedStateReducer;
|
||||
if (reducer) {
|
||||
const newPersistedState = reducer(
|
||||
persistedState,
|
||||
'nav_event',
|
||||
INCOMING_UNDEFINED_NAV_EVENT,
|
||||
);
|
||||
expect(newPersistedState.navigationEvents).toEqual([
|
||||
{
|
||||
uri: null,
|
||||
date: DATE_MOCK_1,
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
expect(reducer).not.toBeNull();
|
||||
}
|
||||
});
|
||||
@@ -6,7 +6,7 @@
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
import {colors, FlexCenter, styled} from 'flipper';
|
||||
import {colors, FlexCenter, styled, LoadingIndicator} from 'flipper';
|
||||
import {NavigationInfoBox} from './';
|
||||
|
||||
import type {Bookmark, NavigationEvent} from '../flow-types';
|
||||
@@ -23,6 +23,11 @@ const TimelineContainer = styled('div')({
|
||||
flexGrow: 1,
|
||||
});
|
||||
|
||||
const NavigationEventContainer = styled('div')({
|
||||
display: 'flex',
|
||||
margin: 20,
|
||||
});
|
||||
|
||||
const NoData = styled(FlexCenter)({
|
||||
height: '100%',
|
||||
fontSize: 18,
|
||||
@@ -30,6 +35,18 @@ const NoData = styled(FlexCenter)({
|
||||
color: colors.macOSTitleBarIcon,
|
||||
});
|
||||
|
||||
const ScreenshotContainer = styled('div')({
|
||||
width: 200,
|
||||
minWidth: 200,
|
||||
margin: 10,
|
||||
border: `1px solid ${colors.highlight}`,
|
||||
borderRadius: '10px',
|
||||
overflow: 'hidden',
|
||||
img: {
|
||||
width: '100%',
|
||||
},
|
||||
});
|
||||
|
||||
export default (props: Props) => {
|
||||
const {bookmarks, events, onNavigate, onFavorite} = props;
|
||||
return events.length === 0 ? (
|
||||
@@ -38,13 +55,28 @@ export default (props: Props) => {
|
||||
<TimelineContainer>
|
||||
{events.map((event: NavigationEvent, idx) => {
|
||||
return (
|
||||
<NavigationEventContainer>
|
||||
{event.uri != null ? (
|
||||
<ScreenshotContainer>
|
||||
{event.screenshot != null ? (
|
||||
<img src={event.screenshot} />
|
||||
) : (
|
||||
<FlexCenter grow>
|
||||
<LoadingIndicator />
|
||||
</FlexCenter>
|
||||
)}
|
||||
</ScreenshotContainer>
|
||||
) : null}
|
||||
<NavigationInfoBox
|
||||
key={idx}
|
||||
isBookmarked={event.uri != null ? bookmarks.has(event.uri) : false}
|
||||
isBookmarked={
|
||||
event.uri != null ? bookmarks.has(event.uri) : false
|
||||
}
|
||||
uri={event.uri}
|
||||
onNavigate={onNavigate}
|
||||
onFavorite={onFavorite}
|
||||
/>
|
||||
</NavigationEventContainer>
|
||||
);
|
||||
})}
|
||||
</TimelineContainer>
|
||||
|
||||
@@ -27,6 +27,7 @@ export type PersistedState = {|
|
||||
export type NavigationEvent = {|
|
||||
date: ?Date,
|
||||
uri: ?URI,
|
||||
screenshot: ?string,
|
||||
|};
|
||||
|
||||
export type Bookmark = {|
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
import {FlipperPlugin} from 'flipper';
|
||||
import {FlipperPlugin, bufferToBlob} from 'flipper';
|
||||
import {
|
||||
BookmarksSidebar,
|
||||
SaveBookmarkDialog,
|
||||
@@ -63,19 +63,6 @@ export default class extends FlipperPlugin<State, {}, PersistedState> {
|
||||
payload: NavigationEvent,
|
||||
): $Shape<PersistedState> => {
|
||||
switch (method) {
|
||||
case 'nav_event':
|
||||
return {
|
||||
...persistedState,
|
||||
currentURI:
|
||||
payload.uri == null ? persistedState.currentURI : payload.uri,
|
||||
navigationEvents: [
|
||||
{
|
||||
uri: payload.uri === undefined ? null : payload.uri,
|
||||
date: payload.date || new Date(),
|
||||
},
|
||||
...persistedState.navigationEvents,
|
||||
],
|
||||
};
|
||||
default:
|
||||
return {
|
||||
...persistedState,
|
||||
@@ -83,8 +70,38 @@ export default class extends FlipperPlugin<State, {}, PersistedState> {
|
||||
}
|
||||
};
|
||||
|
||||
subscribeToNavigationEvents = () => {
|
||||
this.client.subscribe('nav_event', payload => {
|
||||
let {persistedState} = this.props;
|
||||
const {setPersistedState} = this.props;
|
||||
const navigationEvent: NavigationEvent = {
|
||||
uri: payload.uri === undefined ? null : payload.uri,
|
||||
date: payload.date || new Date(),
|
||||
screenshot: null,
|
||||
};
|
||||
setPersistedState({
|
||||
...persistedState,
|
||||
currentURI:
|
||||
payload.uri == null ? persistedState.currentURI : payload.uri,
|
||||
navigationEvents: [navigationEvent, ...persistedState.navigationEvents],
|
||||
});
|
||||
// Wait for view to render and then take a screenshot
|
||||
setTimeout(() => {
|
||||
persistedState = this.props.persistedState;
|
||||
this.getDevice()
|
||||
.then(device => device.screenshot())
|
||||
.then((buffer: Buffer) => {
|
||||
const blobURL = URL.createObjectURL(bufferToBlob(buffer));
|
||||
navigationEvent.screenshot = blobURL;
|
||||
setPersistedState({...persistedState});
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
};
|
||||
|
||||
componentDidMount = () => {
|
||||
const {selectedApp} = this.props;
|
||||
this.subscribeToNavigationEvents();
|
||||
getAppMatchPatterns(selectedApp)
|
||||
.then(patterns => {
|
||||
this.props.setPersistedState({
|
||||
|
||||
Reference in New Issue
Block a user