diff --git a/apps/common/mobile/resources/less/common-ios.less b/apps/common/mobile/resources/less/common-ios.less index c3d834f89..ee582bc7b 100644 --- a/apps/common/mobile/resources/less/common-ios.less +++ b/apps/common/mobile/resources/less/common-ios.less @@ -299,6 +299,29 @@ } } + .button-fill { + color: @themeColor; + background-color: @white; + } + + .button-red { + color: @red; + background-color: @white; + } + + .buttons-list { + li { + border: 0; + border-radius: 0; + height: 43px; + min-height: 43px; + font-size: 17px; + text-transform: initial; + padding: 0; + box-shadow: none; + } + } + .button-red .list-button { color: red; } diff --git a/apps/common/mobile/resources/less/common-material.less b/apps/common/mobile/resources/less/common-material.less index c0d4012bf..dab99d7c2 100644 --- a/apps/common/mobile/resources/less/common-material.less +++ b/apps/common/mobile/resources/less/common-material.less @@ -2,6 +2,7 @@ .device-android { @tabLinkColor: rgba(255,255,255,.7); @red: #f44336; + @white: #fff; --f7-navbar-shadow-image: none; --f7-radio-active-color: @themeColor; --f7-toggle-active-color: @themeColor; @@ -35,29 +36,24 @@ } .button { --f7-button-text-color: @themeColor; - border: 1px solid @themeColor; color: @themeColor; text-align: center; display: block; - // border-radius: 2px; - line-height: 27px; - border-radius: 5px; - // line-height: 36px; + border-radius: 2px; + line-height: 36px; box-sizing: border-box; appearance: none; background: 0 0; margin: 0; - // height: 36px; - height: 29px; + height: 36px; white-space: nowrap; text-overflow: ellipsis; font-size: 14px; text-transform: uppercase; font-family: inherit; cursor: pointer; - // min-width: 64px; - // padding: 0 8px; - padding: 0 10px; + min-width: 64px; + padding: 0 8px; position: relative; overflow: hidden; outline: 0; @@ -66,6 +62,33 @@ -webkit-transform: translate3d(0,0,0); transform: translate3d(0,0,0); } + + .button-fill { + color: @white; + background-color: @themeColor; + } + + .button-raised { + box-shadow: 0 1px 3px rgba(0,0,0,.12), 0 1px 2px rgba(0,0,0,.24); + } + + .button-red { + color: @white; + background-color: @red; + } + + .buttons-list { + li { + margin: 20px 16px; + color: @white; + border-radius: 2px; + text-transform: uppercase; + height: 36px; + min-height: 36px; + font-size: 14px; + } + } + .table-presets { .button { min-width: 0; diff --git a/apps/common/mobile/resources/less/common.less b/apps/common/mobile/resources/less/common.less index 7945fc977..5e6633c9f 100644 --- a/apps/common/mobile/resources/less/common.less +++ b/apps/common/mobile/resources/less/common.less @@ -3,7 +3,7 @@ @black: #000000; @gray: #c4c4c4; @green: #4cd964; -@brightred: #f00; +@red: #f00; @background-normal: @white; @autoColor: @black; @@ -23,6 +23,11 @@ } } +.disabled, [disabled] { + opacity: .55; + pointer-events: none; +} + .shapes { li { width: 70px; @@ -256,25 +261,32 @@ } } -.list { - .apply-all, .duplicate-slide, .delete-slide { - border: 0; - .item-content { - padding-left: 0; - } - .item-inner { - justify-content: center; - padding-right: 0; - } - .item-link .item-inner::before { +.buttons-list { + ul { + &::before, &::after { display: none; } - } - .apply-all, .duplicate-slide { - color: @themeColor; - } - .delete-slide { - color: @brightred; + li { + border: 0; + font-weight: normal; + .item-link { + height: 100%; + .item-content { + min-height: initial; + height: 100%; + padding: 0; + } + .item-inner { + justify-content: center; + align-items: center; + padding: 0; + min-height: initial; + &::before { + display: none; + } + } + } + } } } diff --git a/apps/presentationeditor/mobile/locale/en.json b/apps/presentationeditor/mobile/locale/en.json index 6fb0b7830..2a639adb2 100644 --- a/apps/presentationeditor/mobile/locale/en.json +++ b/apps/presentationeditor/mobile/locale/en.json @@ -130,9 +130,51 @@ "textSec": "s", "textAddCustomColor": "Add Custom Color", "textFill": "Fill", + "textBorder": "Border", + "textEffects": "Effects", "textCustomColor": "Custom Color", "textDuplicateSlide": "Duplicate Slide", - "textDeleteSlide": "Delete Slide" + "textDeleteSlide": "Delete Slide", + "textFontColor": "Font Color", + "textHighlightColor": "Highlight Color", + "textAdditionalFormatting": "Additional Formatting", + "textAdditional": "Additional", + "textBullets": "Bullets", + "textNumbers": "Numbers", + "textLineSpacing": "Line Spacing", + "textFonts": "Fonts", + "textAuto": "Auto", + "textPt": "pt", + "textSize": "Size", + "textStrikethrough": "Strikethrough", + "textDoubleStrikethrough": "Double Strikethrough", + "textSuperscript": "Superscript", + "textSubscript": "Subscript", + "textSmallCaps": "Small Caps", + "textAllCaps": "All Caps", + "textLetterSpacing": "Letter Spacing", + "textDistanceFromText": "Distance From Text", + "textBefore": "Before", + "textAfter": "After", + "textFontColors": "Font Colors", + "textReplace": "Replace", + "textReorder": "Reorder", + "textAlign": "Align", + "textRemoveShape": "Remove Shape", + "textColor": "Color", + "textOpacity": "Opacity", + "textBringToForeground": "Bring to Foreground", + "textSendToBackground": "Send to Background", + "textMoveForward": "Move Forward", + "textMoveBackward": "Move Backward", + "textAlignLeft": "Align Left", + "textAlignCenter": "Align Center", + "textAlignRight": "Align Right", + "textAlignTop": "Align Top", + "textAlignMiddle": "Align Middle", + "textAlignBottom": "Align Bottom", + "textDistributeHorizontally": "Distribute Horizontally", + "textDistributeVertically": "Distribute Vertically" } }, "Common": { diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx index 727925909..40c892ac1 100644 --- a/apps/presentationeditor/mobile/src/controller/Main.jsx +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -5,7 +5,7 @@ import { f7 } from "framework7-react"; import { withTranslation } from 'react-i18next'; import CollaborationController from '../../../../common/mobile/lib/controller/Collaboration.jsx' -@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeSlideSettings") +@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeSlideSettings", "storeTextSettings") class MainController extends Component { constructor(props) { super(props) @@ -220,6 +220,84 @@ class MainController extends Component { Common.Utils.ThemeColor.setColors(colors, standart_colors); }); + // Text settings + + const storeTextSettings = this.props.storeTextSettings; + + this.api.asc_registerCallback('asc_onInitEditorFonts', (fonts, select) => { + storeTextSettings.initEditorFonts(fonts, select); + }); + + this.api.asc_registerCallback('asc_onFontFamily', (font) => { + storeTextSettings.resetFontName(font); + }); + + this.api.asc_registerCallback('asc_onFontSize', (size) => { + storeTextSettings.resetFontSize(size); + }); + + this.api.asc_registerCallback('asc_onBold', (isBold) => { + storeTextSettings.resetIsBold(isBold); + }); + + this.api.asc_registerCallback('asc_onItalic', (isItalic) => { + storeTextSettings.resetIsItalic(isItalic); + }); + + this.api.asc_registerCallback('asc_onUnderline', (isUnderline) => { + storeTextSettings.resetIsUnderline(isUnderline); + }); + + this.api.asc_registerCallback('asc_onStrikeout', (isStrikeout) => { + storeTextSettings.resetIsStrikeout(isStrikeout); + }); + + this.api.asc_registerCallback('asc_onVerticalAlign', (typeBaseline) => { + storeTextSettings.resetTypeBaseline(typeBaseline); + }); + + this.api.asc_registerCallback('asc_onListType', (data) => { + let type = data.get_ListType(); + let subtype = data.get_ListSubType(); + + storeTextSettings.resetListType(type); + + switch (type) { + case 0: + storeTextSettings.resetBullets(subtype); + break; + case 1: + storeTextSettings.resetNumbers(subtype); + break; + default: + storeTextSettings.resetBullets(-1); + storeTextSettings.resetNumbers(-1); + } + }); + + this.api.asc_registerCallback('asc_onPrAlign', (align) => { + storeTextSettings.resetParagraphAlign(align); + }); + + this.api.asc_registerCallback('asc_onVerticalTextAlign', valign => { + storeTextSettings.resetParagraphValign(valign); + }); + + this.api.asc_registerCallback('asc_canIncreaseIndent', value => { + storeTextSettings.resetIncreaseIndent(value); + }); + + this.api.asc_registerCallback('asc_canDecreaseIndent', value => { + storeTextSettings.resetDecreaseIndent(value); + }); + + this.api.asc_registerCallback('asc_onTextColor', (color) => { + storeTextSettings.resetTextColor(color); + }); + + this.api.asc_registerCallback('asc_onParaSpacingLine', (vc) => { + storeTextSettings.resetLineSpacing(vc); + }); } _onDocumentContentReady() { diff --git a/apps/presentationeditor/mobile/src/controller/edit/EditShape.jsx b/apps/presentationeditor/mobile/src/controller/edit/EditShape.jsx new file mode 100644 index 000000000..a7b42a95d --- /dev/null +++ b/apps/presentationeditor/mobile/src/controller/edit/EditShape.jsx @@ -0,0 +1,182 @@ +import React, {Component} from 'react'; +import { f7 } from 'framework7-react'; +import {Device} from '../../../../../common/mobile/utils/device'; +import {observer, inject} from "mobx-react"; + +import { EditShape } from '../../view/edit/EditShape'; + +class EditShapeController extends Component { + constructor (props) { + super(props); + this.onRemoveShape = this.onRemoveShape.bind(this); + this.onBorderSize = this.onBorderSize.bind(this); + this.onBorderColor = this.onBorderColor.bind(this); + + this.props.storeShapeSettings.setFillColor(undefined); + this.props.storeShapeSettings.setBorderColor(undefined); + } + + onReplace(type) { + const api = Common.EditorApi.get(); + api.ChangeShapeType(type); + } + + onReorder(type) { + const api = Common.EditorApi.get(); + + switch(type) { + case 'all-up': + api.shapes_bringToFront(); + break; + case 'all-down': + api.shapes_bringToBack(); + break; + case 'move-up': + api.shapes_bringForward(); + break; + case 'move-down': + api.shapes_bringBackward(); + break; + + } + } + + onAlign(type) { + const api = Common.EditorApi.get(); + + switch(type) { + case 'align-left': + api.put_ShapesAlign(Asc.c_oAscAlignShapeType.ALIGN_LEFT); + break; + case 'align-center': + api.put_ShapesAlign(Asc.c_oAscAlignShapeType.ALIGN_CENTER); + break; + case 'align-right': + api.put_ShapesAlign(Asc.c_oAscAlignShapeType.ALIGN_RIGHT); + break; + case 'align-top': + api.put_ShapesAlign(Asc.c_oAscAlignShapeType.ALIGN_TOP); + break; + case 'align-middle': + api.put_ShapesAlign(Asc.c_oAscAlignShapeType.ALIGN_MIDDLE); + break; + case 'align-bottom': + api.put_ShapesAlign(Asc.c_oAscAlignShapeType.ALIGN_BOTTOM); + break; + case 'distrib-hor': + api.DistributeHorizontally(); + break; + case 'distrib-vert': + api.DistributeVertically(); + break; + } + } + + closeModal() { + if (Device.phone) { + f7.sheet.close('#edit-sheet', true); + } else { + f7.popover.close('#edit-popover'); + } + }; + + onRemoveShape() { + const api = Common.EditorApi.get(); + api.asc_Remove(); + this.closeModal(); + } + + onFillColor(color) { + const api = Common.EditorApi.get(); + + let shape = new Asc.asc_CShapeProperty(), + fill = new Asc.asc_CShapeFill(); + + if (color == 'transparent') { + fill.put_type(Asc.c_oAscFill.FILL_TYPE_NOFILL); + fill.put_fill(null); + } else { + fill.put_type(Asc.c_oAscFill.FILL_TYPE_SOLID); + fill.put_fill(new Asc.asc_CFillSolid()); + fill.get_fill().put_color(Common.Utils.ThemeColor.getRgbColor(color)); + } + + shape.put_fill(fill); + api.ShapeApply(shape); + } + + onBorderColor(color) { + const api = Common.EditorApi.get(); + const _shapeObject = this.props.storeFocusObjects.shapeObject; + + if (_shapeObject && _shapeObject.get_stroke().get_type() == Asc.c_oAscStrokeType.STROKE_COLOR) { + let shape = new Asc.asc_CShapeProperty(), + stroke = new Asc.asc_CStroke(); + + if (_shapeObject.get_stroke().get_width() < 0.01) { + stroke.put_type(Asc.c_oAscStrokeType.STROKE_NONE); + } else { + stroke.put_type(Asc.c_oAscStrokeType.STROKE_COLOR); + stroke.put_color(Common.Utils.ThemeColor.getRgbColor(color)); + stroke.put_width(_shapeObject.get_stroke().get_width()); + stroke.asc_putPrstDash(_shapeObject.get_stroke().asc_getPrstDash()); + } + + shape.put_stroke(stroke); + api.ShapeApply(shape); + } + } + + onBorderSize(value) { + const api = Common.EditorApi.get(); + const shape = new Asc.asc_CShapeProperty(); + const stroke = new Asc.asc_CStroke(); + + const _borderColor = this.props.storeShapeSettings.borderColorView; + + if (value < 0.01) { + stroke.put_type(Asc.c_oAscStrokeType.STROKE_NONE); + } else { + stroke.put_type(Asc.c_oAscStrokeType.STROKE_COLOR); + if (_borderColor == 'transparent') + stroke.put_color(Common.Utils.ThemeColor.getRgbColor({color: '000000', effectId: 29})); + else + stroke.put_color(Common.Utils.ThemeColor.getRgbColor(Common.Utils.ThemeColor.colorValue2EffectId(_borderColor))); + stroke.put_width(value * 25.4 / 72.0); + } + + shape.put_stroke(stroke); + api.ShapeApply(shape); + + this.props.storeShapeSettings.initBorderColorView(this.props.storeFocusObjects.shapeObject); + } + + onOpacity(value) { + const api = Common.EditorApi.get(); + + let fill = new Asc.asc_CShapeFill(), + shape = new Asc.asc_CShapeProperty(); + + fill.put_transparent(parseInt(value * 2.55)); + shape.put_fill(fill); + api.ShapeApply(shape); + } + + + render () { + return ( + + ) + } +} + +export default inject("storeShapeSettings", "storeFocusObjects")(observer(EditShapeController)); \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/edit/EditText.jsx b/apps/presentationeditor/mobile/src/controller/edit/EditText.jsx index 62bd4ae93..2b9ce3ae1 100644 --- a/apps/presentationeditor/mobile/src/controller/edit/EditText.jsx +++ b/apps/presentationeditor/mobile/src/controller/edit/EditText.jsx @@ -9,9 +9,243 @@ class EditTextController extends Component { constructor (props) { super(props); } + + toggleBold(value) { + const api = Common.EditorApi.get(); + api.put_TextPrBold(value); + }; + + toggleItalic(value) { + const api = Common.EditorApi.get(); + api.put_TextPrItalic(value); + }; + + toggleUnderline(value) { + const api = Common.EditorApi.get(); + api.put_TextPrUnderline(value); + }; + + toggleStrikethrough(value) { + const api = Common.EditorApi.get(); + api.put_TextPrStrikeout(value); + }; + + onParagraphAlign(type) { + const api = Common.EditorApi.get(); + let value; + + switch (type) { + case 'just': + value = 3; + break; + case 'right': + value = 0; + break; + case 'center': + value = 2; + break; + default: + value = 1; + break; + } + + api.put_PrAlign(value); + }; + + onParagraphValign(type) { + const api = Common.EditorApi.get(); + let value; + + switch(type) { + case 'top': + value = Asc.c_oAscVAlign.Top; + break; + case 'center': + value = Asc.c_oAscVAlign.Center; + break; + case 'bottom': + value = Asc.c_oAscVAlign.Bottom; + break; + } + + api.setVerticalAlign(value); + }; + + onParagraphMove(type) { + const api = Common.EditorApi.get(); + + if(type === 'left') { + api.DecreaseIndent(); + } else { + api.IncreaseIndent(); + } + }; + + onDistanceBefore(distance, isDecrement) { + const api = Common.EditorApi.get(); + let step; + let newDistance; + + if (Common.Utils.Metric.getCurrentMetric() == Common.Utils.Metric.c_MetricUnits.pt) { + step = 1; + } else { + step = 0.01; + } + + const maxValue = Common.Utils.Metric.fnRecalcFromMM(558.8); + + if(isDecrement) { + newDistance = Math.max(-1, distance - step); + } else { + newDistance = (distance < 0) ? 0 : Math.min(maxValue, distance + step); + } + + api.put_LineSpacingBeforeAfter(0, (newDistance < 0) ? -1 : Common.Utils.Metric.fnRecalcToMM(newDistance)); + }; + + onDistanceAfter(distance, isDecrement) { + const api = Common.EditorApi.get(); + let step; + let newDistance; + + if (Common.Utils.Metric.getCurrentMetric() == Common.Utils.Metric.c_MetricUnits.pt) { + step = 1; + } else { + step = 0.01; + } + + const maxValue = Common.Utils.Metric.fnRecalcFromMM(558.8); + + if(isDecrement) { + newDistance = Math.max(-1, distance - step); + } else { + newDistance = (distance < 0) ? 0 : Math.min(maxValue, distance + step); + } + + api.put_LineSpacingBeforeAfter(1, (newDistance < 0) ? -1 : Common.Utils.Metric.fnRecalcToMM(newDistance)); + }; + + changeFontSize(curSize, isDecrement) { + const api = Common.EditorApi.get(); + let size = curSize; + + if (isDecrement) { + typeof size === 'undefined' ? api.FontSizeOut() : size = Math.max(1, --size); + } else { + typeof size === 'undefined' ? api.FontSizeIn : size = Math.min(100, ++size); + } + if (typeof size !== 'undefined') { + api.put_TextPrFontSize(size); + } + }; + + changeFontFamily(name) { + const api = Common.EditorApi.get(); + if (name) { + api.put_TextPrFontName(name); + } + } + + onTextColor(color) { + const api = Common.EditorApi.get(); + api.put_TextColor(Common.Utils.ThemeColor.getRgbColor(color)); + } + + // Additional + + onAdditionalStrikethrough(type, value) { + const api = Common.EditorApi.get(); + const paragraphProps = new Asc.asc_CParagraphProperty(); + + if ('strikethrough' === type) { + paragraphProps.put_DStrikeout(false); + paragraphProps.put_Strikeout(value); + } else { + paragraphProps.put_DStrikeout(value); + paragraphProps.put_Strikeout(false); + } + + api.paraApply(paragraphProps); + } + + onAdditionalCaps(type, value) { + const api = Common.EditorApi.get(); + const paragraphProps = new Asc.asc_CParagraphProperty(); + + if ('small' === type) { + paragraphProps.put_AllCaps(false); + paragraphProps.put_SmallCaps(value); + } else { + paragraphProps.put_AllCaps(value); + paragraphProps.put_SmallCaps(false); + } + + api.paraApply(paragraphProps); + } + + onAdditionalScript(type, value) { + const api = Common.EditorApi.get(); + + if ('superscript' === type) { + api.put_TextPrBaseline(value ? 1 : 0); + } else { + api.put_TextPrBaseline(value ? 2 : 0); + } + } + + changeLetterSpacing(curSpacing, isDecrement) { + const api = Common.EditorApi.get(); + let spacing = curSpacing; + + if (isDecrement) { + spacing = (spacing === null || spacing === undefined) ? 0 : Math.max(-100, --spacing); + } else { + spacing = (spacing === null || spacing === undefined) ? 0 : Math.min(100, ++spacing); + } + + const properties = new Asc.asc_CParagraphProperty(); + properties.put_TextSpacing(Common.Utils.Metric.fnRecalcToMM(spacing)); + api.paraApply(properties); + } + + onBullet(type) { + const api = Common.EditorApi.get(); + api.put_ListType(0, parseInt(type)); + } + + onNumber(type) { + const api = Common.EditorApi.get(); + api.put_ListType(1, parseInt(type)); + } + + onLineSpacing(value) { + const api = Common.EditorApi.get(); + const LINERULE_AUTO = 1; + api.put_PrLineSpacing(LINERULE_AUTO, value); + } + render () { return ( ) } diff --git a/apps/presentationeditor/mobile/src/less/app.less b/apps/presentationeditor/mobile/src/less/app.less index d83b0a431..5d0124ddb 100644 --- a/apps/presentationeditor/mobile/src/less/app.less +++ b/apps/presentationeditor/mobile/src/less/app.less @@ -5,6 +5,7 @@ @import '../../../../common/mobile/resources/less/common.less'; @import '../../../../common/mobile/resources/less/common-ios.less'; @import '../../../../common/mobile/resources/less/common-material.less'; +@import '../../../../common/mobile/resources/less/dataview.less'; @import '../../../../common/mobile/resources/less/about.less'; @import './app-material.less'; @import './app-ios.less'; diff --git a/apps/presentationeditor/mobile/src/less/icons-ios.less b/apps/presentationeditor/mobile/src/less/icons-ios.less index b29d6067f..6b77662cd 100644 --- a/apps/presentationeditor/mobile/src/less/icons-ios.less +++ b/apps/presentationeditor/mobile/src/less/icons-ios.less @@ -157,7 +157,7 @@ .encoded-svg-mask(''); } - &.icon-text-align-jast { + &.icon-text-align-just { width: 22px; height: 22px; .encoded-svg-mask(''); diff --git a/apps/presentationeditor/mobile/src/less/icons-material.less b/apps/presentationeditor/mobile/src/less/icons-material.less index 97f586ae8..b1de085b6 100644 --- a/apps/presentationeditor/mobile/src/less/icons-material.less +++ b/apps/presentationeditor/mobile/src/less/icons-material.less @@ -127,7 +127,7 @@ .encoded-svg-mask(''); } - &.icon-text-align-jast { + &.icon-text-align-just { width: 22px; height: 22px; .encoded-svg-mask(''); diff --git a/apps/presentationeditor/mobile/src/store/applicationSettings.js b/apps/presentationeditor/mobile/src/store/applicationSettings.js index b69eed851..b9e764a27 100644 --- a/apps/presentationeditor/mobile/src/store/applicationSettings.js +++ b/apps/presentationeditor/mobile/src/store/applicationSettings.js @@ -2,7 +2,7 @@ import {action, observable} from 'mobx'; export class storeApplicationSettings { - @observable unitMeasurement = 0; + @observable unitMeasurement = 1; @observable isSpellChecking = true; @observable macrosMode = 0; diff --git a/apps/presentationeditor/mobile/src/store/focusObjects.js b/apps/presentationeditor/mobile/src/store/focusObjects.js index 12ac4d517..48f28d076 100644 --- a/apps/presentationeditor/mobile/src/store/focusObjects.js +++ b/apps/presentationeditor/mobile/src/store/focusObjects.js @@ -67,4 +67,34 @@ export class storeFocusObjects { return undefined; } } + + @computed get paragraphObject() { + const paragraphs = []; + for (let object of this._focusObjects) { + if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Paragraph) { + paragraphs.push(object); + } + } + if (paragraphs.length > 0) { + const object = paragraphs[paragraphs.length - 1]; // get top + return object.get_ObjectValue(); + } else { + return undefined; + } + } + + @computed get shapeObject() { + const shapes = []; + for (let object of this._focusObjects) { + if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Shape) { + shapes.push(object); + } + } + if (shapes.length > 0) { + const object = shapes[shapes.length - 1]; // get top + return object.get_ObjectValue(); + } else { + return undefined; + } + } } \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/store/mainStore.js b/apps/presentationeditor/mobile/src/store/mainStore.js index c8eb32009..15f597cd7 100644 --- a/apps/presentationeditor/mobile/src/store/mainStore.js +++ b/apps/presentationeditor/mobile/src/store/mainStore.js @@ -8,6 +8,8 @@ import {storePresentationInfo} from './presentationInfo'; import {storePresentationSettings} from './presentationSettings'; import { storePalette } from './palette'; import { storeSlideSettings } from './slideSettings'; +import { storeTextSettings } from './textSettings'; +import { storeShapeSettings } from './shapeSettings'; // import {storeTextSettings} from "./textSettings"; // import {storeParagraphSettings} from "./paragraphSettings"; // import {storeShapeSettings} from "./shapeSettings"; @@ -24,7 +26,9 @@ export const stores = { storePresentationInfo: new storePresentationInfo(), storePresentationSettings: new storePresentationSettings(), storeSlideSettings: new storeSlideSettings(), - storePalette: new storePalette() + storePalette: new storePalette(), + storeTextSettings: new storeTextSettings(), + storeShapeSettings: new storeShapeSettings() // storeTextSettings: new storeTextSettings(), // storeParagraphSettings: new storeParagraphSettings(), // storeShapeSettings: new storeShapeSettings(), diff --git a/apps/presentationeditor/mobile/src/store/shapeSettings.js b/apps/presentationeditor/mobile/src/store/shapeSettings.js new file mode 100644 index 000000000..d119dd7da --- /dev/null +++ b/apps/presentationeditor/mobile/src/store/shapeSettings.js @@ -0,0 +1,224 @@ +import {action, observable, computed} from 'mobx'; + +export class storeShapeSettings { + + getStyleGroups () { + const styles = [ + { + title: 'Text', + thumb: 'shape-01.svg', + type: 'textRect' + }, + { + title: 'Line', + thumb: 'shape-02.svg', + type: 'line' + }, + { + title: 'Line with arrow', + thumb: 'shape-03.svg', + type: 'lineWithArrow' + }, + { + title: 'Line with two arrows', + thumb: 'shape-04.svg', + type: 'lineWithTwoArrows' + }, + { + title: 'Rect', + thumb: 'shape-05.svg', + type: 'rect' + }, + { + title: 'Hexagon', + thumb: 'shape-06.svg', + type: 'hexagon' + }, + { + title: 'Round rect', + thumb: 'shape-07.svg', + type: 'roundRect' + }, + { + title: 'Ellipse', + thumb: 'shape-08.svg', + type: 'ellipse' + }, + { + title: 'Triangle', + thumb: 'shape-09.svg', + type: 'triangle' + }, + { + title: 'Triangle', + thumb: 'shape-10.svg', + type: 'rtTriangle' + }, + { + title: 'Trapezoid', + thumb: 'shape-11.svg', + type: 'trapezoid' + }, + { + title: 'Diamond', + thumb: 'shape-12.svg', + type: 'diamond' + }, + { + title: 'Right arrow', + thumb: 'shape-13.svg', + type: 'rightArrow' + }, + { + title: 'Left-right arrow', + thumb: 'shape-14.svg', + type: 'leftRightArrow' + }, + { + title: 'Left arrow callout', + thumb: 'shape-15.svg', + type: 'leftArrow' + }, + { + title: 'Right arrow callout', + thumb: 'shape-16.svg', + type: 'bentUpArrow' + }, + { + title: 'Flow chart off page connector', + thumb: 'shape-17.svg', + type: 'flowChartOffpageConnector' + }, + { + title: 'Heart', + thumb: 'shape-18.svg', + type: 'heart' + }, + { + title: 'Math minus', + thumb: 'shape-19.svg', + type: 'mathMinus' + }, + { + title: 'Math plus', + thumb: 'shape-20.svg', + type: 'mathPlus' + }, + { + title: 'Parallelogram', + thumb: 'shape-21.svg', + type: 'parallelogram' + }, + { + title: 'Wedge rect callout', + thumb: 'shape-22.svg', + type: 'wedgeRectCallout' + }, + { + title: 'Wedge ellipse callout', + thumb: 'shape-23.svg', + type: 'wedgeEllipseCallout' + }, + { + title: 'Cloud callout', + thumb: 'shape-24.svg', + type: 'cloudCallout' + } + ]; + const groups = []; + let i = 0; + for (let row=0; row _sizes.length - 1) return _sizes[_sizes.length - 1]; + return _sizes[index]; + }, + + indexSizeByValue: function (value) { + let index = 0; + _sizes.forEach((size, idx) => { + if (Math.abs(size - value) < 0.25) { + index = idx; + } + }); + return index; + }, + + sizeByValue: function (value) { + return _sizes[this.indexSizeByValue(value)]; + } + } + } + +} \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/store/textSettings.js b/apps/presentationeditor/mobile/src/store/textSettings.js new file mode 100644 index 000000000..bc543b916 --- /dev/null +++ b/apps/presentationeditor/mobile/src/store/textSettings.js @@ -0,0 +1,153 @@ +import {action, observable, computed} from 'mobx'; + +export class storeTextSettings { + + @observable fontsArray = []; + @observable fontName = ''; + @observable fontSize = undefined; + @observable isBold = false; + @observable isItalic = false; + @observable isUnderline = false; + @observable isStrikethrough = false; + @observable typeBaseline = undefined; + @observable listType = undefined; + @observable typeBullets = undefined; + @observable typeNumbers = undefined; + @observable paragraphAlign = undefined; + @observable paragraphValign = undefined; + @observable canIncreaseIndent = undefined; + @observable canDecreaseIndent = undefined; + @observable textColor = undefined; + @observable customTextColors = []; + @observable lineSpacing = undefined; + + @action initEditorFonts (fonts, select) { + let array = []; + for (let font of fonts) { + let fontId = font.asc_getFontId(); + array.push({ + id : fontId, + name : font.asc_getFontName(), + //displayValue: font.asc_getFontName(), + imgidx : font.asc_getFontThumbnail(), + type : font.asc_getFontType() + }); + } + this.fontsArray = array; + } + @action resetFontName (font) { + let name = (typeof font.get_Name) === "function" ? font.get_Name() : font.asc_getName(); + this.fontName = name; + } + @action resetFontSize (size) { + this.fontSize = size; + } + @action resetIsBold (isBold) { + this.isBold = isBold; + } + @action resetIsItalic (isItalic) { + this.isItalic = isItalic; + } + @action resetIsUnderline (isUnderline) { + this.isUnderline = isUnderline; + } + @action resetIsStrikeout (isStrikethrough) { + this.isStrikethrough = isStrikethrough; + } + + // Indent + + @action resetIncreaseIndent(value) { + this.canIncreaseIndent = value; + } + + @action resetDecreaseIndent(value) { + this.canDecreaseIndent = value; + } + + // vertical align + @action resetTypeBaseline (typeBaseline) { + this.typeBaseline = typeBaseline; + } + @computed get isSuperscript() { + return (this.typeBaseline === 1); + } + @computed get isSubscript() { + return (this.typeBaseline === 2); + } + + // bullets + @action resetListType (type) { + this.listType = type; + } + @action resetBullets (type) { + this.typeBullets = type; + } + @action resetNumbers (type) { + this.typeNumbers = type; + } + + @action resetParagraphAlign (align) { + let value; + switch (align) { + case 0: + value = 'right'; + break; + case 1: + value = 'left'; + break; + case 2: + value = 'center'; + break; + case 3: + value = 'just'; + break; + } + this.paragraphAlign = value; + } + + @action resetParagraphValign (align) { + let value; + switch (align) { + case 0: + value = 'bottom'; + break; + case 4: + value = 'top'; + break; + case 1: + value = 'center'; + break; + } + this.paragraphValign = value; + } + + @action resetTextColor (color) { + let value; + if (color) { + if (color.get_auto()) { + value = 'auto'; + } else { + if (color.get_type() == Asc.c_oAscColor.COLOR_TYPE_SCHEME) { + value = { + color: Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b()), + effectValue: color.get_value() + } + } else { + value = Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b()); + } + } + } + this.textColor = value; + } + + @action changeCustomTextColors (colors) { + this.customTextColors = colors; + } + + @action resetLineSpacing (vc) { + let line = (vc.get_Line() === null || vc.get_LineRule() === null || vc.get_LineRule() != 1) ? -1 : vc.get_Line(); + this.lineSpacing = line; + } + +} \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/view/edit/Edit.jsx b/apps/presentationeditor/mobile/src/view/edit/Edit.jsx index 795d2106c..35933ce37 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Edit.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Edit.jsx @@ -7,8 +7,10 @@ import {Device} from '../../../../../common/mobile/utils/device'; import EditSlideController from "../../controller/edit/EditSlide"; import EditTextController from "../../controller/edit/EditText"; +import EditShapeController from "../../controller/edit/EditShape"; import { Theme, Layout, Transition, Type, Effect, StyleFillColor, CustomFillColor } from './EditSlide'; - +import { PageTextFonts, PageTextFontColor, PageTextCustomFontColor, PageTextAddFormatting, PageTextBullets, PageTextNumbers, PageTextLineSpacing } from './EditText'; +import { PageShapeStyle, PageShapeStyleNoFill, PageReplaceContainer, PageReorderContainer, PageAlignContainer, PageShapeBorderColor, PageShapeCustomBorderColor, PageShapeCustomFillColor } from './EditShape'; //import EditShapeController from "../../controller/edit/EditShape"; //import EditImageController from "../../controller/edit/EditImage"; //import EditTableController from "../../controller/edit/EditTable"; @@ -43,7 +45,68 @@ const routes = [ { path: '/edit-custom-color/', component: CustomFillColor + }, + { + path: '/edit-text-fonts/', + component: PageTextFonts + }, + { + path: '/edit-text-font-color/', + component: PageTextFontColor + }, + { + path: '/edit-text-custom-font-color/', + component: PageTextCustomFontColor + }, + { + path: '/edit-text-add-formatting/', + component: PageTextAddFormatting + }, + { + path: '/edit-text-bullets/', + component: PageTextBullets + }, + { + path: '/edit-text-numbers/', + component: PageTextNumbers + }, + { + path: '/edit-text-line-spacing/', + component: PageTextLineSpacing + }, + { + path: '/edit-style-shape/', + component: PageShapeStyle + }, + { + path: '/edit-style-shape-no-fill/', + component: PageShapeStyleNoFill + }, + { + path: '/edit-replace-shape/', + component: PageReplaceContainer + }, + { + path: '/edit-reorder-shape', + component: PageReorderContainer + }, + { + path: '/edit-align-shape/', + component: PageAlignContainer + }, + { + path: '/edit-shape-border-color/', + component: PageShapeBorderColor + }, + { + path: '/edit-shape-custom-border-color/', + component: PageShapeCustomBorderColor + }, + { + path: '/edit-shape-custom-fill-color/', + component: PageShapeCustomFillColor } + ]; const EmptyEditLayout = () => { @@ -124,6 +187,13 @@ const EditTabs = props => { component: }) } + if (settings.indexOf('shape') > -1) { + editors.push({ + caption: _t.textShape, + id: 'edit-shape', + component: + }) + } /*if (settings.indexOf('table') > -1) { editors.push({ caption: _t.textTable, @@ -131,13 +201,6 @@ const EditTabs = props => { component: }) } - if (settings.indexOf('shape') > -1) { - editors.push({ - caption: _t.textShape, - id: 'edit-shape', - component: - }) - } if (settings.indexOf('image') > -1) { editors.push({ caption: _t.textImage, diff --git a/apps/presentationeditor/mobile/src/view/edit/EditShape.jsx b/apps/presentationeditor/mobile/src/view/edit/EditShape.jsx new file mode 100644 index 000000000..d4e03ef04 --- /dev/null +++ b/apps/presentationeditor/mobile/src/view/edit/EditShape.jsx @@ -0,0 +1,411 @@ +import React, {Fragment, useState} from 'react'; +import {observer, inject} from "mobx-react"; +import {f7, Page, Navbar, List, ListItem, Row, BlockTitle, Link, Toggle, Icon, View, NavRight, ListItemCell, Range, Button, Segmented, Tab, Tabs} from 'framework7-react'; +import { ThemeColorPalette, CustomColorPicker } from '../../../../../common/mobile/lib/component/ThemeColorPalette.jsx'; +import { useTranslation } from 'react-i18next'; +import {Device} from '../../../../../common/mobile/utils/device'; + +const EditShape = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const canFill = props.storeFocusObjects.shapeObject.get_CanFill(); + + return ( + + + {canFill ? + + : + + } + + + + + + {_t.textRemoveShape} + + + ) +}; + +const PaletteFill = inject("storeFocusObjects", "storeShapeSettings", "storePalette")(observer(props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const storeShapeSettings = props.storeShapeSettings; + const shapeObject = props.storeFocusObjects.shapeObject; + const curFillColor = storeShapeSettings.fillColor ? storeShapeSettings.fillColor : storeShapeSettings.getFillColor(shapeObject); + const customColors = props.storePalette.customColors; + + const changeColor = (color, effectId, effectValue) => { + if (color !== 'empty') { + if (effectId !==undefined ) { + const newColor = {color: color, effectId: effectId, effectValue: effectValue}; + props.onFillColor(newColor); + storeShapeSettings.setFillColor(newColor); + } else { + props.onFillColor(color); + storeShapeSettings.setFillColor(color); + } + } else { + // open custom color menu + props.f7router.navigate('/edit-shape-custom-fill-color/'); + } + }; + + return ( + + + + + + + ) +})); + +const PageStyle = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const storeShapeSettings = props.storeShapeSettings; + const shapeObject = props.storeFocusObjects.shapeObject; + const stroke = shapeObject.get_stroke(); + + // Init border size + + const borderSizeTransform = storeShapeSettings.borderSizeTransform(); + const borderSize = stroke.get_width() * 72.0 / 25.4; + const borderType = stroke.get_type(); + const displayBorderSize = (borderType == Asc.c_oAscStrokeType.STROKE_NONE) ? 0 : borderSizeTransform.indexSizeByValue(borderSize); + const displayTextBorderSize = (borderType == Asc.c_oAscStrokeType.STROKE_NONE) ? 0 : borderSizeTransform.sizeByValue(borderSize); + const [stateBorderSize, setBorderSize] = useState(displayBorderSize); + const [stateTextBorderSize, setTextBorderSize] = useState(displayTextBorderSize); + + // Init border color + + const borderColor = !storeShapeSettings.borderColorView ? storeShapeSettings.initBorderColorView(shapeObject) : storeShapeSettings.borderColorView; + const displayBorderColor = borderColor !== 'transparent' ? `#${(typeof borderColor === "object" ? borderColor.color : borderColor)}` : borderColor; + + // Init opacity + + const transparent = shapeObject.get_fill().asc_getTransparent(); + const opacity = transparent !== null && transparent !== undefined ? transparent / 2.55 : 100; + const [stateOpacity, setOpacity] = useState(Math.round(opacity)); + + return ( + + + + {_t.textFill} + {_t.textBorder} + {_t.textEffects} + + + + + + + + + + {_t.textSize} + + {setBorderSize(value); setTextBorderSize(borderSizeTransform.sizeByIndex(value));}} + onRangeChanged={(value) => {props.onBorderSize(borderSizeTransform.sizeByIndex(value))}} + > + + + {stateTextBorderSize + ' ' + Common.Utils.Metric.getMetricName(Common.Utils.Metric.c_MetricUnits.pt)} + + + + + + + + + + + {_t.textOpacity} + + {setOpacity(value)}} + onRangeChanged={(value) => {props.onOpacity(value)}} + > + + + {stateOpacity + ' %'} + + + + + + + ) +}; + +const PageCustomFillColor = props => { + const { t } = useTranslation(); + const _t = t('Edit', {returnObjects: true}); + let fillColor = props.storeShapeSettings.fillColor; + + if (typeof fillColor === 'object') { + fillColor = fillColor.color; + } + + const onAddNewColor = (colors, color) => { + props.storePalette.changeCustomColors(colors); + props.onFillColor(color); + props.storeShapeSettings.setFillColor(color); + props.f7router.back(); + }; + + return( + + + + + ) +}; + +const PageStyleNoFill = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const storeShapeSettings = props.storeShapeSettings; + const shapeObject = props.storeFocusObjects.shapeObject; + const stroke = shapeObject.get_stroke(); + + // Init border size + + const borderSizeTransform = storeShapeSettings.borderSizeTransform(); + const borderSize = stroke.get_width() * 72.0 / 25.4; + const borderType = stroke.get_type(); + const displayBorderSize = (borderType == Asc.c_oAscStrokeType.STROKE_NONE) ? 0 : borderSizeTransform.indexSizeByValue(borderSize); + const displayTextBorderSize = (borderType == Asc.c_oAscStrokeType.STROKE_NONE) ? 0 : borderSizeTransform.sizeByValue(borderSize); + const [stateBorderSize, setBorderSize] = useState(displayBorderSize); + const [stateTextBorderSize, setTextBorderSize] = useState(displayTextBorderSize); + + // Init border color + + const borderColor = !storeShapeSettings.borderColorView ? storeShapeSettings.initBorderColorView(shapeObject) : storeShapeSettings.borderColorView; + const displayBorderColor = borderColor !== 'transparent' ? `#${(typeof borderColor === "object" ? borderColor.color : borderColor)}` : borderColor; + + return ( + + + + + {_t.textSize} + + {setBorderSize(value); setTextBorderSize(borderSizeTransform.sizeByIndex(value));}} + onRangeChanged={(value) => {props.onBorderSize(borderSizeTransform.sizeByIndex(value))}} + > + + + {stateTextBorderSize + ' ' + Common.Utils.Metric.getMetricName(Common.Utils.Metric.c_MetricUnits.pt)} + + + + + + + + ) +}; + +const PageReplace = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const storeShapeSettings = props.storeShapeSettings; + let shapes = storeShapeSettings.getStyleGroups(); + shapes.splice(0, 1); // Remove line shapes + + return ( + + + {shapes.map((row, indexRow) => { + return ( + + {row.map((shape, index) => { + return ( + {props.onReplace(shape.type)}}> + + + + ) + })} + + ) + })} + + ) +}; + +const PageReorder = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + + return ( + + + + {props.onReorder('all-up')}} className='no-indicator'> + + + {props.onReorder('all-down')}} className='no-indicator'> + + + {props.onReorder('move-up')}} className='no-indicator'> + + + {props.onReorder('move-down')}} className='no-indicator'> + + + + + ) +}; + +const PageAlign = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + + return ( + + + + {props.onAlign('align-left')}} className='no-indicator'> + + + {props.onAlign('align-center')}} className='no-indicator'> + + + {props.onAlign('align-right')}} className='no-indicator'> + + + {props.onAlign('align-top')}} className='no-indicator'> + + + {props.onAlign('align-middle')}} className='no-indicator'> + + + {props.onAlign('align-bottom')}} className='no-indicator'> + + + + + {props.onAlign('distrib-hor')}} className='no-indicator'> + + + {props.onAlign('distrib-vert')}} className='no-indicator'> + + + + + ) +} + +const PageBorderColor = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const borderColor = props.storeShapeSettings.borderColorView; + const customColors = props.storePalette.customColors; + + const changeColor = (color, effectId, effectValue) => { + if (color !== 'empty') { + if (effectId !==undefined ) { + const newColor = {color: color, effectId: effectId, effectValue: effectValue}; + props.onBorderColor(newColor); + props.storeShapeSettings.setBorderColor(newColor); + } else { + props.onBorderColor(color); + props.storeShapeSettings.setBorderColor(color); + } + } else { + // open custom color menu + props.f7router.navigate('/edit-shape-custom-border-color/'); + } + }; + return ( + + + + + + + + ) +}; + +const PageCustomBorderColor = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + let borderColor = props.storeShapeSettings.borderColorView; + if (typeof borderColor === 'object') { + borderColor = borderColor.color; + } + const onAddNewColor = (colors, color) => { + props.storePalette.changeCustomColors(colors); + props.onBorderColor(color); + props.storeShapeSettings.setBorderColor(color); + props.f7router.back(); + }; + return ( + + + + + ) +}; + +const EditShapeContainer = inject("storeShapeSettings", "storeFocusObjects")(observer(EditShape)); +const PageShapeStyle = inject("storeFocusObjects", "storeShapeSettings")(observer(PageStyle)); +const PageShapeStyleNoFill = inject("storeFocusObjects", "storeShapeSettings")(observer(PageStyleNoFill)); +const PageShapeCustomFillColor = inject("storeFocusObjects", "storeShapeSettings", "storePalette")(observer(PageCustomFillColor)); +const PageReplaceContainer = inject("storeShapeSettings","storeFocusObjects")(observer(PageReplace)); +const PageReorderContainer = inject("storeFocusObjects")(observer(PageReorder)); +const PageAlignContainer = inject("storeFocusObjects")(observer(PageAlign)); +const PageShapeBorderColor = inject("storeShapeSettings", "storePalette")(observer(PageBorderColor)); +const PageShapeCustomBorderColor = inject("storeShapeSettings", "storePalette")(observer(PageCustomBorderColor)); + +export { + EditShapeContainer as EditShape, + PageShapeStyle, + PageShapeStyleNoFill, + PageReplaceContainer, + PageReorderContainer, + PageAlignContainer, + PageShapeBorderColor, + PageShapeCustomBorderColor, + PageShapeCustomFillColor +} \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx b/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx index fdfd5ea0a..2cbdf19f1 100644 --- a/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx @@ -1,9 +1,9 @@ import React, {Fragment, useState} from 'react'; import {observer, inject} from "mobx-react"; -import {f7, Page, Navbar, List, ListItem, Row, BlockTitle, Link, Toggle, Icon, View, NavRight, ListItemCell, Range} from 'framework7-react'; +import {f7, Page, Navbar, List, ListItem, Row, BlockTitle, Link, Toggle, Icon, View, NavRight, ListItemCell, Range, Button, Segmented} from 'framework7-react'; import { ThemeColorPalette, CustomColorPicker } from '../../../../../common/mobile/lib/component/ThemeColorPalette.jsx'; import { useTranslation } from 'react-i18next'; -// import {Device} from '../../../../../common/mobile/utils/device'; +import {Device} from '../../../../../common/mobile/utils/device'; const EditSlide = props => { const { t } = useTranslation(); @@ -31,9 +31,9 @@ const EditSlide = props => { onFillColor: props.onFillColor }}> - - {_t.textDuplicateSlide} - {_t.textDeleteSlide} + + {_t.textDuplicateSlide} + {_t.textDeleteSlide} ) @@ -129,6 +129,7 @@ const PageLayout = props => { const PageTransition = props => { const { t } = useTranslation(); const _t = t("View.Edit", { returnObjects: true }); + const isAndroid = Device.android; const _arrEffect = [ {displayValue: _t.textNone, value: Asc.c_oAscSlideTransitionTypes.None}, {displayValue: _t.textFade, value: Asc.c_oAscSlideTransitionTypes.Fade}, @@ -257,20 +258,27 @@ const PageTransition = props => { }}> - + {!isAndroid && {(_effectDuration !== null && _effectDuration !== undefined) ? (parseInt(_effectDuration / 1000.) + ' ' + _t.textSec) : ''} - - { + } + + + { let duration = parseInt(_effectDuration / 1000); duration = Math.max(0, --duration); props.changeDuration(duration); - }}>- - { + }}> + {isAndroid ? : ' - '} + + {isAndroid && {(_effectDuration !== null && _effectDuration !== undefined) ? (parseInt(_effectDuration / 1000.) + ' ' + _t.textSec) : ''}} + { let duration = parseInt(_effectDuration / 1000); duration = Math.min(300, ++duration); props.changeDuration(duration); - }}>+ - + }}> + {isAndroid ? : ' + '} + + @@ -297,8 +305,8 @@ const PageTransition = props => { - - {_t.textApplyAll} + + {_t.textApplyAll} ); diff --git a/apps/presentationeditor/mobile/src/view/edit/EditText.jsx b/apps/presentationeditor/mobile/src/view/edit/EditText.jsx index 96a0fd91d..f3f98adc1 100644 --- a/apps/presentationeditor/mobile/src/view/edit/EditText.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/EditText.jsx @@ -1,15 +1,470 @@ import React, {Fragment, useState} from 'react'; import {observer, inject} from "mobx-react"; -import {Page, Navbar, List, ListItem, ListButton, Row, BlockTitle, Range, Toggle, Icon} from 'framework7-react'; +import {f7, List, ListItem, Icon, Row, Button, Page, Navbar, Segmented, BlockTitle} from 'framework7-react'; import { useTranslation } from 'react-i18next'; import {Device} from '../../../../../common/mobile/utils/device'; +import { ThemeColorPalette, CustomColorPicker } from '../../../../../common/mobile/lib/component/ThemeColorPalette.jsx'; const EditText = props => { + const isAndroid = Device.android; + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const metricText = Common.Utils.Metric.getCurrentMetricName(); + const storeTextSettings = props.storeTextSettings; + const storeFocusObjects = props.storeFocusObjects; + const fontName = storeTextSettings.fontName || _t.textFonts; + const fontSize = storeTextSettings.fontSize; + const fontColor = storeTextSettings.textColor; + const displaySize = typeof fontSize === 'undefined' ? _t.textAuto : fontSize + ' ' + _t.textPt; + const isBold = storeTextSettings.isBold; + const isItalic = storeTextSettings.isItalic; + const isUnderline = storeTextSettings.isUnderline; + const isStrikethrough = storeTextSettings.isStrikethrough; + const paragraphAlign = storeTextSettings.paragraphAlign; + const paragraphValign = storeTextSettings.paragraphValign; + const canIncreaseIndent = storeTextSettings.canIncreaseIndent; + const canDecreaseIndent = storeTextSettings.canDecreaseIndent; + const paragraphObj = storeFocusObjects.paragraphObject; + let spaceBefore; + let spaceAfter; + + if(paragraphObj) { + spaceBefore = paragraphObj.get_Spacing().get_Before() < 0 ? paragraphObj.get_Spacing().get_Before() : Common.Utils.Metric.fnRecalcFromMM(paragraphObj.get_Spacing().get_Before()); + spaceAfter = paragraphObj.get_Spacing().get_After() < 0 ? paragraphObj.get_Spacing().get_After() : Common.Utils.Metric.fnRecalcFromMM(paragraphObj.get_Spacing().get_After()); + } + + const displayBefore = spaceBefore && spaceBefore < 0 ? _t.textAuto : spaceBefore + ' ' + metricText; + const displayAfter = spaceAfter && spaceAfter < 0 ? _t.textAuto : spaceAfter + ' ' + metricText; + + const fontColorPreview = fontColor !== 'auto' ? + : + ; + return ( - + + + + + { props.toggleBold(!isBold)}}>B + {props.toggleItalic(!isItalic)}}>I + {props.toggleUnderline(!isUnderline)}} style={{textDecoration: "underline"}}>U + {props.toggleStrikethrough(!isStrikethrough)}} style={{textDecoration: "line-through"}}>S + + + + {!isAndroid ? + {fontColorPreview} : + fontColorPreview + } + + + {!isAndroid && } + + + {paragraphObj ? ( + + + + + {props.onParagraphAlign('left')}}> + + + {props.onParagraphAlign('center')}}> + + + {props.onParagraphAlign('right')}}> + + + {props.onParagraphAlign('just')}}> + + + + + + + {props.onParagraphValign('top')}}> + + + {props.onParagraphValign('center')}}> + + + {props.onParagraphValign('bottom')}}> + + + + + + + {props.onParagraphMove('left')}}> + + + {props.onParagraphMove('right')}}> + + + + + + {!isAndroid && } + + + {!isAndroid && } + + + {!isAndroid && } + + + {_t.textDistanceFromText} + + + {!isAndroid && {displayBefore}} + + + {props.onDistanceBefore(spaceBefore, true)}}> + {isAndroid ? : ' - '} + + {isAndroid && {displayBefore}} + {props.onDistanceBefore(spaceBefore, false)}}> + {isAndroid ? : ' + '} + + + + + + {!isAndroid && {displayAfter}} + + + {props.onDistanceAfter(spaceAfter, true)}}> + {isAndroid ? : ' - '} + + {isAndroid && {displayAfter}} + {props.onDistanceAfter(spaceAfter, false)}}> + {isAndroid ? : ' + '} + + + + + + + ) : null} + ); +}; + +const PageFonts = props => { + const isAndroid = Device.android; + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const storeTextSettings = props.storeTextSettings; + const size = storeTextSettings.fontSize; + const displaySize = typeof size === 'undefined' ? _t.textAuto : size + ' ' + _t.textPt; + const curFontName = storeTextSettings.fontName; + const fonts = storeTextSettings.fontsArray; + + const [vlFonts, setVlFonts] = useState({ + vlData: { + items: [], + } + }); + + const renderExternal = (vl, vlData) => { + setVlFonts((prevState) => { + let fonts = [...prevState.vlData.items]; + fonts.splice(vlData.fromIndex, vlData.toIndex, ...vlData.items); + return {vlData: { + items: fonts, + }}; + }); + }; + + return ( + + + + + {!isAndroid && {displaySize}} + + + {props.changeFontSize(size, true)}}> + {isAndroid ? : ' - '} + + {isAndroid && {displaySize}} + {props.changeFontSize(size, false)}}> + {isAndroid ? : ' + '} + + + + + + {_t.textFonts} + + + {vlFonts.vlData.items.map((item, index) => ( + {props.changeFontFamily(item.name)}} + > + ))} + + + + ); +}; + +const PageFontColor = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const textColor = props.storeTextSettings.textColor; + const customColors = props.storePalette.customColors; + + const changeColor = (color, effectId) => { + if (color !== 'empty') { + if (effectId !== undefined ) { + props.onTextColor({color: color, effectId: effectId}); + } else { + props.onTextColor(color); + } + } else { + // open custom color menu + props.f7router.navigate('/edit-text-custom-font-color/'); + } + }; + + return ( + + + + + + + + ); +}; + +const PageCustomFontColor = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const store = props.storeTextSettings; + let textColor = store.textColor; + + if (typeof textColor === 'object') { + textColor = textColor.color; + } + + const autoColor = textColor === 'auto' ? window.getComputedStyle(document.getElementById('font-color-auto')).backgroundColor : null; + + const onAddNewColor = (colors, color) => { + props.storePalette.changeCustomColors(colors); + props.onTextColor(color); + props.f7router.back(); + }; + return( + + + + ) }; -export {EditText}; \ No newline at end of file +const PageAdditionalFormatting = props => { + const isAndroid = Device.android; + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const storeTextSettings = props.storeTextSettings; + const storeFocusObjects = props.storeFocusObjects; + const paragraphObj = storeFocusObjects.paragraphObject; + const isSuperscript = storeTextSettings.isSuperscript; + const isSubscript = storeTextSettings.isSubscript; + let isStrikeout = false; + let isDStrikeout = false; + let isSmallCaps = false; + let isAllCaps = false; + let letterSpacing = 0; + + if(paragraphObj) { + isStrikeout = paragraphObj.get_Strikeout(); + isDStrikeout = paragraphObj.get_DStrikeout(); + isSmallCaps = paragraphObj.get_SmallCaps(); + isAllCaps = paragraphObj.get_AllCaps(); + letterSpacing = (paragraphObj.get_TextSpacing() === null || paragraphObj.get_TextSpacing() === undefined) ? paragraphObj.get_TextSpacing() : Common.Utils.Metric.fnRecalcFromMM(paragraphObj.get_TextSpacing()); + } + + return ( + + + + {props.onAdditionalStrikethrough('strikethrough', !isStrikeout)}}/> + {props.onAdditionalStrikethrough('dbStrikethrough', !isDStrikeout)}}/> + {props.onAdditionalScript('superscript', !isSuperscript)}}/> + {props.onAdditionalScript('subscript', !isSubscript)}}/> + {props.onAdditionalCaps('small', !isSmallCaps)}}/> + {props.onAdditionalCaps('all', !isAllCaps)}}/> + + + + {!isAndroid && {letterSpacing + ' ' + Common.Utils.Metric.getCurrentMetricName()}} + + + {props.changeLetterSpacing(letterSpacing, true)}}> + {isAndroid ? : ' - '} + + {isAndroid && {letterSpacing + ' ' + Common.Utils.Metric.getCurrentMetricName()}} + {props.changeLetterSpacing(letterSpacing, false)}}> + {isAndroid ? : ' + '} + + + + + + + ) +}; + +const PageBullets = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const bulletArrays = [ + [ + {type: -1, thumb: ''}, + {type: 1, thumb: 'bullet-01.png'}, + {type: 2, thumb: 'bullet-02.png'}, + {type: 3, thumb: 'bullet-03.png'} + ], + [ + {type: 4, thumb: 'bullet-04.png'}, + {type: 5, thumb: 'bullet-05.png'}, + {type: 6, thumb: 'bullet-06.png'}, + {type: 7, thumb: 'bullet-07.png'} + ] + ]; + const storeTextSettings = props.storeTextSettings; + const typeBullets = storeTextSettings.typeBullets; + + return ( + + + {bulletArrays.map((bullets, index) => ( + + {bullets.map((bullet) => ( + {props.onBullet(bullet.type)}}> + {bullet.thumb.length < 1 ? + + {_t.textNone} + : + + } + + ))} + + ))} + + ) +}; + +const PageNumbers = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const numberArrays = [ + [ + {type: -1, thumb: ''}, + {type: 4, thumb: 'number-01.png'}, + {type: 5, thumb: 'number-02.png'}, + {type: 6, thumb: 'number-03.png'} + ], + [ + {type: 1, thumb: 'number-04.png'}, + {type: 2, thumb: 'number-05.png'}, + {type: 3, thumb: 'number-06.png'}, + {type: 7, thumb: 'number-07.png'} + ] + ]; + + const storeTextSettings = props.storeTextSettings; + const typeNumbers = storeTextSettings.typeNumbers; + + return ( + + + {numberArrays.map((numbers, index) => ( + + {numbers.map((number) => ( + {props.onNumber(number.type)}}> + {number.thumb.length < 1 ? + + {_t.textNone} + : + + } + + ))} + + ))} + + ) +}; + +const PageLineSpacing = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const storeTextSettings = props.storeTextSettings; + const lineSpacing = storeTextSettings.lineSpacing; + + return ( + + + + {props.onLineSpacing(1.0)}}> + {props.onLineSpacing(1.15)}}> + {props.onLineSpacing(1.5)}}> + {props.onLineSpacing(2.0)}}> + {props.onLineSpacing(2.5)}}> + {props.onLineSpacing(3.0)}}> + + + ) +}; + +const EditTextContainer = inject("storeTextSettings", "storeFocusObjects")(observer(EditText)); +const PageTextFonts = inject("storeTextSettings", "storeFocusObjects")(observer(PageFonts)); +const PageTextFontColor = inject("storeTextSettings", "storePalette")(observer(PageFontColor)); +const PageTextCustomFontColor = inject("storeTextSettings", "storePalette")(observer(PageCustomFontColor)); +const PageTextAddFormatting = inject("storeTextSettings", "storeFocusObjects")(observer(PageAdditionalFormatting)); +const PageTextBullets = inject("storeTextSettings")(observer(PageBullets)); +const PageTextNumbers = inject("storeTextSettings")(observer(PageNumbers)); +const PageTextLineSpacing = inject("storeTextSettings")(observer(PageLineSpacing)); + +export { + EditTextContainer as EditText, + PageTextFonts, + PageTextFontColor, + PageTextCustomFontColor, + PageTextAddFormatting, + PageTextBullets, + PageTextNumbers, + PageTextLineSpacing +}; \ No newline at end of file
- { +