Merge pull request 'feat/mobile-draw' (#225) from feat/mobile-draw into release/v8.3.0

This commit is contained in:
Maxim Kadushkin
2025-01-16 16:24:02 +00:00
51 changed files with 799 additions and 473 deletions

View File

@ -1,7 +1,8 @@
import React, { useState, useEffect } from 'react';
import { f7, ListItem, List, Icon } from 'framework7-react';
import React from 'react';
import { ListItem, List } from 'framework7-react';
import { useTranslation } from 'react-i18next';
import { LocalStorage } from '../../utils/LocalStorage.mjs';
import { WheelColorPicker } from "./WheelColorPicker";
const ThemeColors = ({ themeColors, onColorClick, curColor, isTypeColors, isTypeCustomColors }) => {
return (
@ -159,23 +160,6 @@ const CustomColorPicker = props => {
}
const countDynamicColors = props.countdynamiccolors || 10;
const [stateColor, setColor] = useState(`#${currentColor}`);
useEffect(() => {
if (document.getElementsByClassName('color-picker-wheel').length < 1) {
const colorPicker = f7.colorPicker.create({
containerEl: document.getElementsByClassName('color-picker-container')[0],
value: {
hex: `#${currentColor}`
},
on: {
change: function (value) {
setColor(value.getValue().hex);
}
}
});
}
});
const addNewColor = (color) => {
let colors = LocalStorage.getItem('mobile-custom-colors');
@ -186,20 +170,7 @@ const CustomColorPicker = props => {
props.onAddNewColor && props.onAddNewColor(colors, newColor);
};
return (
<div id='color-picker'>
<div className='color-picker-container'></div>
<div className='right-block'>
<div className='color-hsb-preview'>
<div className='new-color-hsb-preview' style={{backgroundColor: stateColor}}></div>
<div className='current-color-hsb-preview' style={{backgroundColor: `#${currentColor}`}}></div>
</div>
<a href='#' id='add-new-color' className='button button-round' onClick={()=>{addNewColor(stateColor)}}>
<Icon icon={'icon-plus'} slot="media" />
</a>
</div>
</div>
)
return <WheelColorPicker initialColor={`#${currentColor}`} onSelectColor={addNewColor}/>
};
export { ThemeColorPalette, CustomColorPicker };

View File

@ -0,0 +1,31 @@
import React, { useEffect, useState } from 'react'
import { f7, Icon } from 'framework7-react';
export const WheelColorPicker = ({ initialColor = '#ffffff', onSelectColor }) => {
const [color, setColor] = useState(initialColor);
useEffect(() => {
if (!document.getElementsByClassName('color-picker-wheel').length) {
f7.colorPicker.create({
containerEl: document.getElementsByClassName('color-picker-container')[0],
value: { hex: initialColor },
on: { change: (value) => setColor(value.getValue().hex) }
});
}
});
return (
<div id='color-picker'>
<div className='color-picker-container'/>
<div className='right-block'>
<div className='color-hsb-preview'>
<div className='new-color-hsb-preview' style={{ backgroundColor: color }}/>
<div className='current-color-hsb-preview' style={{ backgroundColor: initialColor }}/>
</div>
<a href='#' id='add-new-color' className='button button-round' onClick={() => onSelectColor(color)}>
<Icon icon='icon-plus' slot="media"/>
</a>
</div>
</div>
)
}

View File

@ -1,6 +1,5 @@
import React, { Component, Fragment } from 'react';
import { f7 } from 'framework7-react';
import {observer, inject} from "mobx-react";
import { Device } from '../../../../common/mobile/utils/device';
import ContextMenuView, { idContextMenuElement, ActionsWithExtraItems } from '../view/ContextMenu';

View File

@ -0,0 +1,95 @@
import React, { useEffect, useState } from 'react'
import { DrawView } from "../view/Draw";
import { inject, observer } from "mobx-react";
import { Device } from "../../utils/device";
import { LocalStorage } from '../../utils/LocalStorage.mjs';
const DEFAULT_TOOL_SETTINGS = {
pen: { color: '#FF0000', opacity: 100, lineSize: 2 },
highlighter: { color: '#FFFC54', opacity: 50, lineSize: 5 },
}
const DEFAULT_ANDROID_COLORS = ['#FF0000', '#FFC000', '#FFFF00', '#92D050', '#00B050', '#00B0F0', '#0070C0', '#002060', '#C00000']
const DEFAULT_IOS_COLORS = ['#FFFC54', '#72F54A', '#74F9FD', '#EB51F7', '#A900F9', '#FF0303', '#EF8B3A', '#D3D3D4', '#000000']
export const DrawController = inject('storeAppOptions')(observer(({ storeAppOptions }) => {
const [currentTool, setCurrentTool] = useState(null);
const [toolSettings, setToolSettings] = useState(() => {
const stored = LocalStorage.getJson('draw-settings');
return stored || DEFAULT_TOOL_SETTINGS;
});
const [colors, setColors] = useState(() => {
const storageColors = LocalStorage.getJson('draw-colors', []);
if (!storageColors.length) {
return Device.android ? DEFAULT_ANDROID_COLORS : DEFAULT_IOS_COLORS
}
return storageColors
})
useEffect(() => {
Common.Notifications.on('draw:start', () => {
storeAppOptions.changeDrawMode(true);
setCurrentToolAndApply('pen');
})
Common.Notifications.on('draw:stop', () => {
storeAppOptions.changeDrawMode(false);
setCurrentToolAndApply('scroll');
})
return () => {
Common.Notifications.off('draw:start');
Common.Notifications.off('draw:stop');
}
}, []);
const createStroke = (color, lineSize, opacity) => {
const stroke = new Asc.asc_CStroke();
stroke.put_type(Asc.c_oAscStrokeType.STROKE_COLOR);
stroke.put_color(Common.Utils.ThemeColor.getRgbColor(color));
stroke.asc_putPrstDash(Asc.c_oDashType.solid);
stroke.put_width(lineSize);
stroke.put_transparent(opacity * 2.55);
return stroke;
};
const toolActions = {
pen: (api, settings) => api.asc_StartDrawInk(createStroke(settings.pen.color, settings.pen.lineSize, settings.pen.opacity), 0),
highlighter: (api, settings) => api.asc_StartDrawInk(createStroke(settings.highlighter.color, settings.highlighter.lineSize, settings.highlighter.opacity), 1),
eraser: (api) => api.asc_StartInkEraser(),
eraseEntireScreen: (api) => {/* fixme: method */
},
scroll: (api) => api.asc_StopInkDrawer(),
};
const setCurrentToolAndApply = (tool) => {
const api = Common.EditorApi.get();
toolActions[tool]?.(api, toolSettings);
setCurrentTool(tool);
};
const updateToolSettings = (newSettings) => {
setToolSettings(prev => {
const updatedSettings = { ...prev, [currentTool]: { ...prev[currentTool], ...newSettings } };
const api = Common.EditorApi.get();
toolActions[currentTool]?.(api, updatedSettings);
LocalStorage.setJson('draw-settings', updatedSettings)
return updatedSettings;
});
};
const addCustomColor = (color) => {
const updatedColors = [...colors, color]
setColors(updatedColors)
updateToolSettings({ color })
LocalStorage.setJson('draw-colors', updatedColors)
}
return storeAppOptions.isDrawMode ? <DrawView
currentTool={currentTool}
setTool={setCurrentToolAndApply}
settings={toolSettings}
setSettings={updateToolSettings}
colors={colors}
addCustomColor={addCustomColor}
/> : null
}));

View File

@ -0,0 +1,118 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Button, f7, Icon, Range, Sheet } from 'framework7-react';
import SvgIcon from '../../../../common/mobile//lib/component/SvgIcon'
import IconDrawPen from '../../../../common/mobile/resources/icons/draw-pen.svg'
import IconDrawHighlighter from '../../../../common/mobile/resources/icons/draw-highlighter.svg'
import IconClearAll from '../../../../common/mobile/resources/icons/clear-all.svg'
import IconClearObject from '../../../../common/mobile/resources/icons/clear-object.svg'
import IconScroll from '../../../../common/mobile/resources/icons/scroll.svg'
import { WheelColorPicker } from "../component/WheelColorPicker";
import { Device } from "../../utils/device";
export const DrawView = ({ currentTool, setTool, settings, setSettings, colors, addCustomColor }) => {
const { t } = useTranslation();
const _t = t('Draw', { returnObjects: true });
const isDrawingTool = currentTool === 'pen' || currentTool === 'highlighter';
return (
<React.Fragment>
{isDrawingTool && (<>
<Sheet className='draw-sheet draw-sheet--color-picker' backdrop swipeToClose onSheetClosed={() => f7.sheet.open('.draw-sheet--settings')}>
<div className='draw-sheet-label'><span>{_t.textCustomColor}</span></div>
<WheelColorPicker
initialColor={settings[currentTool].color}
onSelectColor={(color) => {
f7.sheet.close('.draw-sheet--color-picker')
addCustomColor(color)
}}
/>
</Sheet>
<Sheet className="draw-sheet draw-sheet--settings" backdrop swipeToClose style={{ height: 'auto' }}>
<div id='swipe-handler' className='swipe-container'>
<Icon icon='icon icon-swipe'/>
</div>
<div className='draw-sheet-label'><span>{_t.textColor}</span></div>
<div className='draw-sheet--settings-colors'>
<div className="draw-sheet--settings-colors-list">
{colors.map((color, index) => (
<div
key={index} className="draw-sheet--settings-colors-list-item" style={{ backgroundColor: color }}
onClick={() => setSettings({ color })}
/>
))}
<div
className="draw-sheet--settings-colors-list-add" style={{ backgroundColor: settings[currentTool].color }}
onClick={() => {
f7.sheet.close('.draw-sheet--settings')
f7.sheet.open('.draw-sheet--color-picker')
}}
>
<Icon icon="icon-plus" style={{ backgroundColor: 'var(--brand-word)' }}/>
</div>
</div>
</div>
<div className='draw-sheet-label'><span>{_t.textLineSize}</span></div>
<div className='draw-sheet-item'>
{/*{Device.android ? (*/}
<Range
min={0.5} max={10} step={0.5} value={settings[currentTool].lineSize}
onRangeChange={(value) => setSettings({ lineSize: value })}
/>
{/*) : (*/}
{/* <input className='line-size-range--ios' type='range' min={0.5} max={10} step={0.5} value={settings[currentTool].lineSize} onChange={(e) => setSettings({ lineSize: parseInt(e.target.value) })} />*/}
{/* )}*/}
</div>
<div className='draw-sheet-label'><span>{_t.textOpacity}</span></div>
<div className='draw-sheet-item'>
<input style={{ '--color': settings[currentTool].color }}
className={Device.android ? 'opacity-range-input--android' : 'opacity-range-input--ios'} type='range' min={0} max={100} step={1}
value={settings[currentTool].opacity}
onChange={(e) => setSettings({ opacity: parseInt(e.target.value) })}/>
</div>
</Sheet>
</>)}
<div className="draw-toolbar">
<div className="draw-toolbar-item">
<Button type='button' fill={currentTool === 'pen'} onClick={() => setTool('pen')}>
<SvgIcon symbolId={IconDrawPen.id} className='icon icon-svg'/>
</Button>
</div>
<div className="draw-toolbar-item">
<Button type='button' fill={currentTool === 'highlighter'} onClick={() => setTool('highlighter')}>
<SvgIcon symbolId={IconDrawHighlighter.id} className='icon icon-svg'/>
</Button>
</div>
<div className="draw-toolbar-item">
<Button type='button' sheetOpen={isDrawingTool ? ".draw-sheet--settings" : undefined} disabled={!isDrawingTool}>
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<circle cx="50%" cy="50%" r="8" fill={settings[currentTool]?.color || '#808080'}/>
</svg>
</Button>
</div>
<div className="draw-toolbar-item">
<div className='draw-toolbar-divider'/>
</div>
<div className="draw-toolbar-item">
<Button type='button' disabled={false} fill={currentTool === 'eraser'} onClick={() => setTool('eraser')}>
<SvgIcon symbolId={IconClearObject.id} className='icon icon-svg'/>
</Button>
</div>
<div className="draw-toolbar-item">
<Button type='button' disabled={false} onClick={() => setTool('eraseEntireScreen')}>
<SvgIcon symbolId={IconClearAll.id} className='icon icon-svg'/>
</Button>
</div>
<div className="draw-toolbar-item">
<div className='draw-toolbar-divider'/>
</div>
<div className="draw-toolbar-item">
<Button type='button' fill={currentTool === 'scroll'} onClick={() => setTool('scroll')} tabIndex='-1'>
<SvgIcon symbolId={IconScroll.id} className='icon icon-svg'/>
</Button>
</div>
</div>
</React.Fragment>
)
}

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 2H20V4.45714L21 5.42857V2V1H20H4H3V2V22V23H4H20H21V22V15.1429L20 16.1143V22H4V2Z" fill="currentColor"/>
<path d="M18 19H14.4286M14.4286 19L19.1429 14.2857M14.4286 19H13.0036H8.375L6.39203 16.9856C5.62147 16.2028 5.62642 14.945 6.40312 14.1683L12.7143 7.85714M19.1429 14.2857L21.5858 11.8428C22.3668 11.0617 22.3668 9.79541 21.5858 9.01436L17.9856 5.41421C17.2046 4.63316 15.9383 4.63317 15.1572 5.41421L12.7143 7.85714M19.1429 14.2857L12.7143 7.85714" stroke="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 631 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.1429 22H12.5714M12.5714 22H5.14286L1.58533 18.8378C0.725257 18.0732 0.686148 16.7424 1.49985 15.9287L10.2857 7.14286M12.5714 22L18.8571 15.7143M18.8571 15.7143L22.5858 11.9856C23.3668 11.2046 23.3668 9.93826 22.5858 9.15722L16.8428 3.41421C16.0617 2.63316 14.7954 2.63316 14.0144 3.41421L10.2857 7.14286M18.8571 15.7143L10.2857 7.14286" stroke="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 477 B

View File

@ -0,0 +1,7 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 14H6V21.5V21.75C6 22 6 22 6.25 22H6.5H7H6.75C7 22 7 22 7 21.75V14Z" fill="currentColor"/>
<path d="M18 14H17V21.5V21.75C17 22 17 22 17.25 22H17.5H17.75C18 22 18 22 18 21.75V14Z" fill="currentColor"/>
<path d="M15 7.99998H9H8.75C8.5 7.99998 8.4674 8.10429 8.4348 8.20861L7 13H8L9.2 8.99998H14.75L16 13H17L15.755 8.99998L15.5703 8.20861C15.5469 8.13358 15.45 7.99998 15.25 7.99998H15Z" fill="currentColor"/>
<path d="M7.19 13H16.745H17.245L17.6 12.9995C17.855 12.9995 18 13.1495 18 13.3995V14H16.995H6.94H6V13.3995C6 13.1495 6.15 13 6.4 13H6.69H7.19Z" fill="currentColor"/>
<path d="M9 7.99998H15V2.39189C14.9975 2.21731 14.9628 2.10444 14.9 2.0466C14.8238 1.97646 14.7062 1.98727 14.5544 2.06713L9.64754 4.85429C9.64168 4.85802 9.63591 4.86187 9.63023 4.86584C9.57927 4.90147 9.53532 4.94691 9.5 4.99947C9.45228 5.07048 9.42033 5.15451 9.40822 5.24492L9 7.99998Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1000 B

View File

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.82 5.80825H9.18H8.75C8.5 5.80825 8.4674 5.91382 8.4348 6.01938L6 13.9041H7H17H18L15.8171 6.82024L15.5703 6.01938C15.5469 5.94345 15.45 5.80825 15.25 5.80825H14.82ZM9.18 6.82024L7.5 12.8921H16.5L14.82 6.82024H9.18Z" fill="currentColor"/>
<path d="M7 13.9041H6V21.494V21.747C6 22 6 22 6.25 22H6.5H7H6.75C7 22 7 22 7 21.747V13.9041Z" fill="currentColor"/>
<path d="M18 13.9041H17V21.494V21.747C17 22 17 22 17.25 22H17.5H17.75C18 22 18 22 18 21.747V13.9041Z" fill="currentColor"/>
<path d="M9.18 5.80825H14.82L13.5 3.32813C12.5 1.56585 11.5 1.54875 10.5 3.32813L9.18 5.80825Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 751 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.737 5.62105L22.0002 4.35789C22.0002 4.35789 21.8318 3.34737 21.2423 2.75789C20.6528 2.08421 19.6423 2 19.6423 2L18.3791 3.26316L20.737 5.62105ZM19.7263 5.62108L8.61053 16.6527L7.34737 15.3895L18.4632 4.35792L17.8737 3.76845L6.42105 15.2211L6 18L8.77895 17.579L14.5053 11.8527L20.2316 6.12634L19.7263 5.62108ZM13.4801 7.10498C13.7534 6.68633 13.7532 6.68617 13.7529 6.686L13.7523 6.68561L13.7508 6.68462L13.7466 6.68189L13.7332 6.67345C13.7222 6.66654 13.707 6.6571 13.6876 6.64542C13.6488 6.62206 13.5934 6.58971 13.5223 6.55067C13.3801 6.47261 13.1745 6.36757 12.9125 6.25401C12.3888 6.02712 11.636 5.76465 10.7096 5.61688C8.84758 5.3199 6.30186 5.49026 3.53986 7.30505C0.618665 9.22443 0.000158966 12.2988 0.854419 15.2145C1.7018 18.1067 3.99969 20.8956 6.99949 22.4443L7.45822 21.5557C4.6876 20.1254 2.5803 17.5485 1.81408 14.9333C1.05473 12.3416 1.61422 9.76684 4.08899 8.14078C6.61649 6.48008 8.9036 6.34147 10.5521 6.6044C11.3808 6.73658 12.0526 6.97128 12.5148 7.17157C12.7457 7.2716 12.9234 7.36266 13.0411 7.4273C13.1 7.4596 13.1438 7.48526 13.1717 7.50206C13.1856 7.51046 13.1956 7.51664 13.2015 7.52033L13.2071 7.52389C13.2069 7.52377 13.2067 7.52363 13.4801 7.10498ZM19.1353 20.4311C20.7445 18.6887 20.7121 16.4688 20.147 14.5823C19.5829 12.6991 18.4598 11.0314 17.6862 10.2326L16.9678 10.9283C17.6368 11.619 18.6736 13.1485 19.189 14.8693C19.7035 16.5868 19.6702 18.3779 18.4006 19.7527C17.0172 21.2507 14.7032 21.3649 12.5461 20.8504C11.4861 20.5975 10.5138 20.2025 9.79385 19.7968C9.43322 19.5936 9.14757 19.3943 8.94872 19.2175C8.84948 19.1293 8.77888 19.0529 8.73234 18.9909C8.68391 18.9264 8.67427 18.8944 8.67428 18.8944L7.70686 19.1476C7.78962 19.4639 8.03374 19.7421 8.28433 19.9649C8.55196 20.2028 8.90143 20.4418 9.30292 20.668C10.1072 21.1213 11.1671 21.5495 12.3141 21.8231C14.5712 22.3615 17.3707 22.3418 19.1353 20.4311Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.3131 22.5C10.2175 22.5087 8.01189 20.812 6.84764 17.5345L5.15461 12.7863C5.04986 12.5004 5.00123 12.1658 5.00026 11.9178C4.98411 10.9611 5.71509 10.406 6.54563 10.4022C7.14956 10.4048 7.6768 10.7657 7.97915 11.4901L8.7828 13.4574C8.8051 13.5051 8.82797 13.5234 8.86564 13.5272C8.91504 13.5255 8.93599 13.4935 8.93407 13.4433L8.87828 5.30155C8.87059 4.20929 9.5785 3.49716 10.5628 3.50001C11.5298 3.49655 12.2595 4.19874 12.2672 5.291L12.2914 8.50878C12.5222 8.4346 12.7729 8.38746 12.9964 8.38985C13.7776 8.38785 14.3525 8.83546 14.5653 9.53711C14.843 9.44044 15.114 9.39084 15.39 9.38267C16.1422 9.37998 16.6886 9.79739 16.8878 10.4544C18.531 10.4701 19.4744 11.6762 19.4848 13.8193L19.4998 15.7263C19.5286 20.0452 16.978 22.4813 13.3131 22.5ZM13.3413 21.5001C16.5067 21.4871 18.5706 19.4379 18.5375 15.6325L18.5327 13.9471C18.5206 12.3382 17.992 11.4519 17.054 11.456L17.055 12.5954C17.0635 12.9055 16.8451 13.0833 16.6012 13.0833C16.3542 13.0922 16.1341 12.9128 16.1287 12.5939L16.1232 11.2449C16.1112 10.6661 15.8014 10.3252 15.2845 10.3247C15.0783 10.3286 14.8449 10.382 14.6518 10.4601L14.6691 12.2491C14.6689 12.5561 14.4505 12.7339 14.2153 12.7371C13.9596 12.7428 13.7395 12.5634 13.7428 12.2477L13.7209 10.2489C13.7176 9.6733 13.4108 9.32359 12.8823 9.32867C12.6877 9.32697 12.4513 9.38921 12.2582 9.46724L12.2745 11.8997C12.278 12.1684 12.0936 12.3883 11.8207 12.3877C11.5564 12.3902 11.3486 12.1757 11.3452 11.907L11.3013 5.23546C11.2932 4.75712 11.0149 4.4376 10.5765 4.43598C10.135 4.44315 9.8353 4.76951 9.83472 5.2447L9.90648 14.6501C9.91321 15.0487 9.65545 15.3111 9.30409 15.3116C9.01078 15.3135 8.75494 15.1804 8.58272 14.7808L7.3437 11.9118C7.19128 11.5392 6.96312 11.3272 6.64078 11.3283C6.2283 11.3362 5.94652 11.6393 5.95382 12.0085C5.95037 12.1855 5.98266 12.3161 6.03782 12.465L7.73085 17.2132C8.79341 20.196 10.7626 21.5093 13.3413 21.5001Z" fill="currentColor"/>
<path d="M4.64523 7.22755C4.49571 7.08397 4.25857 7.08587 4.11189 7.23231C3.96521 7.37874 3.96236 7.61551 4.10617 7.7648L5.23002 8.8878C5.30145 8.96006 5.39764 9 5.49861 9C5.59956 9 5.69671 8.96006 5.76815 8.88875L6.89295 7.7667C7.03676 7.61836 7.03485 7.3816 6.88818 7.23516C6.74151 7.08777 6.50437 7.08587 6.35484 7.22945L5.88054 7.70204V3.29677L6.35484 3.76936C6.50436 3.91199 6.7415 3.91104 6.88818 3.76365C7.03485 3.61722 7.03676 3.38045 6.89295 3.23211C5.19098 1.59468 5.81006 1.58329 4.10514 3.23401C3.96133 3.3833 3.96514 3.62006 4.11181 3.7665C4.25848 3.91294 4.49563 3.91484 4.64516 3.77126L5.11946 3.29772V7.70202L4.64523 7.22755Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -31,6 +31,9 @@
--toolbar-segment: #FFF;
--toolbar-tab-normal: #757575;
--draw-toolbar-background: #232323;
--draw-toolbar-border: #54545866;
--component-disabled-opacity: .4;
--image-border-types-filter: invert(100%) brightness(4);

View File

@ -29,11 +29,14 @@
--toolbar-segment: #446995;
--toolbar-tab-normal:fade(#FFF, 50%);
--draw-toolbar-background: #fff;
--draw-toolbar-border: #E6E6E6;
--component-disabled-opacity: .4;
--active-opacity-word: fade(#446995, 30%);
--active-opacity-slide: fade(#BE664F, 30%);
--active-opacity-cell: fade(#40865C, 30%);
--active-opacity-word: #E5F0FF;
--active-opacity-slide: #FBE4DE;
--active-opacity-cell: #D9EFE2;
--image-border-types-filter: none;
@ -109,4 +112,8 @@
@toolbar-segment: var(--toolbar-segment);
@toolbar-tab-normal: var(--toolbar-tab-normal);
@draw-toolbar-background: var(--draw-toolbar-background);
@draw-toolbar-divider: var(--draw-toolbar-divider);
@draw-toolbar-border: var(--draw-toolbar-border);
@component-disabled-opacity: var(--component-disabled-opacity);

View File

@ -70,7 +70,7 @@
.subnavbar {
.subnavbar-inner {
padding: 0;
.title {
white-space: nowrap;
overflow: hidden;
@ -202,13 +202,13 @@
html.pixel-ratio-3 & {
border: 0.33px solid @gray;
}
.thumb {
width: 100%;
height: 100%;
background-color: @fill-white;
background-size: cover;
label {
width: 100%;
text-align: center;
@ -225,7 +225,7 @@
}
}
}
.row.list .item-content {
padding-left: 0;
padding-right: 0;
@ -424,7 +424,7 @@
.style-effect, .style-type {
.list .item-title {
font-weight: normal;
font-weight: normal;
}
}
@ -451,7 +451,7 @@
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, .3);
}
&::-ms-thumb {
&::-ms-thumb {
appearance: none;
height: 28px;
width: 28px;
@ -533,7 +533,7 @@
background-size: 100% 100%;
.encoded-svg-background("<svg xmlns='http://www.w3.org/2000/svg' x='0px' y='0px' viewBox='0 0 22 22' xml:space='preserve'><line stroke='#ff0000' stroke-linecap='undefined' stroke-linejoin='undefined' id='svg_1' y2='0' x2='22' y1='22' x1='0' stroke-width='2' fill='none'/></svg>");
}
}
}
}
}
}
@ -878,7 +878,7 @@ input[type="number"]::-webkit-inner-spin-button {
.content-block {
padding: 0;
}
.picker-3d {
.picker-3d {
.picker-item {
padding: 0;
text-align: left;
@ -1064,11 +1064,11 @@ input[type="number"]::-webkit-inner-spin-button {
}
.target-function-list {
position: absolute;
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 0;
width: 0;
height: 100%;
}
@ -1168,7 +1168,7 @@ input[type="number"]::-webkit-inner-spin-button {
}
}
.list input[type='password'],
.list input[type='password'],
.list input[type='text'] {
background: transparent;
}
@ -1193,7 +1193,7 @@ input[type="number"]::-webkit-inner-spin-button {
}
// Version History
.version-history {
.version-history {
&__user {
width: 40px;
height: 40px;

View File

@ -0,0 +1,200 @@
.draw-sheet {
background-color: @background-primary;
.device-android & {
box-shadow: 0 3.75px 11px 0 #00000030, 0 0.5px 5px 0 #0000000A;
--f7-sheet-border-radius: 16px;
}
.device-ios & {
box-shadow: 0 8px 28px 0 #00000029;
--f7-sheet-border-radius: 10px;
}
.swipe-container {
height: 20px;
}
&-label {
padding-inline: 16px;
height: 48px;
display: flex;
color: @text-normal;
.device-android & {
font-size: 16px;
align-items: center;
}
.device-ios & {
align-items: flex-end;
text-transform: uppercase;
font-size: 13px;
line-height: 18px;
span {
padding-bottom: 4px;
}
}
}
&-item {
padding-inline: 16px;
height: 48px;
display: flex;
align-items: center;
}
}
.draw-sheet--settings {
&-colors {
padding: 8px 16px;
&-list {
width: 100%;
display: grid;
grid-template-columns: repeat(10, 1fr);
gap: 2px;
&-item {
border: 1px solid;
aspect-ratio: 1;
border-color: @background-menu-divider;
}
&-add {
position: relative;
display: flex;
align-items: center;
justify-content: center;
aspect-ratio: 1;
border: 2px solid @background-primary;
i {
background-color: @brandColor;
}
&:after {
content: '';
position: absolute;
inset: -5px;
background: linear-gradient(to right, #FF0000, #FF8A00, #FAFF01, #00FF1A, #00F0FF, #0029FF, #DB00FF);
z-index: -1;
border-radius: 4px;
}
}
}
}
}
#drawbar.navbar {
--height: calc(44px + var(--f7-safe-area-bottom));
height: var(--height);
--f7-navbar-border-color: @draw-toolbar-border;
--f7-navbar-bg-color: @draw-toolbar-background;
.device-android & {
body.theme-type-light & {
--f7-navbar-bg-color: #fff;
}
top: unset;
bottom: env(keyboard-inset-top);
}
.device-ios & {
top: 100vh;
margin-top: calc(-1 * (var(--height) + env(keyboard-inset-top, 0px)));
}
.draw-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
padding-inline: 10px;
width: 100%;
@media (min-width: 550px) {
display: grid;
grid-template-columns: repeat(8, 1fr);
}
&-item {
@media (min-width: 550px) {
display: flex;
align-items: center;
justify-content: center;
}
button {
display: flex;
padding: 0;
width: 36px;
height: 36px;
min-width: 36px;
border-radius: 7px;
border: none;
&.button-fill {
color: @brandColor;
background-color: @button-active-opacity;
}
}
}
&-divider {
width: 1px;
height: 24px;
background-color: @background-menu-divider;
}
}
}
.line-size-range--ios {
appearance: none;
width: 100%;
height: 24px;
background: url(data:image/svg+xml;base64,PHN2ZyBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJub25lIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDM0MyAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAgMTJDMCAxMC44ODYxIDAuODg1NzUgOS45NzQxOCAxLjk5OTE1IDkuOTQxNzJMMzMxLjAwNSAwLjM0OTcwNkMzMzcuNTcyIDAuMTU4MjQgMzQzIDUuNDI5OTIgMzQzIDEyQzM0MyAxOC41NzAxIDMzNy41NzIgMjMuODQxOCAzMzEuMDA1IDIzLjY1MDNMMS45OTkxNSAxNC4wNTgzQzAuODg1NzU0IDE0LjAyNTggMCAxMy4xMTM5IDAgMTJaIiBmaWxsPSIjQUVBRUIyIi8+Cjwvc3ZnPgo=);
background-size: 100% 24px;
background-repeat: no-repeat;
}
.opacity-range-input--ios {
appearance: none;
width: 100%;
height: 24px;
border-radius: 30px;
background: linear-gradient(90deg, transparent, var(--color)),
linear-gradient(#9797971A, #9797971A),
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAEsWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS41LjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyIKICAgIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgdGlmZjpJbWFnZUxlbmd0aD0iNjQiCiAgIHRpZmY6SW1hZ2VXaWR0aD0iNjQiCiAgIHRpZmY6UmVzb2x1dGlvblVuaXQ9IjIiCiAgIHRpZmY6WFJlc29sdXRpb249IjcyLzEiCiAgIHRpZmY6WVJlc29sdXRpb249IjcyLzEiCiAgIGV4aWY6UGl4ZWxYRGltZW5zaW9uPSI2NCIKICAgZXhpZjpQaXhlbFlEaW1lbnNpb249IjY0IgogICBleGlmOkNvbG9yU3BhY2U9IjEiCiAgIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiCiAgIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIKICAgeG1wOk1vZGlmeURhdGU9IjIwMjUtMDEtMTVUMDM6NTY6MjIrMDU6MDAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMjUtMDEtMTVUMDM6NTY6MjIrMDU6MDAiPgogICA8eG1wTU06SGlzdG9yeT4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJwcm9kdWNlZCIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWZmaW5pdHkgUGhvdG8gMiAyLjUuNSIKICAgICAgc3RFdnQ6d2hlbj0iMjAyNS0wMS0xNVQwMzo1NjoyMiswNTowMCIvPgogICAgPC9yZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+sHvpjAAAAYFpQ0NQc1JHQiBJRUM2MTk2Ni0yLjEAACiRdZG5S0NBEIe/REXxiqCIhUWQaBUlHkRtLBK8QC2SCF5N8nIJOR7vJYjYCrYBBdHGq9C/QFvBWhAURRBrbRVtNDznJYGImFl29tvfzgy7s2ANJJSkXu2CZCqj+SY99oXFJXvtKxaaaWeI4aCiq7P+iQAV7fNeosVue81aleP+tYZwRFfAUic8pqhaRnhKeGYto5q8I9ymxINh4TNhpyYXFL4z9VCRX0yOFfnbZC3g84K1Rdge+8WhX6zEtaSwvBxHMpFVSvcxX9IYSc37Ze2S2YmOj0k82JlmHC9u+hkV76aXAfpkR4V8VyF/jrTkKuJV1tFYJUacDE5Rs1I9ImtU9IiMBOtm///2VY8ODhSrN3qg5tkw3ruhdhvyOcP4OjKM/DFUPcFlqpyfPoSRD9FzZc1xALZNOL8qa6FduNiCjkc1qAULUpVMazQKb6fQtAitN1C/XOxZ6ZyTBwhsyFddw94+9Ei8beUH1zhoGb7OAhMAAAAJcEhZcwAACxMAAAsTAQCanBgAAAC4SURBVHic7drBCcUwDMDQ5NNZu/8G+UP48Ggr3Y2FyCXgvda614BzzmR87b1H89P9v9H0CyiAFtAUQAtoCqAFNAXQApoCaAFNAbSApgBaQHM9/T8/3f/5F1AALaApgBbQFEALaAqgBTQF0AKaAmgBTQG0gOZ6+n+++4AhBdACmgJoAU0BtICmAFpAUwAtoCmAFtAUQAtoug8YTb+AAmgBTQG0gKYAWkBTAC2gKYAW0BRAC2gKoAU0f7KKGOlRUMddAAAAAElFTkSuQmCC);
background-size: 100%, 100%, 32px;
}
.opacity-range-input--ios::-webkit-slider-thumb, .line-size-range--ios::-webkit-slider-thumb {
appearance: none;
width: 28px;
height: 28px;
border: 0.5px solid rgba(116, 116, 128, 0.08);
border-radius: 50%;
background: #fff;
box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.03),
0 1px 1px 0 rgba(0, 0, 0, 0.01),
0 3px 8px 0 rgba(0, 0, 0, 0.1);
}
.opacity-range-input--android {
appearance: none;
width: 100%;
height: 16px;
border-radius: 8px;
box-shadow: 0 0 0 0.5px #0000001F;
background: linear-gradient(90deg, #C4C4C4, var(--color));
}
.opacity-range-input--android::-webkit-slider-thumb {
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #fff;
box-shadow: 0 1px 3px 0 #00000033, 0 2px 2px 0 #0000001F, 0 0 2px 0 #00000024;
}

View File

@ -65,7 +65,7 @@
&.icon-close {
width: 24px;
height: 24px;
.encoded-svg-mask('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M18.9844 6.42188L13.4062 12L18.9844 17.5781L17.5781 18.9844L12 13.4062L6.42188 18.9844L5.01562 17.5781L10.5938 12L5.01562 6.42188L6.42188 5.01562L12 10.5938L17.5781 5.01562L18.9844 6.42188Z"/></svg>', @text-normal);
.encoded-svg-mask('<svg xmlns="http://www.w3.org/2000/svg" fill="@{toolbar-icons}" width="24" height="24" viewBox="0 0 24 24"><path d="M18.9844 6.42188L13.4062 12L18.9844 17.5781L17.5781 18.9844L12 13.4062L6.42188 18.9844L5.01562 17.5781L10.5938 12L5.01562 6.42188L6.42188 5.01562L12 10.5938L17.5781 5.01562L18.9844 6.42188Z"/></svg>', @toolbar-icons);
}
&.icon-done-disabled {
width: 24px;

View File

@ -78,6 +78,19 @@ class LocalStorage {
else return this._store[name]===undefined ? null : this._store[name];
};
setJson(name, value, just) {
this.setItem(name, JSON.stringify(value), just);
}
getJson(name, fallbackValue = null) {
try {
const stored = this.getItem(name);
return stored ? JSON.parse(stored) : fallbackValue;
} catch {
return fallbackValue;
}
}
setBool(name, value, just) {
this.setItem(name, value ? 1 : 0, just);
}

View File

@ -30,6 +30,7 @@
"textEmptyImgUrl": "You need to specify image URL.",
"textEvenPage": "Even Page",
"textFootnote": "Footnote",
"textDrawing": "Drawing",
"textFormat": "Format",
"textImage": "Image",
"textImageURL": "Image URL",
@ -814,5 +815,11 @@
"textSwitchedMobileView": "Switched to Mobile view",
"textSwitchedStandardView": "Switched to Standard view",
"warnEmptyRequiredField": "Fill all required fields to send form."
},
"Draw": {
"textOpacity": "Opacity",
"textLineSize": "Line size",
"textColor": "Color",
"textCustomColor": "Custom color"
}
}

View File

@ -10,19 +10,13 @@ const ToolbarController = inject('storeAppOptions', 'users', 'storeReview', 'sto
const {t} = useTranslation();
const _t = t("Toolbar", { returnObjects: true });
const appOptions = props.storeAppOptions;
const isEdit = appOptions.isEdit;
const isForm = appOptions.isForm;
const canFillForms = appOptions.canFillForms;
const canSubmitForms = appOptions.canSubmitForms;
const storeVersionHistory = props.storeVersionHistory;
const isVersionHistoryMode = storeVersionHistory.isVersionHistoryMode;
const isViewer = appOptions.isViewer;
const isMobileView = appOptions.isMobileView;
const isDisconnected = props.users.isDisconnected;
const displayMode = props.storeReview.displayMode;
const stateDisplayMode = displayMode == "final" || displayMode == "original" ? true : false;
const displayCollaboration = props.users.hasEditUsers || appOptions.canViewComments || appOptions.canReview || appOptions.canViewReview;
const readerMode = appOptions.readerMode;
const objectLocked = props.storeFocusObjects.objectLocked;
const storeToolbarSettings = props.storeToolbarSettings;
const isCanUndo = storeToolbarSettings.isCanUndo;
@ -30,7 +24,7 @@ const ToolbarController = inject('storeAppOptions', 'users', 'storeReview', 'sto
const disabledControls = storeToolbarSettings.disabledControls;
const disabledEditControls = storeToolbarSettings.disabledEditControls;
const disabledSettings = storeToolbarSettings.disabledSettings;
const showEditDocument = !isEdit && appOptions.canEdit && appOptions.canRequestEditRights;
const showEditDocument = !appOptions.isEdit && appOptions.canEdit && appOptions.canRequestEditRights;
const storeDocumentInfo = props.storeDocumentInfo;
const docExt = storeDocumentInfo.dataDoc ? storeDocumentInfo.dataDoc.fileType : '';
const docTitle = storeDocumentInfo.dataDoc ? storeDocumentInfo.dataDoc.title : '';
@ -215,13 +209,12 @@ const ToolbarController = inject('storeAppOptions', 'users', 'storeReview', 'sto
appOptions.changeViewerMode(true);
api.asc_addRestriction(Asc.c_oAscRestrictionType.View);
Common.Notifications.trigger('draw:stop');
}
const changeMobileView = () => {
const api = Common.EditorApi.get();
const isMobileView = appOptions.isMobileView;
LocalStorage.setBool('mobile-view', !isMobileView);
LocalStorage.setBool('mobile-view', !appOptions.isMobileView);
appOptions.changeMobileView();
api.ChangeReaderMode();
}
@ -355,8 +348,8 @@ const ToolbarController = inject('storeAppOptions', 'users', 'storeReview', 'sto
}
const saveForm = () => {
const isSubmitForm = canFillForms && canSubmitForms;
const isSavePdf = appOptions.canDownload && canFillForms && !canSubmitForms;
const isSubmitForm = appOptions.canFillForms && appOptions.canSubmitForms;
const isSavePdf = appOptions.canDownload && appOptions.canFillForms && !appOptions.canSubmitForms;
if(isSubmitForm) submitForm();
if(isSavePdf) saveAsPdf();
@ -411,13 +404,14 @@ const ToolbarController = inject('storeAppOptions', 'users', 'storeReview', 'sto
disabledEditControls={disabledEditControls}
disabledSettings={disabledSettings}
displayCollaboration={displayCollaboration}
readerMode={readerMode}
readerMode={appOptions.readerMode}
showEditDocument={showEditDocument}
onEditDocument={onEditDocument}
isDisconnected={isDisconnected}
isViewer={isViewer}
isDrawMode={appOptions.isDrawMode}
turnOnViewerMode={turnOnViewerMode}
isMobileView={isMobileView}
isMobileView={appOptions.isMobileView}
isMobileViewAvailable={appOptions.isMobileViewAvailable}
changeMobileView={changeMobileView}
changeTitleHandler={changeTitleHandler}
@ -427,8 +421,8 @@ const ToolbarController = inject('storeAppOptions', 'users', 'storeReview', 'sto
moveNextField={moveNextField}
movePrevField={movePrevField}
saveForm={saveForm}
isForm={isForm}
canFillForms={canFillForms}
isForm={appOptions.isForm}
canFillForms={appOptions.canFillForms}
canSubmitForms={appOptions.canSubmitForms}
/>
)

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: blob:">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover, interactive-widget=resizes-content">
<meta name="theme-color" content="#007aff">
<meta name="format-detection" content="telephone=no">

View File

@ -36,6 +36,7 @@
@import '../../../../common/mobile/resources/less/search.less';
@import '../../../../common/mobile/resources/less/contextmenu.less';
@import '../../../../common/mobile/resources/less/comments.less';
@import '../../../../common/mobile/resources/less/draw.less';
@import './app-material.less';
@import './app-ios.less';
@import './icons-ios.less';

View File

@ -1,6 +1,7 @@
.icon-svg {
fill: @brand-word;
color: @brand-word;
}
// Formats

View File

@ -17,6 +17,7 @@ import Snackbar from '../components/Snackbar/Snackbar';
import { Themes } from '../../../../common/mobile/lib/controller/Themes';
import EditView from '../view/edit/Edit';
import VersionHistoryController from '../../../../common/mobile/lib/controller/VersionHistory';
import {DrawController} from "../../../../common/mobile/lib/controller/Draw";
export const MainContext = createContext();
@ -45,15 +46,9 @@ const MainPage = inject('storeDocumentInfo', 'users', 'storeAppOptions', 'storeV
const docExt = dataDoc?.fileType || '';
const isAvailableExt = docExt && docExt !== 'djvu' && docExt !== 'pdf' && docExt !== 'xps';
const storeToolbarSettings = props.storeToolbarSettings;
const isDisconnected = props.users.isDisconnected;
const isViewer = appOptions.isViewer;
const isEdit = appOptions.isEdit;
const isMobileView = appOptions.isMobileView;
const disabledControls = storeToolbarSettings.disabledControls;
const disabledSettings = storeToolbarSettings.disabledSettings;
const isProtected = appOptions.isProtected;
const typeProtection = appOptions.typeProtection;
const isFabShow = isViewer && !disabledSettings && !disabledControls && !isDisconnected && isAvailableExt && isEdit && (!isProtected || typeProtection === Asc.c_oAscEDocProtect.TrackedChanges);
const isFabShow = appOptions.isViewer && !storeToolbarSettings.disabledSettings && !storeToolbarSettings.disabledControls &&
!props.users.isDisconnected && isAvailableExt && appOptions.isEdit &&
(!appOptions.isProtected || appOptions.typeProtection === Asc.c_oAscEDocProtect.TrackedChanges);
const config = appOptions.config;
const { customization = {} } = config;
const isShowPlaceholder = !appOptions.isDocReady && (!customization || !(customization.loaderName || customization.loaderLogo));
@ -261,7 +256,7 @@ const MainPage = inject('storeDocumentInfo', 'users', 'storeAppOptions', 'storeV
closeOptions: handleOptionsViewClosed,
showPanels: state.addShowOptions,
isBranding,
isViewer,
isViewer: appOptions.isViewer,
}}>
<Page name="home" className={`editor${!isHideLogo ? ' page-with-logo' : ''}`}>
<Navbar id='editor-navbar' className={`main-navbar${!isHideLogo ? ' navbar-with-logo' : ''}`}>
@ -288,6 +283,9 @@ const MainPage = inject('storeDocumentInfo', 'users', 'storeAppOptions', 'storeV
}
</Navbar>
<View id="editor_sdk"></View>
<Navbar id='drawbar' style={{ display: !appOptions.isDrawMode && 'none' }}>
<DrawController />
</Navbar>
{isShowPlaceholder ?
<div className="doc-placeholder-container">
<div className="doc-placeholder">
@ -317,7 +315,7 @@ const MainPage = inject('storeDocumentInfo', 'users', 'storeAppOptions', 'storeV
<Snackbar
isShowSnackbar={state.snackbarVisible}
closeCallback={() => handleOptionsViewClosed('snackbar')}
message={isMobileView ? t("Toolbar.textSwitchedMobileView") : t("Toolbar.textSwitchedStandardView")}
message={appOptions.isMobileView ? t("Toolbar.textSwitchedMobileView") : t("Toolbar.textSwitchedStandardView")}
/>
<SearchSettings useSuspense={false} />
{!state.editOptionsVisible ? null : <EditView />}

View File

@ -28,6 +28,9 @@ export class storeAppOptions {
isViewer: observable,
changeViewerMode: action,
isDrawMode: observable,
changeDrawMode: action,
isMobileView: observable,
changeMobileView: action,
@ -76,6 +79,11 @@ export class storeAppOptions {
this.isViewer = value;
}
isDrawMode = false;
changeDrawMode(value) {
this.isDrawMode = value;
}
canViewComments = false;
changeCanViewComments(value) {
this.canViewComments = value;

View File

@ -12,13 +12,13 @@ import {storeDocumentInfo} from "./documentInfo";
import {storeLinkSettings} from './linkSettings';
import {storeApplicationSettings} from './applicationSettings';
import {storeAppOptions} from "./appOptions";
import {storePalette} from "./palette";
import {storeReview} from '../../../../common/mobile/lib/store/review';
import {storeComments} from "../../../../common/mobile/lib/store/comments";
import {storeToolbarSettings} from "./toolbar";
import { storeNavigation } from './navigation';
import { storeThemes } from '../../../../common/mobile/lib/store/themes';
import { storeVersionHistory } from '../../../../common/mobile/lib/store/versionHistory';
import { storePalette } from "./palette";
export const stores = {
storeAppOptions: new storeAppOptions(),

View File

@ -1,4 +1,4 @@
import {action, observable, makeObservable} from 'mobx';
import {action, makeObservable, observable} from 'mobx';
export class storePalette {
constructor() {

View File

@ -10,9 +10,7 @@ const ToolbarView = props => {
const isDisconnected = props.isDisconnected;
const docExt = props.docExt;
const isAvailableExt = docExt && docExt !== 'djvu' && docExt !== 'pdf' && docExt !== 'xps';
const isForm = props.isForm;
const canFillForms = props.canFillForms;
const isEditableForms = isForm && canFillForms;
const isEditableForms = props.isForm && props.canFillForms;
const disableEditBtn = props.isObjectLocked || props.stateDisplayMode || props.disabledEditControls || isDisconnected;
const isViewer = props.isViewer;
const isMobileView = props.isMobileView;
@ -23,9 +21,6 @@ const ToolbarView = props => {
if ( $$('.skl-container').length ) {
$$('.skl-container').remove();
}
return () => {
}
}, []);
return (
@ -78,7 +73,7 @@ const ToolbarView = props => {
}}></Link>,
(props.showEditDocument && !isViewer) &&
<Link key='edit-link' className={(props.disabledControls || isOpenModal) && 'disabled'} icon='icon-edit' href={false} onClick={props.onEditDocument}></Link>,
(props.isEdit && isAvailableExt && !isViewer && EditorUIController.getToolbarOptions &&
(props.isEdit && isAvailableExt && !isViewer && !props.isDrawMode && EditorUIController.getToolbarOptions &&
<Fragment key='editing-buttons'>
{EditorUIController.getToolbarOptions({
disabled: disableEditBtn || props.disabledControls || isOpenModal,
@ -90,7 +85,7 @@ const ToolbarView = props => {
(Device.phone ? null :
<Link key='search-link' className={(props.disabledControls || props.readerMode || isOpenModal) && 'disabled'} icon='icon-search' searchbarEnable='.searchbar' href={false}></Link>
),
(window.matchMedia("(min-width: 360px)").matches && !isForm && !isVersionHistoryMode ?
(window.matchMedia("(min-width: 360px)").matches && !props.isForm && !props.isDrawMode && !isVersionHistoryMode ?
<Link key='coauth-link' className={(props.disabledControls || isOpenModal) && 'disabled'} id='btn-coauth' href={false} icon='icon-collaboration' onClick={() => props.openOptions('coauth')}></Link>
: null),
(isVersionHistoryMode ?

View File

@ -1,8 +1,10 @@
import React, {useState} from 'react';
import {observer, inject} from "mobx-react";
import {List, ListItem, Page, Navbar, Icon, ListButton, ListInput, BlockTitle, Segmented, Button} from 'framework7-react';
import {List, ListItem, Page, Navbar, Icon, ListButton, BlockTitle, Segmented, Button} from 'framework7-react';
import { useTranslation } from 'react-i18next';
import {Device} from "../../../../../common/mobile/utils/device";
import SvgIcon from '../../../../../common/mobile//lib/component/SvgIcon'
import IconDraw from '../../../../../common/mobile/resources/icons/draw.svg'
const PageNumber = props => {
const { t } = useTranslation();
@ -154,32 +156,17 @@ const AddOther = props => {
const { t } = useTranslation();
const _t = t('Add', {returnObjects: true});
const storeFocusObjects = props.storeFocusObjects;
const storeLinkSettings = props.storeLinkSettings;
const canAddLink = storeLinkSettings.canAddLink;
let isShape = storeFocusObjects.settings.indexOf('shape') > -1,
const isShape = storeFocusObjects.settings.indexOf('shape') > -1,
isText = storeFocusObjects.settings.indexOf('text') > -1,
isChart = storeFocusObjects.settings.indexOf('chart') > -1,
isHyperLink = storeFocusObjects.settings.indexOf('hyperlink') > -1,
isHeader = storeFocusObjects.settings.indexOf('header') > -1;
let disabledAddLink = false,
disabledAddBreak = false,
disabledAddFootnote = false,
disabledAddPageNumber = false,
inFootnote = props.inFootnote,
inControl = props.inControl,
paragraphLocked = props.paragraphLocked,
controlPlain = props.controlPlain,
richDelLock = props.richDelLock,
richEditLock = props.richEditLock,
plainDelLock = props.plainDelLock,
plainEditLock = props.plainEditLock;
disabledAddBreak = paragraphLocked || inFootnote || inControl || richEditLock || plainEditLock || richDelLock || plainDelLock;
disabledAddFootnote = paragraphLocked || controlPlain || richEditLock || plainEditLock;
disabledAddLink = paragraphLocked || !canAddLink;
disabledAddPageNumber = controlPlain;
const disabledAddBreak = props.paragraphLocked || props.inFootnote || props.inControl || props.richEditLock || props.plainEditLock || props.richDelLock || props.plainDelLock;
const disabledAddFootnote = props.paragraphLocked || props.controlPlain || props.richEditLock || props.plainEditLock;
const disabledAddLink = props.paragraphLocked || !props.storeLinkSettings.canAddLink;
const disabledAddPageNumber = props.controlPlain;
return (
<List>
@ -213,11 +200,11 @@ const AddOther = props => {
<Icon slot="media" icon="icon-sectionbreak"></Icon>
</ListItem>
}
{!isHeader &&
{!isHeader &&
<ListItem title={_t.textTableContents} link="/add-table-contents/">
<Icon slot="media" icon="icon-table-contents"></Icon>
</ListItem>
}
}
{(isShape || isChart) || (isText && disabledAddFootnote) ? null :
<ListItem key='footnote' title={_t.textFootnote} link={'/add-footnote/'} routeProps={{
getFootnoteProps: props.getFootnoteProps,
@ -229,14 +216,22 @@ const AddOther = props => {
<Icon slot="media" icon="icon-footnote"></Icon>
</ListItem>
}
<ListItem key='drawing' title={_t.textDrawing} onClick={() => {
props.closeModal();
Common.Notifications.trigger('draw:start');
}}>
<SvgIcon slot='media' symbolId={IconDraw.id} className='icon icon-svg'/>
</ListItem>
</List>
)
};
const AddOtherContainer = inject("storeComments","storeFocusObjects", "storeLinkSettings")(observer(AddOther));
export {AddOtherContainer as AddOther,
PageNumber as PageAddNumber,
PageBreak as PageAddBreak,
PageSectionBreak as PageAddSectionBreak,
PageFootnote as PageAddFootnote};
export {
AddOtherContainer as AddOther,
PageNumber as PageAddNumber,
PageBreak as PageAddBreak,
PageSectionBreak as PageAddSectionBreak,
PageFootnote as PageAddFootnote,
};

View File

@ -270,6 +270,7 @@
"waitText": "Please, wait..."
},
"Toolbar": {
"textOk": "OK",
"dlgLeaveMsgText": "You have unsaved changes in this document. Click 'Stay on this Page' to wait for autosave. Click 'Leave this Page' to discard all the unsaved changes.",
"dlgLeaveTitleText": "You leave the application",
"leaveButtonText": "Leave this page",
@ -281,6 +282,7 @@
"View": {
"Add": {
"notcriticalErrorTitle": "Warning",
"textDrawing": "Drawing",
"textAddLink": "Add Link",
"textAddress": "Address",
"textBack": "Back",
@ -554,5 +556,11 @@
"textVersion": "Version",
"textVersionHistory": "Version History"
}
},
"Draw": {
"textOpacity": "Opacity",
"textLineSize": "Line size",
"textColor": "Color",
"textCustomColor": "Custom color"
}
}

View File

@ -259,6 +259,7 @@ const ToolbarController = inject('storeAppOptions', 'users', 'storeFocusObjects'
<ToolbarView
openOptions={props.openOptions}
isEdit={appOptions.isEdit}
isDrawMode={appOptions.isDrawMode}
docTitle={docTitle}
isShowBack={isShowBack}
isCanUndo={isCanUndo}

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: blob:">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover, interactive-widget=resizes-content">
<meta name="theme-color" content="#007aff">
<meta name="format-detection" content="telephone=no">

View File

@ -4,5 +4,9 @@
background: @background-tertiary;
}
}
.back-reader-mode {
margin-left: 10px;
}
}

View File

@ -2,6 +2,7 @@
@import '../../../../common/mobile/resources/less/_mixins.less';
@import '../../../../common/mobile/resources/less/colors-table.less';
@import '../../../../common/mobile/resources/less/colors-table-dark.less';
@import '../../../../common/mobile/resources/less/draw.less';
@import './app-rtl.less';
@brandColor: var(--brand-slide);

View File

@ -1,3 +1,8 @@
.icon-svg {
fill: @brand-slide;
color: @brand-slide;
}
i.icon {
&.icon-format-pptx {
width: 22px;

View File

@ -14,6 +14,7 @@ import SettingsController from '../controller/settings/Settings';
import AddView from '../view/add/Add';
import EditView from '../view/edit/Edit';
import VersionHistoryController from '../../../../common/mobile/lib/controller/VersionHistory';
import { DrawController } from "../../../../common/mobile/lib/controller/Draw";
export const MainContext = createContext();
@ -212,6 +213,9 @@ class MainPage extends Component {
</Navbar>
{/* Page content */}
<View id="editor_sdk" />
<Navbar id='drawbar' style={{ display: !appOptions.isDrawMode && 'none' }}>
<DrawController />
</Navbar>
{isShowPlaceholder ?
<div className="doc-placeholder">

View File

@ -9,6 +9,9 @@ export class storeAppOptions {
setConfigOptions: action,
setPermissionOptions: action,
isDrawMode: observable,
changeDrawMode: action,
lostEditingRights: observable,
changeEditingRights: action,
canBrandingExt: observable,
@ -28,6 +31,11 @@ export class storeAppOptions {
config = {};
customization;
isDrawMode = false;
changeDrawMode(value) {
this.isDrawMode = value;
}
lostEditingRights = false;
changeEditingRights (value) {
this.lostEditingRights = value;

View File

@ -23,7 +23,8 @@ const ToolbarView = props => {
return (
<Fragment>
<NavLeft>
{(props.isShowBack && !isVersionHistoryMode) && <Link className={`btn-doc-back${(props.disabledControls || isOpenModal) && ' disabled'}`} icon='icon-return' onClick={() => Common.Notifications.trigger('goback')}></Link>}
{props.isDrawMode && <Link text={Device.ios ? t("Toolbar.textOk") : ''} icon={Device.android ? 'icon-close' : null} className='back-reader-mode' onClick={() => Common.Notifications.trigger('draw:stop')}/>}
{(props.isShowBack && !props.isDrawMode && !isVersionHistoryMode) && <Link className={`btn-doc-back${(props.disabledControls || isOpenModal) && ' disabled'}`} icon='icon-return' onClick={() => Common.Notifications.trigger('goback')}></Link>}
{isVersionHistoryMode ? <a href="#" className='btn-close-history' onClick={(e) => {
e.preventDefault();
props.closeHistory();
@ -47,21 +48,21 @@ const ToolbarView = props => {
onUndoClick: props.onUndo,
onRedoClick: props.onRedo
})}
{!isVersionHistoryMode &&
{(!isVersionHistoryMode && !props.isDrawMode) &&
<Link className={(props.disabledControls || props.disabledPreview || isOpenModal) && 'disabled'} icon='icon-play' href={false} onClick={() => {props.openOptions('preview')}}></Link>
}
{(props.showEditDocument && !isVersionHistoryMode) &&
<Link className={(props.disabledControls || isOpenModal) ? 'disabled' : ''} icon='icon-edit' href={false} onClick={props.onEditDocument}></Link>
}
{(props.isEdit && EditorUIController.getToolbarOptions && !isVersionHistoryMode) && EditorUIController.getToolbarOptions({
{(props.isEdit && EditorUIController.getToolbarOptions && !props.isDrawMode && !isVersionHistoryMode) && EditorUIController.getToolbarOptions({
disabledEdit: props.disabledEdit || props.disabledControls || isDisconnected || props.disabledPreview || isOpenModal,
disabledAdd: props.disabledControls || isDisconnected || isOpenModal,
onEditClick: () => props.openOptions('edit'),
onAddClick: () => props.openOptions('add')
})}
{Device.phone ? null : <Link className={(props.disabledControls || props.disabledPreview || isOpenModal) && 'disabled'} icon='icon-search' searchbarEnable='.searchbar' href={false}></Link>}
{props.displayCollaboration && window.matchMedia("(min-width: 375px)").matches && !isVersionHistoryMode ? <Link className={(props.disabledControls || isOpenModal) && 'disabled'} id='btn-coauth' href={false} icon='icon-collaboration' onClick={() => props.openOptions('coauth')}></Link> : null}
{isVersionHistoryMode ? <Link id='btn-open-history' icon='icon-version-history' href={false} className={isOpenModal && 'disabled'} onClick={() => props.openOptions('history')}></Link> : null}
{props.displayCollaboration && window.matchMedia("(min-width: 375px)").matches && !props.isDrawMode && !isVersionHistoryMode ? <Link className={(props.disabledControls || isOpenModal) && 'disabled'} id='btn-coauth' href={false} icon='icon-collaboration' onClick={() => props.openOptions('coauth')}></Link> : null}
{(isVersionHistoryMode && !props.isDrawMode) ? <Link id='btn-open-history' icon='icon-version-history' href={false} className={isOpenModal && 'disabled'} onClick={() => props.openOptions('history')}></Link> : null}
<Link className={(props.disabledSettings || props.disabledControls || isDisconnected || isOpenModal) && 'disabled'} id='btn-settings' icon='icon-settings' href={false} onClick={() => props.openOptions('settings')}></Link>
</NavRight>
</Fragment>

View File

@ -3,6 +3,8 @@ import {observer, inject} from "mobx-react";
import {List, ListItem, Page, Navbar, Icon, ListButton, ListInput, BlockTitle, SkeletonBlock, Segmented, Button} from 'framework7-react';
import { useTranslation } from 'react-i18next';
import {Device} from "../../../../../common/mobile/utils/device";
import SvgIcon from "../../../../../common/mobile/lib/component/SvgIcon";
import IconDraw from "../../../../../common/mobile/resources/icons/draw.svg";
const PageTable = props => {
const { t } = useTranslation();
@ -71,6 +73,12 @@ const AddOther = props => {
<Icon slot="media" icon="icon-link"></Icon>
</ListItem>
}
<ListItem key='drawing' title={_t.textDrawing} onClick={() => {
props.closeModal();
Common.Notifications.trigger('draw:start');
}}>
<SvgIcon slot='media' symbolId={IconDraw.id} className='icon icon-svg'/>
</ListItem>
</List>
)
};

View File

@ -443,6 +443,7 @@
"textWarnDeleteSheet": "The sheet maybe has data. Proceed operation?"
},
"Toolbar": {
"textOk": "OK",
"dlgLeaveMsgText": "You have unsaved changes in this document. Click 'Stay on this Page' to wait for autosave. Click 'Leave this Page' to discard all the unsaved changes.",
"dlgLeaveTitleText": "You leave the application",
"leaveButtonText": "Leave this Page",
@ -453,6 +454,7 @@
},
"View": {
"Add": {
"textDrawing": "Drawing",
"errorMaxRows": "ERROR! The maximum number of data series per chart is 255.",
"errorStockChart": "Incorrect row order. To build a stock chart, place the data on the sheet in the following order:<br> opening price, max price, min price, closing price.",
"notcriticalErrorTitle": "Warning",
@ -862,5 +864,11 @@
"txtZh": "Chinese",
"warnDownloadAs": "If you continue saving in this format all features except the text will be lost.<br>Are you sure you want to continue?"
}
},
"Draw": {
"textOpacity": "Opacity",
"textLineSize": "Line size",
"textColor": "Color",
"textCustomColor": "Custom color"
}
}

View File

@ -277,6 +277,7 @@ const ToolbarController = inject('storeAppOptions', 'users', 'storeSpreadsheetIn
<ToolbarView
openOptions={props.openOptions}
isEdit={appOptions.isEdit}
isDrawMode={appOptions.isDrawMode}
docTitle={docTitle}
isShowBack={isShowBack}
isCanUndo={isCanUndo}

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: blob:">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover, interactive-widget=resizes-content">
<meta name="theme-color" content="#007aff">
<meta name="format-detection" content="telephone=no">

View File

@ -36,4 +36,8 @@
overflow: hidden;
}
}
.back-reader-mode {
margin-left: 10px;
}
}

View File

@ -3,6 +3,7 @@
@import '../../../../common/mobile/resources/less/_mixins.less';
@import '../../../../common/mobile/resources/less/colors-table.less';
@import '../../../../common/mobile/resources/less/colors-table-dark.less';
@import '../../../../common/mobile/resources/less/draw.less';
@import './app-rtl.less';
// @themeColor: #40865c;

View File

@ -1,3 +1,7 @@
.icon-svg {
fill: @brand-cell;
color: @brand-cell;
}
.chart-types .thumb {
//@relativepath: '../../resources/img';

View File

@ -17,6 +17,7 @@ import SettingsController from '../controller/settings/Settings';
import AddingController from '../controller/add/Add';
import EditView from '../view/edit/Edit';
import VersionHistoryController from '../../../../common/mobile/lib/controller/VersionHistory';
import { DrawController } from "../../../../common/mobile/lib/controller/Draw";
export const MainContext = createContext();
@ -208,6 +209,9 @@ class MainPage extends Component {
<CellEditor onClickToOpenAddOptions={(panels, button) => this.handleClickToOpenOptions('add', {panels: panels, button: button})} />
{/* Page content */}
<View id="editor_sdk" />
<Navbar id='drawbar' style={{ display: !appOptions.isDrawMode && 'none' }}>
<DrawController />
</Navbar>
{isShowPlaceholder ?
<div className="doc-placeholder">
<div className="columns"></div>

View File

@ -9,6 +9,9 @@ export class storeAppOptions {
setConfigOptions: action,
setPermissionOptions: action,
isDrawMode: observable,
changeDrawMode: action,
lostEditingRights: observable,
changeEditingRights: action,
@ -25,6 +28,11 @@ export class storeAppOptions {
isEdit = false;
config = {};
customization;
isDrawMode = false;
changeDrawMode(value) {
this.isDrawMode = value;
}
canViewComments = false;
changeCanViewComments(value) {

View File

@ -218,7 +218,7 @@ const StatusbarView = inject('storeAppOptions', 'storeWorksheets', 'users')(obse
return (
<Fragment>
<View id="idx-statusbar" className="statusbar" style={viewStyle}>
<View id="idx-statusbar" className="statusbar" style={{ marginBottom: storeAppOptions.isDrawMode ? 'calc(44px + env(safe-area-inset-bottom) + env(keyboard-inset-top))' : undefined, ...viewStyle }}>
{isEdit &&
<div id="idx-box-add-tab" className={`${isDisconnected || isWorkbookLocked ? 'disabled box-tab' : 'box-tab'}`}>
<Link href={false} id="idx-btn-addtab" className={`tab${isDisabledEditSheet || isDisconnected || isWorkbookLocked || isProtectedWorkbook ? ' disabled' : ''}`} onClick={props.onAddTabClicked}>

View File

@ -32,7 +32,8 @@ const ToolbarView = props => {
return (
<Fragment>
<NavLeft>
{(props.isShowBack && !isVersionHistoryMode) && <Link className={`btn-doc-back${(props.disabledControls || isOpenModal) && ' disabled'}`} icon='icon-return' onClick={() => Common.Notifications.trigger('goback')}></Link>}
{props.isDrawMode && <Link text={Device.ios ? t("Toolbar.textOk") : ''} icon={Device.android ? 'icon-close' : null} className='back-reader-mode' onClick={() => Common.Notifications.trigger('draw:stop')}/>}
{(!props.isDrawMode && props.isShowBack && !isVersionHistoryMode) && <Link className={`btn-doc-back${(props.disabledControls || isOpenModal) && ' disabled'}`} icon='icon-return' onClick={() => Common.Notifications.trigger('goback')}></Link>}
{isVersionHistoryMode ? <a href="#" className='btn-close-history' onClick={(e) => {
e.preventDefault();
props.closeHistory();
@ -49,7 +50,7 @@ const ToolbarView = props => {
{(props.showEditDocument && !isVersionHistoryMode) &&
<Link className={(props.disabledControls || isOpenModal) ? 'disabled' : ''} icon='icon-edit' href={false} onClick={props.onEditDocument}></Link>
}
{(props.isEdit && EditorUIController.toolbarOptions && !isVersionHistoryMode) && EditorUIController.toolbarOptions.getEditOptions({
{(!props.isDrawMode && props.isEdit && EditorUIController.toolbarOptions && !isVersionHistoryMode) && EditorUIController.toolbarOptions.getEditOptions({
disabled: props.disabledEditControls || props.disabledControls || isDisconnected || isOpenModal,
wsProps,
focusOn,
@ -58,7 +59,7 @@ const ToolbarView = props => {
onAddClick: () => props.openOptions('add')
})}
{Device.phone ? null : <Link className={(props.disabledControls || props.disabledSearch || isOpenModal) && 'disabled'} icon='icon-search' searchbarEnable='.searchbar' href={false}></Link>}
{props.displayCollaboration && window.matchMedia("(min-width: 360px)").matches && !isVersionHistoryMode ? <Link className={(props.disabledControls || props.disabledCollaboration || isOpenModal) && 'disabled'} id='btn-coauth' href={false} icon='icon-collaboration' onClick={() => props.openOptions('coauth')}></Link> : null}
{!props.isDrawMode && props.displayCollaboration && window.matchMedia("(min-width: 360px)").matches && !isVersionHistoryMode ? <Link className={(props.disabledControls || props.disabledCollaboration || isOpenModal) && 'disabled'} id='btn-coauth' href={false} icon='icon-collaboration' onClick={() => props.openOptions('coauth')}></Link> : null}
{isVersionHistoryMode ? <Link id='btn-open-history' icon='icon-version-history' href={false} className={isOpenModal && 'disabled'} onClick={() => props.openOptions('history')}></Link> : null}
<Link className={(props.disabledSettings || props.disabledControls || isDisconnected || isOpenModal) && 'disabled'} id='btn-settings' icon='icon-settings' href={false} onClick={() => props.openOptions('settings')}></Link>
</NavRight>

View File

@ -3,6 +3,9 @@ import { inject, observer } from 'mobx-react';
import {List, ListItem, Icon} from 'framework7-react';
import { useTranslation } from 'react-i18next';
import { MainContext } from '../../page/main';
import { Device } from "../../../../../common/mobile/utils/device";
import SvgIcon from "../../../../../common/mobile/lib/component/SvgIcon";
import IconDraw from "../../../../../common/mobile/resources/icons/draw.svg";
const AddOther = inject("storeFocusObjects", "storeAppOptions")(observer(props => {
const { t } = useTranslation();
@ -34,6 +37,12 @@ const AddOther = inject("storeFocusObjects", "storeAppOptions")(observer(props =
}}>
<Icon slot="media" icon="icon-link"></Icon>
</ListItem>
<ListItem key='drawing' title={_t.textDrawing} onClick={() => {
props.closeModal();
Common.Notifications.trigger('draw:start');
}}>
<SvgIcon slot='media' symbolId={IconDraw.id} className='icon icon-svg'/>
</ListItem>
</List>
)
}));

File diff suppressed because it is too large Load Diff

View File

@ -79,6 +79,7 @@
"postcss-loader": "^7.3.4",
"postcss-preset-env": "^9.4.0",
"style-loader": "^3.3.3",
"svg-sprite-loader": "^6.0.11",
"terser-webpack-plugin": "^5.3.10",
"url-loader": "^4.1.1",
"webpack": "^5.90.1",