-
Notifications
You must be signed in to change notification settings - Fork 250
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request 'feat/mobile-draw' (#225) from feat/mobile-draw in…
…to release/v8.3.0
- Loading branch information
Showing
51 changed files
with
799 additions
and
473 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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> | ||
) | ||
} | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.