added gpx dialog

This commit is contained in:
Fedor Katurov 2020-01-24 16:53:47 +07:00
parent 947ec69e60
commit e995b46641
33 changed files with 11687 additions and 131 deletions

View file

@ -0,0 +1,147 @@
import React, { FC, useCallback, ChangeEvent } from 'react';
import { connect } from 'react-redux';
import * as EDITOR_ACTIONS from '~/redux/editor/actions';
import { IState } from '~/redux/store';
import { selectEditorGpx } from '~/redux/editor/selectors';
import { GpxDialogRow } from '~/components/gpx/GpxDialogRow';
import { MainMap } from '~/constants/map';
import { latLngBounds } from 'leaflet';
import { Switch } from '../Switch';
import { selectMapRoute, selectMapTitle, selectMapAddress } from '~/redux/map/selectors';
import classNames from 'classnames';
import uuid from 'uuid';
import { getUrlData } from '~/utils/history';
import { getRandomColor } from '~/utils/dom';
const mapStateToProps = (state: IState) => ({
gpx: selectEditorGpx(state),
route: selectMapRoute(state),
title: selectMapTitle(state),
address: selectMapAddress(state),
});
const mapDispatchToProps = {
editorDropGpx: EDITOR_ACTIONS.editorDropGpx,
editorUploadGpx: EDITOR_ACTIONS.editorUploadGpx,
editorSetGpx: EDITOR_ACTIONS.editorSetGpx,
editorGetGPXTrack: EDITOR_ACTIONS.editorGetGPXTrack,
};
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
const GpxDialogUnconnected: FC<Props> = ({
title,
address,
gpx,
route,
editorGetGPXTrack,
editorSetGpx,
editorUploadGpx,
}) => {
const onGpxUpload = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
if (!event.target || !event.target.files || event.target.files.length === 0) {
return;
}
editorUploadGpx(event.target.files[0]);
},
[editorUploadGpx]
);
const onFocusRoute = useCallback(
index => {
if (!gpx.list[index] || !gpx.list[index].latlngs) return;
const bounds = latLngBounds(gpx.list[index].latlngs);
MainMap.fitBounds(bounds);
},
[gpx, MainMap]
);
const onRouteDrop = useCallback(
index => {
editorSetGpx({ list: gpx.list.filter((el, i) => i !== index) });
},
[gpx, editorSetGpx]
);
const toggleGpx = useCallback(() => {
editorSetGpx({ enabled: !gpx.enabled });
}, [gpx, editorSetGpx]);
const onRouteToggle = useCallback(
index => {
if (!gpx.enabled) return;
editorSetGpx({
list: gpx.list.map((el, i) => (i !== index ? el : { ...el, enabled: !el.enabled })),
});
},
[gpx, editorSetGpx]
);
const addCurrent = useCallback(() => {
if (!route.length) return;
const { path } = getUrlData()
editorSetGpx({
list: [
...gpx.list,
{
latlngs: route,
enabled: false,
name: title || address || path,
id: uuid(),
color: getRandomColor(),
},
],
});
}, [route, gpx, editorSetGpx]);
return (
<div className="control-dialog control-dialog__left control-dialog__small">
<div className="gpx-title">
<div className="flex_1 big white upper">Треки</div>
<Switch active={gpx.enabled} onPress={toggleGpx} />
</div>
{gpx.list.map((item, index) => (
<GpxDialogRow
item={item}
key={item.id}
index={index}
enabled={gpx.enabled}
onRouteDrop={onRouteDrop}
onFocusRoute={onFocusRoute}
onRouteToggle={onRouteToggle}
/>
))}
<div className="gpx-buttons">
<button className="button outline">
<input type="file" onChange={onGpxUpload} />
Загрузить GPX
</button>
<div
className={classNames('button outline', { disabled: !route.length })}
onClick={addCurrent}
>
Добавить текущий
</div>
<div
className={classNames('button success', { disabled: !route.length })}
onClick={editorGetGPXTrack}
>
Скачать текущий
</div>
</div>
</div>
);
};
const GpxDialog = connect(mapStateToProps, mapDispatchToProps)(GpxDialogUnconnected);
export { GpxDialog };

View file

@ -0,0 +1,34 @@
import React, { FC } from 'react';
import { IGpxRoute } from '~/redux/editor';
import { Switch } from '../Switch';
import { Icon } from '../panels/Icon';
import classnames from 'classnames';
interface IProps {
item: IGpxRoute;
index: number
enabled: boolean;
onFocusRoute: (i: number) => void
onRouteDrop: (i: number) => void
onRouteToggle: (i: number) => void
}
const GpxDialogRow: FC<IProps> = ({ item, index, enabled, onRouteToggle, onFocusRoute, onRouteDrop }) => {
return (
<div className={classnames("gpx-row", { 'gpx-row_disabled': !enabled || !item.enabled })}>
<div className="gpx-row__color" style={{ backgroundColor: item.color }}/>
<div className="gpx-row__title" onClick={() => onFocusRoute(index)}>
{item.name}
</div>
<div className="gpx-row__buttons">
<div onClick={() => onRouteDrop(index)}><Icon icon="icon-trash-6" size={24} /></div>
<div><Switch active={item.enabled} onPress={() => onRouteToggle(index)}/></div>
</div>
</div>
);
};
export { GpxDialogRow };

View file

@ -8,6 +8,7 @@ import { TrashDialog } from '~/components/dialogs/TrashDialog';
import { LogoDialog } from '~/components/dialogs/LogoDialog';
import { SaveDialog } from '~/components/dialogs/SaveDialog';
import { CancelDialog } from '~/components/dialogs/CancelDialog';
import { GpxDialog } from '~/components/dialogs/GpxDialog';
import { connect } from 'react-redux';
@ -31,6 +32,7 @@ const DIALOG_CONTENTS: { [x: string]: any } = {
[MODES.PROVIDER]: ProviderDialog,
[MODES.SHOT_PREFETCH]: ShotPrefetchDialog,
[MODES.POLY]: PolylineDialog,
[MODES.GPX]: GpxDialog,
};
const EditorDialogUnconnected = (props: Props) =>

View file

@ -11,6 +11,7 @@ import {
editorSetDialogActive,
editorGetGPXTrack,
editorSearchNominatim,
editorChangeMode,
} from '~/redux/editor/actions';
import { connect } from 'react-redux';
import { Icon } from '~/components/panels/Icon';
@ -22,6 +23,7 @@ import { Tooltip } from '~/components/panels/Tooltip';
import { TitleDialog } from '~/components/dialogs/TitleDialog';
import { NominatimSearchPanel } from '~/components/dialogs/NominatimSearchPanel';
import { IState } from '~/redux/store';
import { MODES } from '~/constants/modes';
const mapStateToProps = ({
user: { user },
@ -46,6 +48,7 @@ const mapDispatchToProps = {
openMapDialog,
editorGetGPXTrack,
editorSearchNominatim,
editorChangeMode,
};
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
@ -118,13 +121,17 @@ export class UserPanelUnconnected extends PureComponent<Props, State> {
);
};
openGpxDialog = () => {
this.props.editorChangeMode(MODES.GPX);
}
render() {
const {
props: { user, dialog, dialog_active, route, stickers, features },
state: { menuOpened },
} = this;
const is_empty = !route.length && !stickers.length;
// const is_empty = !route.length && !stickers.length;
return (
<div>
@ -171,8 +178,9 @@ export class UserPanelUnconnected extends PureComponent<Props, State> {
<div className="control-bar">
<button
className={classnames({ inactive: is_empty })}
onClick={this.props.editorGetGPXTrack}
// className={classnames({ inactive: is_empty })}
onClick={this.openGpxDialog}
// onClick={this.props.editorGetGPXTrack}
>
<Tooltip>Экспорт GPX</Tooltip>
<Icon icon="icon-gpx-1" />