From db867796e050bca95763c4bbf51ce03b6e0a0c62 Mon Sep 17 00:00:00 2001 From: SergeyEzhin Date: Tue, 22 Dec 2020 20:52:29 +0300 Subject: [PATCH 01/17] [PE mobile] Make layout settings --- apps/presentationeditor/mobile/locale/en.json | 7 +- .../mobile/src/controller/Main.jsx | 13 ++- .../mobile/src/controller/edit/EditSlide.jsx | 3 +- .../mobile/src/controller/edit/Layout.jsx | 16 ++++ .../mobile/src/less/app-ios.less | 80 ++++++++++++------ .../mobile/src/less/app-material.less | 82 +++++++++++++------ .../mobile/src/store/layout.js | 11 +++ .../mobile/src/store/mainStore.js | 4 +- .../mobile/src/view/edit/Edit.jsx | 7 +- .../mobile/src/view/edit/EditSlide.jsx | 13 ++- .../mobile/src/view/edit/EditText.jsx | 2 +- .../mobile/src/view/edit/Layout.jsx | 34 ++++++++ 12 files changed, 216 insertions(+), 56 deletions(-) create mode 100644 apps/presentationeditor/mobile/src/controller/edit/Layout.jsx create mode 100644 apps/presentationeditor/mobile/src/store/layout.js create mode 100644 apps/presentationeditor/mobile/src/view/edit/Layout.jsx diff --git a/apps/presentationeditor/mobile/locale/en.json b/apps/presentationeditor/mobile/locale/en.json index d4ae0d7d0..2b0bdb7b8 100644 --- a/apps/presentationeditor/mobile/locale/en.json +++ b/apps/presentationeditor/mobile/locale/en.json @@ -81,7 +81,12 @@ "textShape": "Shape", "textImage": "Image", "textChart": "Chart", - "textHyperlink": "Hyperlink" + "textHyperlink": "Hyperlink", + "textTheme": "Theme", + "textStyle": "Style", + "textLayout": "Layout", + "textTransition": "Transition", + "textBack": "Back" } } } \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx index 00beac336..634dcb24e 100644 --- a/apps/presentationeditor/mobile/src/controller/Main.jsx +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -4,7 +4,7 @@ import { inject } from "mobx-react"; import { withTranslation } from 'react-i18next'; import CollaborationController from '../../../../common/mobile/lib/controller/Collaboration.jsx' -@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings") +@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeLayout") class MainController extends Component { constructor(props) { super(props) @@ -195,6 +195,17 @@ class MainController extends Component { this.api.asc_registerCallback('asc_onFocusObject', objects => { storeFocusObjects.resetFocusObjects(objects); }); + + this.api.asc_registerCallback('asc_onUpdateThemeIndex', themeId => { + console.log(themeId); + }); + + const storeLayout = this.props.storeLayout; + + this.api.asc_registerCallback('asc_onUpdateLayout', (layouts) => { + console.log(layouts); + storeLayout.addArrayLayouts(layouts); + }); } _onDocumentContentReady() { diff --git a/apps/presentationeditor/mobile/src/controller/edit/EditSlide.jsx b/apps/presentationeditor/mobile/src/controller/edit/EditSlide.jsx index 67aae4433..8843e39b8 100644 --- a/apps/presentationeditor/mobile/src/controller/edit/EditSlide.jsx +++ b/apps/presentationeditor/mobile/src/controller/edit/EditSlide.jsx @@ -11,8 +11,7 @@ class EditSlideController extends Component { } render () { return ( - + ) } } diff --git a/apps/presentationeditor/mobile/src/controller/edit/Layout.jsx b/apps/presentationeditor/mobile/src/controller/edit/Layout.jsx new file mode 100644 index 000000000..a4c9c3dc2 --- /dev/null +++ b/apps/presentationeditor/mobile/src/controller/edit/Layout.jsx @@ -0,0 +1,16 @@ +import React, { Component } from "react"; +import Layout from "../../view/edit/Layout"; + +class LayoutController extends Component { + constructor(props) { + super(props); + } + + render() { + return ( + + ); + } +} + +export default LayoutController; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/less/app-ios.less b/apps/presentationeditor/mobile/src/less/app-ios.less index 55a23a31e..08d52715d 100644 --- a/apps/presentationeditor/mobile/src/less/app-ios.less +++ b/apps/presentationeditor/mobile/src/less/app-ios.less @@ -1,29 +1,63 @@ .device-ios { + // Color Schemes + + .color-schemes-menu { + cursor: pointer; + display: block; + background-color: #fff; + .item-inner { + justify-content: flex-start; + } + .color-schema-block { + display: flex; + } + .color { + min-width: 26px; + min-height: 26px; + margin: 0 2px 0 0; + box-shadow: 0 0 0 1px rgba(0,0,0,.15) inset; + } + .item-title { + margin-left: 20px; + color: #212121; + } + } + + + // Layout + + .list-layouts { + margin: auto; + ul { + display: flex; + flex-wrap: wrap; + justify-content: space-around; + } + li { + position: relative; + z-index: 1; + margin: 0; + margin-top: 12px; + img { + box-shadow: 0 0 0 1px rgba(0,0,0,.15); + } + } + li .item-inner:after { + display: none; + } + li.active .item-inner:after { + content: ''; + position: absolute; + width: 22px; + height: 22px; + right: -5px; + bottom: -5px; + background-repeat: no-repeat; + .encoded-svg-background(''); + } + } } -// Color Schemes - -.color-schemes-menu { - cursor: pointer; - display: block; - background-color: #fff; - .item-inner { - justify-content: flex-start; - } - .color-schema-block { - display: flex; - } - .color { - min-width: 26px; - min-height: 26px; - margin: 0 2px 0 0; - box-shadow: 0 0 0 1px rgba(0,0,0,.15) inset; - } - .item-title { - margin-left: 20px; - color: #212121; - } -} diff --git a/apps/presentationeditor/mobile/src/less/app-material.less b/apps/presentationeditor/mobile/src/less/app-material.less index 3a7fb97e7..8356510c0 100644 --- a/apps/presentationeditor/mobile/src/less/app-material.less +++ b/apps/presentationeditor/mobile/src/less/app-material.less @@ -21,28 +21,62 @@ align-items: center; width: auto; } + + + // Color Schemes + + .color-schemes-menu { + cursor: pointer; + display: block; + background-color: #fff; + .item-inner { + justify-content: flex-start; + } + .color-schema-block { + display: flex; + } + .color { + min-width: 26px; + min-height: 26px; + margin: 0 2px 0 0; + box-shadow: 0 0 0 1px rgba(0,0,0,.15) inset; + } + .item-title { + margin-left: 20px; + color: #212121; + } + } + + // Layout + + .list-layouts { + margin: auto; + ul { + display: flex; + flex-wrap: wrap; + justify-content: space-around; + } + li { + position: relative; + z-index: 1; + margin: 0; + margin-top: 12px; + img { + box-shadow: 0 0 0 1px rgba(0,0,0,.15); + } + } + li .item-inner:after { + display: none; + } + li.active .item-inner:after { + content: ''; + position: absolute; + width: 22px; + height: 22px; + right: -5px; + bottom: -5px; + background-repeat: no-repeat; + .encoded-svg-background(''); + } + } } - -// Color Schemes - -.color-schemes-menu { - cursor: pointer; - display: block; - background-color: #fff; - .item-inner { - justify-content: flex-start; - } - .color-schema-block { - display: flex; - } - .color { - min-width: 26px; - min-height: 26px; - margin: 0 2px 0 0; - box-shadow: 0 0 0 1px rgba(0,0,0,.15) inset; - } - .item-title { - margin-left: 20px; - color: #212121; - } -} \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/store/layout.js b/apps/presentationeditor/mobile/src/store/layout.js new file mode 100644 index 000000000..93e00b7e2 --- /dev/null +++ b/apps/presentationeditor/mobile/src/store/layout.js @@ -0,0 +1,11 @@ +import {action, observable} from 'mobx'; + +export class storeLayout { + + @observable arrayLayouts; + + @action addArrayLayouts(array) { + this.arrayLayouts = array; + } + +} \ 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 4db12d1fd..ceb746a37 100644 --- a/apps/presentationeditor/mobile/src/store/mainStore.js +++ b/apps/presentationeditor/mobile/src/store/mainStore.js @@ -6,6 +6,7 @@ import {storeUsers} from '../../../../common/mobile/lib/store/users'; import {storeApplicationSettings} from './applicationSettings'; import {storePresentationInfo} from './presentationInfo'; import {storePresentationSettings} from './presentationSettings'; +import { storeLayout } from './layout'; // import {storeTextSettings} from "./textSettings"; // import {storeParagraphSettings} from "./paragraphSettings"; // import {storeShapeSettings} from "./shapeSettings"; @@ -20,7 +21,8 @@ export const stores = { users: new storeUsers(), storeApplicationSettings: new storeApplicationSettings(), storePresentationInfo: new storePresentationInfo(), - storePresentationSettings: new storePresentationSettings() + storePresentationSettings: new storePresentationSettings(), + storeLayout: new storeLayout() // storeTextSettings: new storeTextSettings(), // storeParagraphSettings: new storeParagraphSettings(), // storeShapeSettings: new storeShapeSettings(), diff --git a/apps/presentationeditor/mobile/src/view/edit/Edit.jsx b/apps/presentationeditor/mobile/src/view/edit/Edit.jsx index 8c9ccd45c..1ff57fb59 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Edit.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Edit.jsx @@ -7,6 +7,7 @@ import {Device} from '../../../../../common/mobile/utils/device'; import EditSlideController from "../../controller/edit/EditSlide"; import EditTextController from "../../controller/edit/EditText"; +import LayoutController from "../../controller/edit/Layout"; //import EditShapeController from "../../controller/edit/EditShape"; //import EditImageController from "../../controller/edit/EditImage"; //import EditTableController from "../../controller/edit/EditTable"; @@ -14,7 +15,10 @@ import EditTextController from "../../controller/edit/EditText"; //import EditLinkController from "../../controller/edit/EditLink"; const routes = [ - + { + path: '/layout/', + component: LayoutController + } ]; const EmptyEditLayout = () => { @@ -73,6 +77,7 @@ const EditTabs = props => { const _t = t('View.Edit', {returnObjects: true}); const settings = props.storeFocusObjects.settings; + let editors = []; if (settings.length < 1) { editors.push({ diff --git a/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx b/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx index d9b7009b1..d342e3e9f 100644 --- a/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx @@ -1,13 +1,22 @@ 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 {Page, Navbar, List, ListItem, ListButton, Row, BlockTitle, Range, Toggle, Icon, View} from 'framework7-react'; +import {f7} from 'framework7-react'; import { useTranslation } from 'react-i18next'; import {Device} from '../../../../../common/mobile/utils/device'; const EditSlide = props => { + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + return ( - + + + + + + ) }; diff --git a/apps/presentationeditor/mobile/src/view/edit/EditText.jsx b/apps/presentationeditor/mobile/src/view/edit/EditText.jsx index 76cd8df00..96a0fd91d 100644 --- a/apps/presentationeditor/mobile/src/view/edit/EditText.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/EditText.jsx @@ -7,7 +7,7 @@ import {Device} from '../../../../../common/mobile/utils/device'; const EditText = props => { return ( - + ) }; diff --git a/apps/presentationeditor/mobile/src/view/edit/Layout.jsx b/apps/presentationeditor/mobile/src/view/edit/Layout.jsx new file mode 100644 index 000000000..bd111f555 --- /dev/null +++ b/apps/presentationeditor/mobile/src/view/edit/Layout.jsx @@ -0,0 +1,34 @@ +import React, {Fragment} from "react"; +import { observer, inject } from "mobx-react"; +import { Page, Navbar, List, ListItem, BlockTitle } from "framework7-react"; +import { useTranslation } from "react-i18next"; + +const PageLayout = props => { + const { t } = useTranslation(); + const _t = t("View.Edit", { returnObjects: true }); + const store = props.storeLayout; + const arrayLayouts = JSON.parse(JSON.stringify(store.arrayLayouts)); + console.log(arrayLayouts); + console.log(store); + + return ( + + + {arrayLayouts.length ? ( + + {arrayLayouts.map((elem, index) => { + return ( + + + + ) + })} + + ) : null} + + ); +}; + +const Layout = inject("storeLayout")(observer(PageLayout)); + +export default Layout; \ No newline at end of file From a9b9ec6c88b5d01b2ac3d498a57c1d55e75d2264 Mon Sep 17 00:00:00 2001 From: SergeyEzhin Date: Wed, 23 Dec 2020 18:39:32 +0300 Subject: [PATCH 02/17] [PE mobile] Almost maked layout settings --- .../mobile/src/controller/Main.jsx | 28 +++++++++++++------ .../mobile/src/controller/edit/Layout.jsx | 13 ++++++++- .../mobile/src/less/app-ios.less | 23 ++++++++++----- .../mobile/src/less/app-material.less | 23 ++++++++++----- .../mobile/src/store/layout.js | 5 ++++ .../mobile/src/view/edit/Layout.jsx | 27 +++++++++++++----- 6 files changed, 88 insertions(+), 31 deletions(-) diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx index 634dcb24e..d864e977e 100644 --- a/apps/presentationeditor/mobile/src/controller/Main.jsx +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -192,18 +192,28 @@ class MainController extends Component { // me.api.asc_registerCallback('asc_onMeta', _.bind(me.onMeta, me)); const storeFocusObjects = this.props.storeFocusObjects; - this.api.asc_registerCallback('asc_onFocusObject', objects => { - storeFocusObjects.resetFocusObjects(objects); - }); - - this.api.asc_registerCallback('asc_onUpdateThemeIndex', themeId => { - console.log(themeId); - }); - const storeLayout = this.props.storeLayout; + this.api.asc_registerCallback('asc_onFocusObject', objects => { + + console.log(objects); + storeFocusObjects.resetFocusObjects(objects); + + const settings = storeFocusObjects.settings; + console.log(settings); + + if(settings[0] === "slide") { + const slideObject = objects[0].get_ObjectValue(); + storeLayout.changeSlideLayoutIndex(slideObject.get_LayoutIndex()); + } + }); + + // this.api.asc_registerCallback('asc_onUpdateThemeIndex', themeId => { + // console.log(themeId); + // }); + this.api.asc_registerCallback('asc_onUpdateLayout', (layouts) => { - console.log(layouts); + // console.log(layouts); storeLayout.addArrayLayouts(layouts); }); } diff --git a/apps/presentationeditor/mobile/src/controller/edit/Layout.jsx b/apps/presentationeditor/mobile/src/controller/edit/Layout.jsx index a4c9c3dc2..572b47a70 100644 --- a/apps/presentationeditor/mobile/src/controller/edit/Layout.jsx +++ b/apps/presentationeditor/mobile/src/controller/edit/Layout.jsx @@ -6,9 +6,20 @@ class LayoutController extends Component { super(props); } + onLayoutClick(index) { + const api = Common.EditorApi.get(); + let props = new Asc.CAscSlideProps(); + console.log(api); + + props.LayoutIndex = index; + api.SetSlideProps(props); + + console.log(props); + } + render() { return ( - + ); } } diff --git a/apps/presentationeditor/mobile/src/less/app-ios.less b/apps/presentationeditor/mobile/src/less/app-ios.less index 08d52715d..62aa74165 100644 --- a/apps/presentationeditor/mobile/src/less/app-ios.less +++ b/apps/presentationeditor/mobile/src/less/app-ios.less @@ -28,8 +28,10 @@ // Layout - .list-layouts { - margin: auto; + .slide-layout { + .list { + margin: auto; + } ul { display: flex; flex-wrap: wrap; @@ -38,25 +40,32 @@ li { position: relative; z-index: 1; - margin: 0; margin-top: 12px; img { box-shadow: 0 0 0 1px rgba(0,0,0,.15); } } - li .item-inner:after { + .item-inner { + padding-top: 0; + } + .item-inner:after { display: none; } - li.active .item-inner:after { + .item-inner:before { + opacity: 0; content: ''; position: absolute; width: 22px; height: 22px; - right: -5px; - bottom: -5px; + right: 11px; + bottom: 0; + z-index: 1; background-repeat: no-repeat; .encoded-svg-background(''); } + .active .item-inner:before { + opacity: 1; + } } } diff --git a/apps/presentationeditor/mobile/src/less/app-material.less b/apps/presentationeditor/mobile/src/less/app-material.less index 8356510c0..8367a79ab 100644 --- a/apps/presentationeditor/mobile/src/less/app-material.less +++ b/apps/presentationeditor/mobile/src/less/app-material.less @@ -49,8 +49,10 @@ // Layout - .list-layouts { - margin: auto; + .slide-layout { + .list { + margin: auto; + } ul { display: flex; flex-wrap: wrap; @@ -59,24 +61,31 @@ li { position: relative; z-index: 1; - margin: 0; margin-top: 12px; img { box-shadow: 0 0 0 1px rgba(0,0,0,.15); } } - li .item-inner:after { + .item-inner { + padding-top: 0; + } + .item-inner:after { display: none; } - li.active .item-inner:after { + .item-inner:before { + opacity: 0; content: ''; position: absolute; width: 22px; height: 22px; - right: -5px; - bottom: -5px; + right: 11px; + bottom: 0; + z-index: 1; background-repeat: no-repeat; .encoded-svg-background(''); } + .active .item-inner:before { + opacity: 1; + } } } diff --git a/apps/presentationeditor/mobile/src/store/layout.js b/apps/presentationeditor/mobile/src/store/layout.js index 93e00b7e2..4992a5b79 100644 --- a/apps/presentationeditor/mobile/src/store/layout.js +++ b/apps/presentationeditor/mobile/src/store/layout.js @@ -3,9 +3,14 @@ import {action, observable} from 'mobx'; export class storeLayout { @observable arrayLayouts; + @observable slideLayoutIndex = -1; @action addArrayLayouts(array) { this.arrayLayouts = array; } + @action changeSlideLayoutIndex(index) { + this.slideLayoutIndex = index; + } + } \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/view/edit/Layout.jsx b/apps/presentationeditor/mobile/src/view/edit/Layout.jsx index bd111f555..0f05a8cde 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Layout.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Layout.jsx @@ -1,6 +1,6 @@ -import React, {Fragment} from "react"; +import React from "react"; import { observer, inject } from "mobx-react"; -import { Page, Navbar, List, ListItem, BlockTitle } from "framework7-react"; +import { Page, Navbar, List, ListItem, NavRight, Link } from "framework7-react"; import { useTranslation } from "react-i18next"; const PageLayout = props => { @@ -8,18 +8,31 @@ const PageLayout = props => { const _t = t("View.Edit", { returnObjects: true }); const store = props.storeLayout; const arrayLayouts = JSON.parse(JSON.stringify(store.arrayLayouts)); + const slideLayoutIndex = store.slideLayoutIndex; + + console.log(slideLayoutIndex); console.log(arrayLayouts); console.log(store); + + return ( - - + + + + + + {arrayLayouts.length ? ( - + {arrayLayouts.map((elem, index) => { return ( - - + { + store.changeSlideLayoutIndex(index); + props.onLayoutClick(index); + }}> + ) })} From dbd4ae73dd8a146eed7dcb607839d72e17a89c5a Mon Sep 17 00:00:00 2001 From: SergeyEzhin Date: Thu, 24 Dec 2020 20:23:09 +0300 Subject: [PATCH 03/17] [PE mobile] Maked Themes and Layout Settings --- .../mobile/resources/img/themes/themes.png | Bin 0 -> 41865 bytes apps/common/mobile/resources/less/common.less | 110 ++++++++++++++++++ apps/presentationeditor/mobile/locale/en.json | 8 +- .../mobile/src/controller/Main.jsx | 20 +++- .../mobile/src/controller/edit/Layout.jsx | 8 +- .../mobile/src/controller/edit/Theme.jsx | 21 ++++ .../mobile/src/controller/edit/Transition.jsx | 16 +++ .../mobile/src/less/app-ios.less | 68 +---------- .../mobile/src/less/app-material.less | 66 ----------- .../mobile/src/store/mainStore.js | 6 +- .../mobile/src/store/theme.js | 15 +++ .../mobile/src/store/transition.js | 16 +++ .../mobile/src/view/edit/Edit.jsx | 10 ++ .../mobile/src/view/edit/EditSlide.jsx | 4 +- .../mobile/src/view/edit/Layout.jsx | 5 +- .../mobile/src/view/edit/Theme.jsx | 57 +++++++++ .../mobile/src/view/edit/Transition.jsx | 35 ++++++ 17 files changed, 311 insertions(+), 154 deletions(-) create mode 100644 apps/common/mobile/resources/img/themes/themes.png create mode 100644 apps/presentationeditor/mobile/src/controller/edit/Theme.jsx create mode 100644 apps/presentationeditor/mobile/src/controller/edit/Transition.jsx create mode 100644 apps/presentationeditor/mobile/src/store/theme.js create mode 100644 apps/presentationeditor/mobile/src/store/transition.js create mode 100644 apps/presentationeditor/mobile/src/view/edit/Theme.jsx create mode 100644 apps/presentationeditor/mobile/src/view/edit/Transition.jsx diff --git a/apps/common/mobile/resources/img/themes/themes.png b/apps/common/mobile/resources/img/themes/themes.png new file mode 100644 index 0000000000000000000000000000000000000000..3e3503d69cd4d87132e0a55ef9b4510daffca983 GIT binary patch literal 41865 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"{pxS4>v!#H6UXzb?j6s(tAs)kbbfg zdD!*ZEhvIjI9U};3ae~kfIz-G#z=j82ca=1H`tOW<9Q1qzZq=pI1sLH0BhtijYP+p zz3*c&vot7f3yHn>fwI>LN9gF1Q zj;0IU3z=1L?p!Gc*=*eTS`T9Sm5hjAT(zV7jn?l!p*RAab0}GJ4NZMvoVaYGS3x+@ zGr;J4*BAlgst5l{k5$0_6xz}0kPQzT5z8A|Og44N2% zK`ab}tazBOzpcoNevl@Ay!e4OXLeByFlmW9V8SzljB=Ejk`Q<0LAS|8xKIVcujYNQ z`z6G-p1*rPB|495Yr?r=bP~D4$N+pvKIoQa73Zo{#>MbOl%{~G2;EcbG`%2h#j0d4 zyc%#Bv~%&nXG#jp_rYID*Y8R>ppKZBAO#p#@dv_@a-vSJ2<2sOHnv~VZ6sI$51kRHoW#Vt ztdWs@bI908FZ*&*@Gm`m>!Z6PUERz=n7upLbM1=5$YDWnNi2YxT0^rn*suu{1LH*F zoH5f9@l`a~^+@PK@O3P_QV=!^_~#MDmb5e@#9o>DYmGL#H6l4fdz44h2L zt1geeOZnqOFRTcJ9$;S^I#iI2Iy=Z@v2ib1A8gTQ8b9K#Xo%aoS;Pln=n^H-8wKs} zJ`H394BxszkX4x_Ujhs70SU_{4p6wbHCih?`@)316Hwg|k#`xD8M87Yru1;U!{+4x zdb(Ag7OM^liFqq>F4me3tIPQ$TbYpS&)8)4Gh4OomI6?==RBN zo_a>7ki~n}Bro{z8{mS|oO{2*o5pzCrgDTdP zYwR8Bn?~PPjXw4u8}W;id%*qgFV7?#sI_Z4ct|8Q%w|3`fqzX3@am*ByD9-uOYN%^ zNkVF@LO3*c#NvI}JstioMYw8o9I{pTd3Lf6<3eDVh|{ale7>YV)cWqvaT`PT6O(db zR(#@lR^U&A^)MnLls^OOr-H!-^}J-Uj86T65{EH&O2cD6c?r=tZiTcsh43MEk_09^ z%yDvyb78d+m=^bAWIEF`d{iIHI{q~BS`sidF0!FcPP(l~w9qfu*UG9MkU%jt!X0KW zr@!_)l23wkE?1-jAEKSJGB*l^%J5&C#tv_)&TB{)Rvj3XHe1LTY}A?oK}=Ru%uj8J zs+e<9OLuHbN*qfXHMEUv;klzLC_zRk=H5Y7fsBG;$@_Rcm1@R0Ol1PIx>px*X&l#S(4CtZc5Z28uZlCR@_u zpI;I90hqT^u@br-2bfZ;bp)%6{60HBCuVh7UGSR3{f{DQ&oZ%GK5^QVW8tupa~*r= z@_GF`%6|GY1)GF%Q&1_omMI$SE^@=2L^sC zjN!Y++7)2l(w)shJOxa6fD8NY9Cf4jCfZKZ*8mO3l;PQ0wAKNvQKpHf1hInw88G-y zG?{2;Vq&CcaoQyIi`_lMn+t*khjG0!0#jnldYDp4%q1&v= z-NPK2p957;&4)7hNs7H013%mVpM$;PQSLCH&6&yZ?8&1kAU?_W`aiGNanPlYwljMt zSj(m%a<9L5*u1~D*Xw3vsa(uOB5uJ=D(mcG_v1tyTRQEFvcr|z-Gm4C&D=dn=nZnb zD$uy=Si-a8nCa8Q`AhrKxPZsVHAZR;q|N2zNtsFN(NeMn`BcUQ7~~^pzC@EzoNZSw z>&5aGOq%Duznq;DSR>!5Rh8Jgp88fD64>Jb;?&A!!ai8?8U2sErPjptd#lqR+!a{q zmMbx+jUs(T_~vIZXYpZOPp--WF17E4$i6$&bqrjbT5<5Y!ROPKrJ4~DL5X8}ZwW6Bfz=AFw!aY+2eLCC;}3U}6p?wD(CsN9 zFm1gVqvaVMFY1-*1+~JJZ7!i9&Rv&R@TB*s}s+pff3Quymm?V~ZWZ=;Q zX*fkx2&lDc+R!9I02Vz|3l_9yXy)myXSc-$98xO7Ikq-AkfO#GKielu@e&&GPHpqY z<)}nGene|u{?h2@PlD84L)>sB`}^GPEk#lN7D;{-nE&;Pq8Yl5Ez2;LX^68{jh{hA z7vkPEG=O@UUfhSN>^??%IA3_w>}-{wB`u90*R$FigGSJV*p|CXXeQeoO%efc`gjzL}W(KyNxi}W*nU}~v>kHkfX`1i4ypq8REYJ@Q+!G47Bvh&{_v<2Q6oJp7b^=2ZybOj6n!YQ(FwIaPLr77Xlep5Itq2?-q zwk19yPh3w~he-zaQ}e(&S~82ic}6uolApaJ0F}zIFOb;#om*`t@4G(TXK$t7=nQ1p zlW=Jk+U~PJ@xZ_}i=Ej`w28O$hLDuP*`KTb$k$cmraR8RHOI&z-U4g+aw7qf{o^rR zNyuj1D)gYX;Mj{M4AwMWJS*-chJ;*N&MRgkETYbzp{9pFDW8ySJyTAPJu2%OC?;`_ z8d?=eMlr|gBKX4e6tV`gYyu!34Y%$0Z}DPD2k-A*ai(p26jE_9>OLF{k*@K18g-u^ zX}`o}wO~{+e>Z;>*T68ita;B-%kTwUPiNYb`%5oX{v=d~YVJ+XO&@D^#O^YhMW0hW z@1qgodB*G1*yxwNk=$`?#b(1WhykTTJbzfp9kX1ayKQ-VIW|1>veMC4j_FIyTz{

O8Q~v214+~TkQcDU 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 Jt7J{X{|E8l#WVl_ literal 0 HcmV?d00001 diff --git a/apps/common/mobile/resources/less/common.less b/apps/common/mobile/resources/less/common.less index d2ca0f40b..fbd950316 100644 --- a/apps/common/mobile/resources/less/common.less +++ b/apps/common/mobile/resources/less/common.less @@ -44,3 +44,113 @@ padding: 0 16px; box-sizing: border-box; } + + +// Color Schemes + +.color-schemes-menu { + cursor: pointer; + display: block; + background-color: @white; + .item-inner { + justify-content: flex-start; + } + .color-schema-block { + display: flex; + } + .color { + min-width: 26px; + min-height: 26px; + margin: 0 2px 0 0; + box-shadow: 0 0 0 1px rgba(0,0,0,.15) inset; + } + .item-title { + margin-left: 20px; + color: #212121; + } +} + + +// Layout + +.slide-layout { + .list { + margin: auto; + } + ul { + display: flex; + flex-wrap: wrap; + justify-content: space-around; + } + li { + position: relative; + z-index: 1; + margin-top: 12px; + img { + box-shadow: 0 0 0 1px rgba(0,0,0,.15); + } + } + .item-inner { + padding-top: 0; + } + .item-inner:after { + display: none; + } + .item-inner:before { + opacity: 0; + content: ''; + position: absolute; + width: 22px; + height: 22px; + right: 11px; + bottom: 0; + z-index: 1; + background-repeat: no-repeat; + .encoded-svg-background(''); + } + .active .item-inner:before { + opacity: 1; + } +} + +// Theme + +.slide-theme .item-theme { + background-image: url(../img/themes/themes.png); +} + +.slide-theme { + .item-inner:after { + display: none; + } + .list { + margin: auto; + } + ul { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + padding-left: 18px; + padding-right: 18px; + padding-bottom: 14px; + } + .item-theme { + position: relative; + margin: 0; + box-shadow: 0 0 0 1px rgba(0,0,0,.15); + width: 85px; + height: 38px; + margin-top: 14px; + } + .item-theme.active:before { + content: ''; + position: absolute; + width: 22px; + height: 22px; + right: -5px; + bottom: -5px; + z-index: 1; + .encoded-svg-background(''); + } +} + diff --git a/apps/presentationeditor/mobile/locale/en.json b/apps/presentationeditor/mobile/locale/en.json index 2b0bdb7b8..5c4503d75 100644 --- a/apps/presentationeditor/mobile/locale/en.json +++ b/apps/presentationeditor/mobile/locale/en.json @@ -86,7 +86,13 @@ "textStyle": "Style", "textLayout": "Layout", "textTransition": "Transition", - "textBack": "Back" + "textBack": "Back", + "textEffect": "Effect", + "textType": "Type", + "textDuration": "Duration", + "textStartOnClick": "Start On Click", + "textDelay": "Delay", + "textApplyAll": "Apply to All Slides" } } } \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx index d864e977e..0d0693568 100644 --- a/apps/presentationeditor/mobile/src/controller/Main.jsx +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -4,7 +4,7 @@ import { inject } from "mobx-react"; import { withTranslation } from 'react-i18next'; import CollaborationController from '../../../../common/mobile/lib/controller/Collaboration.jsx' -@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeLayout") +@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeLayout", "storeTheme") class MainController extends Component { constructor(props) { super(props) @@ -195,7 +195,6 @@ class MainController extends Component { const storeLayout = this.props.storeLayout; this.api.asc_registerCallback('asc_onFocusObject', objects => { - console.log(objects); storeFocusObjects.resetFocusObjects(objects); @@ -208,14 +207,23 @@ class MainController extends Component { } }); - // this.api.asc_registerCallback('asc_onUpdateThemeIndex', themeId => { - // console.log(themeId); - // }); + const storeTheme = this.props.storeTheme; - this.api.asc_registerCallback('asc_onUpdateLayout', (layouts) => { + this.api.asc_registerCallback('asc_onInitEditorStyles', themes => { + // console.log(themes); + storeTheme.addArrayThemes(themes); + }); + + this.api.asc_registerCallback('asc_onUpdateThemeIndex', themeId => { + // console.log(themeId); + storeTheme.changeSlideThemeIndex(themeId); + }); + + this.api.asc_registerCallback('asc_onUpdateLayout', layouts => { // console.log(layouts); storeLayout.addArrayLayouts(layouts); }); + } _onDocumentContentReady() { diff --git a/apps/presentationeditor/mobile/src/controller/edit/Layout.jsx b/apps/presentationeditor/mobile/src/controller/edit/Layout.jsx index 572b47a70..acc725bc6 100644 --- a/apps/presentationeditor/mobile/src/controller/edit/Layout.jsx +++ b/apps/presentationeditor/mobile/src/controller/edit/Layout.jsx @@ -8,13 +8,7 @@ class LayoutController extends Component { onLayoutClick(index) { const api = Common.EditorApi.get(); - let props = new Asc.CAscSlideProps(); - console.log(api); - - props.LayoutIndex = index; - api.SetSlideProps(props); - - console.log(props); + api.ChangeLayout(index); } render() { diff --git a/apps/presentationeditor/mobile/src/controller/edit/Theme.jsx b/apps/presentationeditor/mobile/src/controller/edit/Theme.jsx new file mode 100644 index 000000000..5f3d23392 --- /dev/null +++ b/apps/presentationeditor/mobile/src/controller/edit/Theme.jsx @@ -0,0 +1,21 @@ +import React, { Component } from "react"; +import Theme from "../../view/edit/Theme"; + +class ThemeController extends Component { + constructor(props) { + super(props); + } + + onThemeClick(index) { + const api = Common.EditorApi.get(); + api.ChangeTheme(index); + } + + render() { + return ( + + ); + } +} + +export default ThemeController; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx new file mode 100644 index 000000000..61722f0da --- /dev/null +++ b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx @@ -0,0 +1,16 @@ +import React, { Component } from "react"; +import Transition from "../../view/edit/Transition"; + +class TransitionController extends Component { + constructor(props) { + super(props); + } + + render() { + return ( + + ); + } +} + +export default TransitionController; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/less/app-ios.less b/apps/presentationeditor/mobile/src/less/app-ios.less index 62aa74165..dda949856 100644 --- a/apps/presentationeditor/mobile/src/less/app-ios.less +++ b/apps/presentationeditor/mobile/src/less/app-ios.less @@ -1,72 +1,6 @@ .device-ios { - // Color Schemes - - .color-schemes-menu { - cursor: pointer; - display: block; - background-color: #fff; - .item-inner { - justify-content: flex-start; - } - .color-schema-block { - display: flex; - } - .color { - min-width: 26px; - min-height: 26px; - margin: 0 2px 0 0; - box-shadow: 0 0 0 1px rgba(0,0,0,.15) inset; - } - .item-title { - margin-left: 20px; - color: #212121; - } - } - - - // Layout - - .slide-layout { - .list { - margin: auto; - } - ul { - display: flex; - flex-wrap: wrap; - justify-content: space-around; - } - li { - position: relative; - z-index: 1; - margin-top: 12px; - img { - box-shadow: 0 0 0 1px rgba(0,0,0,.15); - } - } - .item-inner { - padding-top: 0; - } - .item-inner:after { - display: none; - } - .item-inner:before { - opacity: 0; - content: ''; - position: absolute; - width: 22px; - height: 22px; - right: 11px; - bottom: 0; - z-index: 1; - background-repeat: no-repeat; - .encoded-svg-background(''); - } - .active .item-inner:before { - opacity: 1; - } - } - + } diff --git a/apps/presentationeditor/mobile/src/less/app-material.less b/apps/presentationeditor/mobile/src/less/app-material.less index 8367a79ab..b52ae72f9 100644 --- a/apps/presentationeditor/mobile/src/less/app-material.less +++ b/apps/presentationeditor/mobile/src/less/app-material.less @@ -22,70 +22,4 @@ width: auto; } - - // Color Schemes - - .color-schemes-menu { - cursor: pointer; - display: block; - background-color: #fff; - .item-inner { - justify-content: flex-start; - } - .color-schema-block { - display: flex; - } - .color { - min-width: 26px; - min-height: 26px; - margin: 0 2px 0 0; - box-shadow: 0 0 0 1px rgba(0,0,0,.15) inset; - } - .item-title { - margin-left: 20px; - color: #212121; - } - } - - // Layout - - .slide-layout { - .list { - margin: auto; - } - ul { - display: flex; - flex-wrap: wrap; - justify-content: space-around; - } - li { - position: relative; - z-index: 1; - margin-top: 12px; - img { - box-shadow: 0 0 0 1px rgba(0,0,0,.15); - } - } - .item-inner { - padding-top: 0; - } - .item-inner:after { - display: none; - } - .item-inner:before { - opacity: 0; - content: ''; - position: absolute; - width: 22px; - height: 22px; - right: 11px; - bottom: 0; - z-index: 1; - background-repeat: no-repeat; - .encoded-svg-background(''); - } - .active .item-inner:before { - opacity: 1; - } - } } diff --git a/apps/presentationeditor/mobile/src/store/mainStore.js b/apps/presentationeditor/mobile/src/store/mainStore.js index ceb746a37..a022c8999 100644 --- a/apps/presentationeditor/mobile/src/store/mainStore.js +++ b/apps/presentationeditor/mobile/src/store/mainStore.js @@ -7,6 +7,8 @@ import {storeApplicationSettings} from './applicationSettings'; import {storePresentationInfo} from './presentationInfo'; import {storePresentationSettings} from './presentationSettings'; import { storeLayout } from './layout'; +import { storeTransition } from './transition'; +import { storeTheme } from './theme'; // import {storeTextSettings} from "./textSettings"; // import {storeParagraphSettings} from "./paragraphSettings"; // import {storeShapeSettings} from "./shapeSettings"; @@ -22,7 +24,9 @@ export const stores = { storeApplicationSettings: new storeApplicationSettings(), storePresentationInfo: new storePresentationInfo(), storePresentationSettings: new storePresentationSettings(), - storeLayout: new storeLayout() + storeLayout: new storeLayout(), + storeTransition: new storeTransition(), + storeTheme: new storeTheme() // storeTextSettings: new storeTextSettings(), // storeParagraphSettings: new storeParagraphSettings(), // storeShapeSettings: new storeShapeSettings(), diff --git a/apps/presentationeditor/mobile/src/store/theme.js b/apps/presentationeditor/mobile/src/store/theme.js new file mode 100644 index 000000000..226efc562 --- /dev/null +++ b/apps/presentationeditor/mobile/src/store/theme.js @@ -0,0 +1,15 @@ +import {action, observable} from 'mobx'; + +export class storeTheme { + + @observable arrayThemes; + @observable slideThemeIndex; + + @action addArrayThemes(array) { + this.arrayThemes = array; + } + + @action changeSlideThemeIndex(index) { + this.slideThemeIndex = index; + } +} \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/store/transition.js b/apps/presentationeditor/mobile/src/store/transition.js new file mode 100644 index 000000000..44d3308b9 --- /dev/null +++ b/apps/presentationeditor/mobile/src/store/transition.js @@ -0,0 +1,16 @@ +import {action, observable} from 'mobx'; + +export class storeTransition { + + // @observable arrayLayouts; + // @observable slideLayoutIndex = -1; + + // @action addArrayLayouts(array) { + // this.arrayLayouts = array; + // } + + // @action changeSlideLayoutIndex(index) { + // this.slideLayoutIndex = index; + // } + +} \ 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 1ff57fb59..96c486499 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Edit.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Edit.jsx @@ -8,6 +8,8 @@ import {Device} from '../../../../../common/mobile/utils/device'; import EditSlideController from "../../controller/edit/EditSlide"; import EditTextController from "../../controller/edit/EditText"; import LayoutController from "../../controller/edit/Layout"; +import TransitionController from '../../controller/edit/Transition'; +import ThemeController from '../../controller/edit/Theme'; //import EditShapeController from "../../controller/edit/EditShape"; //import EditImageController from "../../controller/edit/EditImage"; //import EditTableController from "../../controller/edit/EditTable"; @@ -18,6 +20,14 @@ const routes = [ { path: '/layout/', component: LayoutController + }, + { + path: '/theme/', + component: ThemeController + }, + { + path: '/transition/', + component: TransitionController } ]; diff --git a/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx b/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx index d342e3e9f..39897381f 100644 --- a/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/EditSlide.jsx @@ -12,9 +12,9 @@ const EditSlide = props => { return ( - + - + diff --git a/apps/presentationeditor/mobile/src/view/edit/Layout.jsx b/apps/presentationeditor/mobile/src/view/edit/Layout.jsx index 0f05a8cde..bb2ed0d5a 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Layout.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Layout.jsx @@ -12,10 +12,7 @@ const PageLayout = props => { console.log(slideLayoutIndex); console.log(arrayLayouts); - console.log(store); - - - + return ( diff --git a/apps/presentationeditor/mobile/src/view/edit/Theme.jsx b/apps/presentationeditor/mobile/src/view/edit/Theme.jsx new file mode 100644 index 000000000..1e80f8d0b --- /dev/null +++ b/apps/presentationeditor/mobile/src/view/edit/Theme.jsx @@ -0,0 +1,57 @@ +import React from "react"; +import { observer, inject } from "mobx-react"; +import { Page, Navbar, List, ListItem, NavRight, Link } from "framework7-react"; +import { useTranslation } from "react-i18next"; + +const PageTheme = props => { + const { t } = useTranslation(); + const _t = t("View.Edit", { returnObjects: true }); + const store = props.storeTheme; + const arrayThemes = JSON.parse(JSON.stringify(store.arrayThemes)); + const slideThemeIndex = store.slideThemeIndex; + const defaultThemes = arrayThemes[0]; + const docThemes = arrayThemes[1]; + + console.log(slideThemeIndex); + console.log(arrayThemes); + + return ( + + + + + + + {arrayThemes.length ? ( + + {defaultThemes.map((elem, index) => { + return ( + { + store.changeSlideThemeIndex(elem.Index); + props.onThemeClick(elem.Index); + }}> + + ); + })} + {docThemes.map((elem, index) => { + return ( + { + store.changeSlideThemeIndex(elem.Index); + props.onThemeClick(elem.Index); + }}> + + ); + })} + + ) : null} + + ); +}; + +const Theme = inject("storeTheme")(observer(PageTheme)); + +export default Theme; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/view/edit/Transition.jsx b/apps/presentationeditor/mobile/src/view/edit/Transition.jsx new file mode 100644 index 000000000..9f4630bd0 --- /dev/null +++ b/apps/presentationeditor/mobile/src/view/edit/Transition.jsx @@ -0,0 +1,35 @@ +import React, {Fragment} from "react"; +import { observer, inject } from "mobx-react"; +import { Page, Navbar, List, ListItem, BlockTitle, NavRight, Link } from "framework7-react"; +import { useTranslation } from "react-i18next"; + +const PageTransition = props => { + const { t } = useTranslation(); + const _t = t("View.Edit", { returnObjects: true }); + // const storeInfo = props.storePresentationInfo; + // const dataApp = props.getAppProps(); + // const dataModified = props.getModified; + // const dataModifiedBy = props.getModifiedBy; + // const creators = props.getCreators; + // const dataDoc = JSON.parse(JSON.stringify(storeInfo.dataDoc)); + + return ( + + + + + + + + + + + + + + ); +}; + +const Transition = inject("storeTransition")(observer(PageTransition)); + +export default Transition; \ No newline at end of file From 57b7d0c4101a29c1fe360127367ca656a8a14182 Mon Sep 17 00:00:00 2001 From: SergeyEzhin Date: Sat, 26 Dec 2020 00:26:51 +0300 Subject: [PATCH 04/17] [PE mobile] Make Transition settings --- apps/common/mobile/resources/less/common.less | 47 ++++++++++++++++++ .../mobile/src/controller/Main.jsx | 6 ++- .../mobile/src/controller/edit/Effect.jsx | 16 +++++++ .../mobile/src/controller/edit/Transition.jsx | 27 +++++++++++ .../mobile/src/controller/edit/Type.jsx | 16 +++++++ .../mobile/src/store/effect.js | 5 ++ .../mobile/src/store/mainStore.js | 6 ++- .../mobile/src/store/transition.js | 17 ++++--- .../mobile/src/store/type.js | 5 ++ .../mobile/src/view/edit/Edit.jsx | 10 ++++ .../mobile/src/view/edit/Effect.jsx | 24 ++++++++++ .../mobile/src/view/edit/Transition.jsx | 48 +++++++++++++++---- .../mobile/src/view/edit/Type.jsx | 28 +++++++++++ 13 files changed, 236 insertions(+), 19 deletions(-) create mode 100644 apps/presentationeditor/mobile/src/controller/edit/Effect.jsx create mode 100644 apps/presentationeditor/mobile/src/controller/edit/Type.jsx create mode 100644 apps/presentationeditor/mobile/src/store/effect.js create mode 100644 apps/presentationeditor/mobile/src/store/type.js create mode 100644 apps/presentationeditor/mobile/src/view/edit/Effect.jsx create mode 100644 apps/presentationeditor/mobile/src/view/edit/Type.jsx diff --git a/apps/common/mobile/resources/less/common.less b/apps/common/mobile/resources/less/common.less index fbd950316..7a2d26d4e 100644 --- a/apps/common/mobile/resources/less/common.less +++ b/apps/common/mobile/resources/less/common.less @@ -154,3 +154,50 @@ } } +// Transition + +.slide-transition { + .splitter { + display: flex; + align-items: center; + color: @black; + label { + margin: 0 5px; + } + } + .buttons-row { + display: flex; + margin: 0; + min-width: 90px; + margin-left: 10px; + .button { + width: 100%; + } + .button:first-child { + border-radius: 5px 0 0 5px; + border-left-width: 1px; + border-left-style: solid; + } + .button:last-child { + border-radius: 0 5px 5px 0; + } + } + .range-slider { + .range-bar { + height: 2px; + } + .range-bar-active { + background: transparent; + } + } + .slide-apply-all { + color: @themeColor; + border: 0; + .item-inner { + justify-content: center; + } + } +} + + + diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx index 0d0693568..ae7481d58 100644 --- a/apps/presentationeditor/mobile/src/controller/Main.jsx +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -4,7 +4,7 @@ import { inject } from "mobx-react"; import { withTranslation } from 'react-i18next'; import CollaborationController from '../../../../common/mobile/lib/controller/Collaboration.jsx' -@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeLayout", "storeTheme") +@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeLayout", "storeTheme", "storeTransition") class MainController extends Component { constructor(props) { super(props) @@ -193,6 +193,7 @@ class MainController extends Component { const storeFocusObjects = this.props.storeFocusObjects; const storeLayout = this.props.storeLayout; + const storeTransition = this.props.storeTransition; this.api.asc_registerCallback('asc_onFocusObject', objects => { console.log(objects); @@ -204,6 +205,9 @@ class MainController extends Component { if(settings[0] === "slide") { const slideObject = objects[0].get_ObjectValue(); storeLayout.changeSlideLayoutIndex(slideObject.get_LayoutIndex()); + // const timing = slideObject.get_transition(); + // console.log(timing); + storeTransition.addTransitionObj(slideObject.get_transition()); } }); diff --git a/apps/presentationeditor/mobile/src/controller/edit/Effect.jsx b/apps/presentationeditor/mobile/src/controller/edit/Effect.jsx new file mode 100644 index 000000000..147b57e61 --- /dev/null +++ b/apps/presentationeditor/mobile/src/controller/edit/Effect.jsx @@ -0,0 +1,16 @@ +import React, { Component } from "react"; +import Effect from "../../view/edit/Effect"; + +class EffectController extends Component { + constructor(props) { + super(props); + } + + render() { + return ( + + ); + } +} + +export default EffectController; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx index 61722f0da..57f2674bc 100644 --- a/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx +++ b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx @@ -6,6 +6,29 @@ class TransitionController extends Component { super(props); } + initTransitionView(timing) { + + const _effect = timing.get_TransitionType(); + // me.getView('EditSlide').fillEffectTypes(_effect); + // $('#edit-slide-effect .item-after').text(me.getView('EditSlide').getEffectName(_effect)); + // $('#edit-slide-effect-type').toggleClass('disabled', _effect == Asc.c_oAscSlideTransitionTypes.None); + // $('#edit-slide-duration').toggleClass('disabled', _effect == Asc.c_oAscSlideTransitionTypes.None); + + // _effectType = timing.get_TransitionOption(); + // $('#edit-slide-effect-type .item-after').text((_effect != Asc.c_oAscSlideTransitionTypes.None) ? me.getView('EditSlide').getEffectTypeName(_effectType) : ''); + + // _effectDuration = timing.get_TransitionDuration(); + // $('#edit-slide-duration .item-after label').text((_effectDuration!==null && _effectDuration!==undefined) ? (parseInt(_effectDuration/1000.) + ' ' + me.textSec) : ''); + + // $('#edit-slide-start-click input:checkbox').prop('checked', !!timing.get_SlideAdvanceOnMouseClick()); + // $('#edit-slide-delay input:checkbox').prop('checked', !!timing.get_SlideAdvanceAfter()); + // $('#edit-slide-delay .item-content:nth-child(2)').toggleClass('disabled',!timing.get_SlideAdvanceAfter()); + + // _effectDelay = timing.get_SlideAdvanceDuration(); + // $('#edit-slide-delay .item-content:nth-child(2) .item-after').text((_effectDelay!==null && _effectDelay!==undefined) ? (parseInt(_effectDelay/1000.) + ' ' + me.textSec) : ''); + // $('#edit-slide-delay .item-content:nth-child(2) input').val([(_effectDelay!==null && _effectDelay!==undefined) ? parseInt(_effectDelay/1000.) : 0]); + } + render() { return ( @@ -13,4 +36,8 @@ class TransitionController extends Component { } } +// const initTransitionView = (timing) => { + +// } + export default TransitionController; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/edit/Type.jsx b/apps/presentationeditor/mobile/src/controller/edit/Type.jsx new file mode 100644 index 000000000..c544d0187 --- /dev/null +++ b/apps/presentationeditor/mobile/src/controller/edit/Type.jsx @@ -0,0 +1,16 @@ +import React, { Component } from "react"; +import Type from "../../view/edit/Type"; + +class TypeController extends Component { + constructor(props) { + super(props); + } + + render() { + return ( + + ); + } +} + +export default TypeController; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/store/effect.js b/apps/presentationeditor/mobile/src/store/effect.js new file mode 100644 index 000000000..aee5a0782 --- /dev/null +++ b/apps/presentationeditor/mobile/src/store/effect.js @@ -0,0 +1,5 @@ +import {action, observable} from 'mobx'; + +export class storeEffect { + +} \ 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 a022c8999..604465a0a 100644 --- a/apps/presentationeditor/mobile/src/store/mainStore.js +++ b/apps/presentationeditor/mobile/src/store/mainStore.js @@ -9,6 +9,8 @@ import {storePresentationSettings} from './presentationSettings'; import { storeLayout } from './layout'; import { storeTransition } from './transition'; import { storeTheme } from './theme'; +import { storeEffect } from './effect'; +import { storeType } from './type'; // import {storeTextSettings} from "./textSettings"; // import {storeParagraphSettings} from "./paragraphSettings"; // import {storeShapeSettings} from "./shapeSettings"; @@ -26,7 +28,9 @@ export const stores = { storePresentationSettings: new storePresentationSettings(), storeLayout: new storeLayout(), storeTransition: new storeTransition(), - storeTheme: new storeTheme() + storeTheme: new storeTheme(), + storeEffect: new storeEffect(), + storeType: new storeType() // storeTextSettings: new storeTextSettings(), // storeParagraphSettings: new storeParagraphSettings(), // storeShapeSettings: new storeShapeSettings(), diff --git a/apps/presentationeditor/mobile/src/store/transition.js b/apps/presentationeditor/mobile/src/store/transition.js index 44d3308b9..912275696 100644 --- a/apps/presentationeditor/mobile/src/store/transition.js +++ b/apps/presentationeditor/mobile/src/store/transition.js @@ -2,15 +2,14 @@ import {action, observable} from 'mobx'; export class storeTransition { - // @observable arrayLayouts; - // @observable slideLayoutIndex = -1; - - // @action addArrayLayouts(array) { - // this.arrayLayouts = array; - // } + @observable isDelay = false; + @observable transitionObj = {}; - // @action changeSlideLayoutIndex(index) { - // this.slideLayoutIndex = index; - // } + @action toggleDelay() { + this.isDelay = !this.isDelay; + } + @action addTransitionObj(obj) { + this.transitionObj = obj; + } } \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/store/type.js b/apps/presentationeditor/mobile/src/store/type.js new file mode 100644 index 000000000..a019c6a94 --- /dev/null +++ b/apps/presentationeditor/mobile/src/store/type.js @@ -0,0 +1,5 @@ +import {action, observable} from 'mobx'; + +export class storeType { + +} \ 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 96c486499..db47714e8 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Edit.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Edit.jsx @@ -10,6 +10,8 @@ import EditTextController from "../../controller/edit/EditText"; import LayoutController from "../../controller/edit/Layout"; import TransitionController from '../../controller/edit/Transition'; import ThemeController from '../../controller/edit/Theme'; +import EffectController from '../../controller/edit/Effect'; +import TypeController from '../../controller/edit/Type'; //import EditShapeController from "../../controller/edit/EditShape"; //import EditImageController from "../../controller/edit/EditImage"; //import EditTableController from "../../controller/edit/EditTable"; @@ -28,6 +30,14 @@ const routes = [ { path: '/transition/', component: TransitionController + }, + { + path: '/effect/', + component: EffectController + }, + { + path: '/type/', + component: TypeController } ]; diff --git a/apps/presentationeditor/mobile/src/view/edit/Effect.jsx b/apps/presentationeditor/mobile/src/view/edit/Effect.jsx new file mode 100644 index 000000000..0a6924890 --- /dev/null +++ b/apps/presentationeditor/mobile/src/view/edit/Effect.jsx @@ -0,0 +1,24 @@ +import React, {useState} from "react"; +import { observer, inject } from "mobx-react"; +import { Page, Navbar, List, ListItem, NavRight, Link, Toggle, Range, ListItemCell } from "framework7-react"; +import { useTranslation } from "react-i18next"; + +const PageEffect= props => { + const { t } = useTranslation(); + const _t = t("View.Edit", { returnObjects: true }); + + return ( + + + + + + + + + ); +}; + +const Effect = inject("storeEffect")(observer(PageEffect)); + +export default Effect; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/view/edit/Transition.jsx b/apps/presentationeditor/mobile/src/view/edit/Transition.jsx index 9f4630bd0..c663be886 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Transition.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Transition.jsx @@ -1,12 +1,14 @@ -import React, {Fragment} from "react"; +import React, {useState} from "react"; import { observer, inject } from "mobx-react"; -import { Page, Navbar, List, ListItem, BlockTitle, NavRight, Link } from "framework7-react"; +import { Page, Navbar, List, ListItem, NavRight, Link, Toggle, Range, ListItemCell } from "framework7-react"; import { useTranslation } from "react-i18next"; const PageTransition = props => { const { t } = useTranslation(); const _t = t("View.Edit", { returnObjects: true }); - // const storeInfo = props.storePresentationInfo; + const [stateRange, changeRange] = useState(0); + const store = props.storeTransition; + const isDelay = store.isDelay; // const dataApp = props.getAppProps(); // const dataModified = props.getModified; // const dataModifiedBy = props.getModifiedBy; @@ -14,18 +16,48 @@ const PageTransition = props => { // const dataDoc = JSON.parse(JSON.stringify(storeInfo.dataDoc)); return ( - + - - - + + +

+
+ +
+ +

+ - + + +

+
+
+
+ + + {_t.textStartOnClick} + + + + {_t.textDelay} + + + + + + + + {stateRange} s + + + + + {_t.textApplyAll} -
); }; diff --git a/apps/presentationeditor/mobile/src/view/edit/Type.jsx b/apps/presentationeditor/mobile/src/view/edit/Type.jsx new file mode 100644 index 000000000..d1dbb4de2 --- /dev/null +++ b/apps/presentationeditor/mobile/src/view/edit/Type.jsx @@ -0,0 +1,28 @@ +import React, {useState} from "react"; +import { observer, inject } from "mobx-react"; +import { Page, Navbar, List, ListItem, NavRight, Link, Toggle, Range, ListItemCell } from "framework7-react"; +import { useTranslation } from "react-i18next"; + +const PageType= props => { + const { t } = useTranslation(); + const _t = t("View.Edit", { returnObjects: true }); + + return ( + + + + + + + + + + + + + ); +}; + +const Type = inject("storeType")(observer(PageType)); + +export default Type; \ No newline at end of file From b948e839db53dffc267454d428f34bfa2b4688cd Mon Sep 17 00:00:00 2001 From: SergeyEzhin Date: Tue, 29 Dec 2020 02:09:59 +0300 Subject: [PATCH 05/17] [PE mobile] Make Transition Settings --- apps/presentationeditor/mobile/locale/en.json | 32 +++- .../mobile/src/controller/Main.jsx | 2 +- .../mobile/src/controller/edit/Transition.jsx | 68 +++++--- .../mobile/src/store/transition.js | 11 +- .../mobile/src/view/edit/Transition.jsx | 151 +++++++++++++++--- 5 files changed, 220 insertions(+), 44 deletions(-) diff --git a/apps/presentationeditor/mobile/locale/en.json b/apps/presentationeditor/mobile/locale/en.json index 5c4503d75..0e99c1e05 100644 --- a/apps/presentationeditor/mobile/locale/en.json +++ b/apps/presentationeditor/mobile/locale/en.json @@ -92,7 +92,37 @@ "textDuration": "Duration", "textStartOnClick": "Start On Click", "textDelay": "Delay", - "textApplyAll": "Apply to All Slides" + "textApplyAll": "Apply to All Slides", + "textNone": "None", + "textFade": "Fade", + "textPush": "Push", + "textWipe": "Wipe", + "textSplit": "Split", + "textUnCover": "UnCover", + "textCover": "Cover", + "textClock": "Clock", + "textZoom": "Zoom", + "textSmoothly": "Smoothly", + "textBlack": "Through Black", + "textLeft": "Left", + "textTop": "Top", + "textRight": "Right", + "textBottom": "Bottom", + "textTopLeft": "Top-Left", + "textTopRight": "Top-Right", + "textBottomLeft": "Bottom-Left", + "textBottomRight": "Bottom-Right", + "textVerticalIn": "Vertical In", + "textVerticalOut": "Vertical Out", + "textHorizontalIn": "Horizontal In", + "textHorizontalOut": "Horizontal Out", + "textClockwise": "Clockwise", + "textCounterclockwise": "Counterclockwise", + "textWedge": "Wedge", + "textZoomIn": "Zoom In", + "textZoomOut": "Zoom Out", + "textZoomRotate": "Zoom and Rotate", + "textSec": "s" } } } \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx index ae7481d58..78f322d36 100644 --- a/apps/presentationeditor/mobile/src/controller/Main.jsx +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -207,7 +207,7 @@ class MainController extends Component { storeLayout.changeSlideLayoutIndex(slideObject.get_LayoutIndex()); // const timing = slideObject.get_transition(); // console.log(timing); - storeTransition.addTransitionObj(slideObject.get_transition()); + storeTransition.addTransition(slideObject.get_transition()); } }); diff --git a/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx index 57f2674bc..644c280ea 100644 --- a/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx +++ b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx @@ -6,38 +6,64 @@ class TransitionController extends Component { super(props); } - initTransitionView(timing) { - - const _effect = timing.get_TransitionType(); - // me.getView('EditSlide').fillEffectTypes(_effect); - // $('#edit-slide-effect .item-after').text(me.getView('EditSlide').getEffectName(_effect)); - // $('#edit-slide-effect-type').toggleClass('disabled', _effect == Asc.c_oAscSlideTransitionTypes.None); - // $('#edit-slide-duration').toggleClass('disabled', _effect == Asc.c_oAscSlideTransitionTypes.None); + onApplyAll() { + const api = Common.EditorApi.get(); + console.log(api); + // api.SlideTimingApplyToAll(); + }; - // _effectType = timing.get_TransitionOption(); - // $('#edit-slide-effect-type .item-after').text((_effect != Asc.c_oAscSlideTransitionTypes.None) ? me.getView('EditSlide').getEffectTypeName(_effectType) : ''); + changeDuration(_effectDuration) { + const api = Common.EditorApi.get(); + let props = new Asc.CAscSlideProps(), + timing = new Asc.CAscSlideTiming(); - // _effectDuration = timing.get_TransitionDuration(); - // $('#edit-slide-duration .item-after label').text((_effectDuration!==null && _effectDuration!==undefined) ? (parseInt(_effectDuration/1000.) + ' ' + me.textSec) : ''); + timing.put_TransitionDuration(_effectDuration); + props.put_timing(timing); + api.SetSlideProps(props); + }; - // $('#edit-slide-start-click input:checkbox').prop('checked', !!timing.get_SlideAdvanceOnMouseClick()); - // $('#edit-slide-delay input:checkbox').prop('checked', !!timing.get_SlideAdvanceAfter()); - // $('#edit-slide-delay .item-content:nth-child(2)').toggleClass('disabled',!timing.get_SlideAdvanceAfter()); + onStartClick(value) { + const api = Common.EditorApi.get(); + let props = new Asc.CAscSlideProps(), + timing = new Asc.CAscSlideTiming(); - // _effectDelay = timing.get_SlideAdvanceDuration(); - // $('#edit-slide-delay .item-content:nth-child(2) .item-after').text((_effectDelay!==null && _effectDelay!==undefined) ? (parseInt(_effectDelay/1000.) + ' ' + me.textSec) : ''); - // $('#edit-slide-delay .item-content:nth-child(2) input').val([(_effectDelay!==null && _effectDelay!==undefined) ? parseInt(_effectDelay/1000.) : 0]); + timing.put_SlideAdvanceOnMouseClick(value); + props.put_timing(timing); + api.SetSlideProps(props); + }; + + onDelayCheck(value, _effectDelay) { + const api = Common.EditorApi.get(); + let props = new Asc.CAscSlideProps(), + timing = new Asc.CAscSlideTiming(); + + timing.put_SlideAdvanceAfter(value); + timing.put_SlideAdvanceDuration(_effectDelay); + props.put_timing(timing); + api.SetSlideProps(props); } + onDelay(_effectDelay) { + const api = Common.EditorApi.get(); + let props = new Asc.CAscSlideProps(), + timing = new Asc.CAscSlideTiming(); + + timing.put_SlideAdvanceDuration(_effectDelay); + props.put_timing(timing); + api.SetSlideProps(props); + }; + render() { return ( - + ); } } -// const initTransitionView = (timing) => { - -// } export default TransitionController; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/store/transition.js b/apps/presentationeditor/mobile/src/store/transition.js index 912275696..e7e511942 100644 --- a/apps/presentationeditor/mobile/src/store/transition.js +++ b/apps/presentationeditor/mobile/src/store/transition.js @@ -2,14 +2,19 @@ import {action, observable} from 'mobx'; export class storeTransition { + @observable transition = {}; @observable isDelay = false; - @observable transitionObj = {}; + @observable isStartOnClick = true; @action toggleDelay() { this.isDelay = !this.isDelay; } - @action addTransitionObj(obj) { - this.transitionObj = obj; + @action toggleStartOnClick() { + this.isStartOnClick = !this.isStartOnClick; + } + + @action addTransition(obj) { + this.transition = obj; } } \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/view/edit/Transition.jsx b/apps/presentationeditor/mobile/src/view/edit/Transition.jsx index c663be886..571fd62b3 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Transition.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Transition.jsx @@ -6,15 +6,108 @@ import { useTranslation } from "react-i18next"; const PageTransition = props => { const { t } = useTranslation(); const _t = t("View.Edit", { returnObjects: true }); - const [stateRange, changeRange] = useState(0); const store = props.storeTransition; + const transition = store.transition; + const _effect = transition.get_TransitionType(); + + let _arrCurrentEffectTypes; + let _effectDelay = transition.get_SlideAdvanceDuration(); + const [stateRange, changeRange] = useState((_effectDelay !== null && _effectDelay !== undefined) ? parseInt(_effectDelay / 1000.) : 0); + const isDelay = store.isDelay; - // const dataApp = props.getAppProps(); - // const dataModified = props.getModified; - // const dataModifiedBy = props.getModifiedBy; - // const creators = props.getCreators; - // const dataDoc = JSON.parse(JSON.stringify(storeInfo.dataDoc)); - + const isStartOnClick = store.isStartOnClick; + + const _arrEffect = [ + {displayValue: _t.textNone, value: Asc.c_oAscSlideTransitionTypes.None}, + {displayValue: _t.textFade, value: Asc.c_oAscSlideTransitionTypes.Fade}, + {displayValue: _t.textPush, value: Asc.c_oAscSlideTransitionTypes.Push}, + {displayValue: _t.textWipe, value: Asc.c_oAscSlideTransitionTypes.Wipe}, + {displayValue: _t.textSplit, value: Asc.c_oAscSlideTransitionTypes.Split}, + {displayValue: _t.textUnCover, value: Asc.c_oAscSlideTransitionTypes.UnCover}, + {displayValue: _t.textCover, value: Asc.c_oAscSlideTransitionTypes.Cover}, + {displayValue: _t.textClock, value: Asc.c_oAscSlideTransitionTypes.Clock}, + {displayValue: _t.textZoom, value: Asc.c_oAscSlideTransitionTypes.Zoom} + ]; + + const _arrEffectType = [ + {displayValue: _t.textSmoothly, value: Asc.c_oAscSlideTransitionParams.Fade_Smoothly}, + {displayValue: _t.textBlack, value: Asc.c_oAscSlideTransitionParams.Fade_Through_Black}, + {displayValue: _t.textLeft, value: Asc.c_oAscSlideTransitionParams.Param_Left}, + {displayValue: _t.textTop, value: Asc.c_oAscSlideTransitionParams.Param_Top}, + {displayValue: _t.textRight, value: Asc.c_oAscSlideTransitionParams.Param_Right}, + {displayValue: _t.textBottom, value: Asc.c_oAscSlideTransitionParams.Param_Bottom}, + {displayValue: _t.textTopLeft, value: Asc.c_oAscSlideTransitionParams.Param_TopLeft}, + {displayValue: _t.textTopRight, value: Asc.c_oAscSlideTransitionParams.Param_TopRight}, + {displayValue: _t.textBottomLeft, value: Asc.c_oAscSlideTransitionParams.Param_BottomLeft}, + {displayValue: _t.textBottomRight, value: Asc.c_oAscSlideTransitionParams.Param_BottomRight}, + {displayValue: _t.textVerticalIn, value: Asc.c_oAscSlideTransitionParams.Split_VerticalIn}, + {displayValue: _t.textVerticalOut, value: Asc.c_oAscSlideTransitionParams.Split_VerticalOut}, + {displayValue: _t.textHorizontalIn, value: Asc.c_oAscSlideTransitionParams.Split_HorizontalIn}, + {displayValue: _t.textHorizontalOut, value: Asc.c_oAscSlideTransitionParams.Split_HorizontalOut}, + {displayValue: _t.textClockwise, value: Asc.c_oAscSlideTransitionParams.Clock_Clockwise}, + {displayValue: _t.textCounterclockwise, value: Asc.c_oAscSlideTransitionParams.Clock_Counterclockwise}, + {displayValue: _t.textWedge, value: Asc.c_oAscSlideTransitionParams.Clock_Wedge}, + {displayValue: _t.textZoomIn, value: Asc.c_oAscSlideTransitionParams.Zoom_In}, + {displayValue: _t.textZoomOut, value: Asc.c_oAscSlideTransitionParams.Zoom_Out}, + {displayValue: _t.textZoomRotate, value: Asc.c_oAscSlideTransitionParams.Zoom_AndRotate} + ]; + + const fillEffectTypes = type => { + _arrCurrentEffectTypes = []; + switch (type) { + case Asc.c_oAscSlideTransitionTypes.Fade: + _arrCurrentEffectTypes.push(_arrEffectType[0], _arrEffectType[1]); + break; + case Asc.c_oAscSlideTransitionTypes.Push: + _arrCurrentEffectTypes = _arrEffectType.slice(2, 6); + break; + case Asc.c_oAscSlideTransitionTypes.Wipe: + _arrCurrentEffectTypes = _arrEffectType.slice(2, 10); + break; + case Asc.c_oAscSlideTransitionTypes.Split: + _arrCurrentEffectTypes = _arrEffectType.slice(10, 14); + break; + case Asc.c_oAscSlideTransitionTypes.UnCover: + _arrCurrentEffectTypes = _arrEffectType.slice(2, 10); + break; + case Asc.c_oAscSlideTransitionTypes.Cover: + _arrCurrentEffectTypes = _arrEffectType.slice(2, 10); + break; + case Asc.c_oAscSlideTransitionTypes.Clock: + _arrCurrentEffectTypes = _arrEffectType.slice(14, 17); + break; + case Asc.c_oAscSlideTransitionTypes.Zoom: + _arrCurrentEffectTypes = _arrEffectType.slice(17); + break; + } + return (_arrCurrentEffectTypes.length > 0) ? _arrCurrentEffectTypes[0].value : -1; + }; + + const getEffectName = effect => { + for (var i=0; i < _arrEffect.length; i++) { + if (_arrEffect[i].value == effect) return _arrEffect[i].displayValue; + } + return ''; + }; + + const getEffectTypeName = type => { + for (var i=0; i < _arrCurrentEffectTypes.length; i++) { + if (_arrCurrentEffectTypes[i].value == type) return _arrCurrentEffectTypes[i].displayValue; + } + return ''; + }; + + const nameEffect = getEffectName(_effect); + const arrTypesEffect = fillEffectTypes(_effect); + const _effectType = transition.get_TransitionOption(); + const nameEffectType = getEffectTypeName(_effectType); + const _effectDuration = transition.get_TransitionDuration(); + + // console.log(_effectType); + // console.log(_effectDuration); + // console.log(transition.get_SlideAdvanceOnMouseClick()); + // console.log(transition.get_SlideAdvanceAfter()); + return ( @@ -23,16 +116,28 @@ const PageTransition = props => { - - + +
- +
- +

- - - + + { + let duration = parseInt(_effectDuration / 1000); + duration = Math.max(0, --duration); + _effectDuration = duration * 1000; + props.changeDuration(_effectDuration); + }}>- + { + let duration = parseInt(_effectDuration / 1000); + duration = Math.min(300, ++duration); + _effectDuration = duration * 1000; + props.changeDuration(_effectDuration); + }}>+

@@ -40,23 +145,33 @@ const PageTransition = props => { {_t.textStartOnClick} - + { + store.toggleStartOnClick(); + // props.onStartClick(isStartOnClick); + }} /> {_t.textDelay} - + { + store.toggleDelay(); + // props.onDelayCheck(isDelay, _effectDelay); + }} /> - + { + // changeRange() + // _effectDelay = stateRange * 1000; + // props.onDelay(_effectDelay); + }} disabled={!isDelay}> - {stateRange} s + {stateRange} {_t.textSec} - {_t.textApplyAll} + {_t.textApplyAll}
); From b7ed3bee649c4823d51e7dddde0ca9a34f5f8f0d Mon Sep 17 00:00:00 2001 From: SergeyEzhin Date: Wed, 30 Dec 2020 02:51:05 +0300 Subject: [PATCH 06/17] [PE mobile] Continue make transition settings --- apps/common/mobile/resources/less/common.less | 46 +++++++++++++++++-- .../mobile/src/controller/Main.jsx | 5 +- .../mobile/src/controller/edit/Transition.jsx | 25 +++++----- .../mobile/src/view/edit/Transition.jsx | 28 ++++++----- 4 files changed, 68 insertions(+), 36 deletions(-) diff --git a/apps/common/mobile/resources/less/common.less b/apps/common/mobile/resources/less/common.less index 7a2d26d4e..3a1cd4156 100644 --- a/apps/common/mobile/resources/less/common.less +++ b/apps/common/mobile/resources/less/common.less @@ -182,12 +182,45 @@ border-radius: 0 5px 5px 0; } } - .range-slider { - .range-bar { - height: 2px; + // .range-slider { + // .range-bar { + // height: 2px; + // } + // .range-bar-active { + // background: transparent; + // } + // } + .range-slider-delay { + width: 100%; + margin: 4px 0 5px 0; + appearance: none; + background: linear-gradient(to right,#b7b8b7 0,#b7b8b7 100%); + background-position: center; + background-size: 100% 2px; + background-repeat: no-repeat; + outline: 0; + border: none; + box-sizing: content-box; + &:disabled { + opacity: .55; } - .range-bar-active { - background: transparent; + &::-webkit-slider-thumb { + appearance: none; + height: 28px; + width: 28px; + border-radius: 50%; + background: @white; + cursor: pointer; + box-shadow: 0 2px 4px rgba(0, 0, 0, .3); + } + &::-ms-thumb { + appearance: none; + height: 28px; + width: 28px; + border-radius: 50%; + background: @white; + cursor: pointer; + box-shadow: 0 2px 4px rgba(0, 0, 0, .3); } } .slide-apply-all { @@ -196,6 +229,9 @@ .item-inner { justify-content: center; } + .item-inner::before { + display: none; + } } } diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx index 78f322d36..a8fd5d2aa 100644 --- a/apps/presentationeditor/mobile/src/controller/Main.jsx +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -196,17 +196,14 @@ class MainController extends Component { const storeTransition = this.props.storeTransition; this.api.asc_registerCallback('asc_onFocusObject', objects => { - console.log(objects); + // console.log(objects); storeFocusObjects.resetFocusObjects(objects); const settings = storeFocusObjects.settings; - console.log(settings); if(settings[0] === "slide") { const slideObject = objects[0].get_ObjectValue(); storeLayout.changeSlideLayoutIndex(slideObject.get_LayoutIndex()); - // const timing = slideObject.get_transition(); - // console.log(timing); storeTransition.addTransition(slideObject.get_transition()); } }); diff --git a/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx index 644c280ea..9e97aa536 100644 --- a/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx +++ b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx @@ -8,48 +8,49 @@ class TransitionController extends Component { onApplyAll() { const api = Common.EditorApi.get(); - console.log(api); - // api.SlideTimingApplyToAll(); + api.SlideTransitionApplyToAll(); }; - changeDuration(_effectDuration) { + changeDuration(duration) { const api = Common.EditorApi.get(); let props = new Asc.CAscSlideProps(), - timing = new Asc.CAscSlideTiming(); + timing = new Asc.CAscSlideTransition(); + _effectDuration = duration * 1000; timing.put_TransitionDuration(_effectDuration); - props.put_timing(timing); + props.put_transition(timing); api.SetSlideProps(props); }; onStartClick(value) { const api = Common.EditorApi.get(); let props = new Asc.CAscSlideProps(), - timing = new Asc.CAscSlideTiming(); + timing = new Asc.CAscSlideTransition(); timing.put_SlideAdvanceOnMouseClick(value); - props.put_timing(timing); + props.put_transition(timing); api.SetSlideProps(props); }; onDelayCheck(value, _effectDelay) { const api = Common.EditorApi.get(); let props = new Asc.CAscSlideProps(), - timing = new Asc.CAscSlideTiming(); + timing = new Asc.CAscSlideTransition(); timing.put_SlideAdvanceAfter(value); timing.put_SlideAdvanceDuration(_effectDelay); - props.put_timing(timing); + props.put_transition(timing); api.SetSlideProps(props); } - onDelay(_effectDelay) { + onDelay(value) { const api = Common.EditorApi.get(); let props = new Asc.CAscSlideProps(), - timing = new Asc.CAscSlideTiming(); + timing = new Asc.CAscSlideTransition(), + _effectDelay = value * 1000; timing.put_SlideAdvanceDuration(_effectDelay); - props.put_timing(timing); + props.put_transition(timing); api.SetSlideProps(props); }; diff --git a/apps/presentationeditor/mobile/src/view/edit/Transition.jsx b/apps/presentationeditor/mobile/src/view/edit/Transition.jsx index 571fd62b3..b388794c7 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Transition.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Transition.jsx @@ -12,8 +12,8 @@ const PageTransition = props => { let _arrCurrentEffectTypes; let _effectDelay = transition.get_SlideAdvanceDuration(); - const [stateRange, changeRange] = useState((_effectDelay !== null && _effectDelay !== undefined) ? parseInt(_effectDelay / 1000.) : 0); + const [stateRange, changeRange] = useState((_effectDelay !== null && _effectDelay !== undefined) ? parseInt(_effectDelay / 1000.) : 0); const isDelay = store.isDelay; const isStartOnClick = store.isStartOnClick; @@ -126,17 +126,15 @@ const PageTransition = props => {

- { + { let duration = parseInt(_effectDuration / 1000); duration = Math.max(0, --duration); - _effectDuration = duration * 1000; - props.changeDuration(_effectDuration); + props.changeDuration(duration); }}>- - { + { let duration = parseInt(_effectDuration / 1000); duration = Math.min(300, ++duration); - _effectDuration = duration * 1000; - props.changeDuration(_effectDuration); + props.changeDuration(duration); }}>+

@@ -147,23 +145,23 @@ const PageTransition = props => { {_t.textStartOnClick} { store.toggleStartOnClick(); - // props.onStartClick(isStartOnClick); + props.onStartClick(isStartOnClick); }} /> {_t.textDelay} { store.toggleDelay(); - // props.onDelayCheck(isDelay, _effectDelay); + props.onDelayCheck(isDelay, _effectDelay); }} /> - { - // changeRange() - // _effectDelay = stateRange * 1000; - // props.onDelay(_effectDelay); - }} disabled={!isDelay}> + { + changeRange(e.target.value); + props.onDelay(stateRange); + }} disabled={!isDelay} /> {stateRange} {_t.textSec} @@ -171,7 +169,7 @@ const PageTransition = props => { - {_t.textApplyAll} + {_t.textApplyAll}
); From b92ba29b6f5807becf193806af2f71c53f989806 Mon Sep 17 00:00:00 2001 From: SergeyEzhin Date: Thu, 31 Dec 2020 02:18:22 +0300 Subject: [PATCH 07/17] [PE mobile] Edited store, views and continue make settings --- .../mobile/src/controller/Main.jsx | 15 ++- .../mobile/src/controller/edit/Effect.jsx | 26 ++-- .../mobile/src/controller/edit/Transition.jsx | 29 ++++- .../mobile/src/store/effect.js | 5 - .../mobile/src/store/focusObjects.js | 15 +++ .../mobile/src/store/mainStore.js | 6 +- .../mobile/src/store/transition.js | 18 +-- .../mobile/src/store/type.js | 5 - .../mobile/src/view/edit/Edit.jsx | 8 +- .../mobile/src/view/edit/Effect.jsx | 48 ++++---- .../mobile/src/view/edit/Layout.jsx | 12 +- .../mobile/src/view/edit/Transition.jsx | 113 ++++++++++++------ 12 files changed, 182 insertions(+), 118 deletions(-) delete mode 100644 apps/presentationeditor/mobile/src/store/effect.js delete mode 100644 apps/presentationeditor/mobile/src/store/type.js diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx index a8fd5d2aa..0cda019e2 100644 --- a/apps/presentationeditor/mobile/src/controller/Main.jsx +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -193,19 +193,18 @@ class MainController extends Component { const storeFocusObjects = this.props.storeFocusObjects; const storeLayout = this.props.storeLayout; - const storeTransition = this.props.storeTransition; - + this.api.asc_registerCallback('asc_onFocusObject', objects => { // console.log(objects); storeFocusObjects.resetFocusObjects(objects); - const settings = storeFocusObjects.settings; + // const settings = storeFocusObjects.settings; - if(settings[0] === "slide") { - const slideObject = objects[0].get_ObjectValue(); - storeLayout.changeSlideLayoutIndex(slideObject.get_LayoutIndex()); - storeTransition.addTransition(slideObject.get_transition()); - } + // if(settings[0] === "slide") { + // const slideObject = objects[0].get_ObjectValue(); + // storeLayout.changeSlideLayoutIndex(slideObject.get_LayoutIndex()); + // storeTransition.initTransition(slideObject.get_transition()); + // } }); const storeTheme = this.props.storeTheme; diff --git a/apps/presentationeditor/mobile/src/controller/edit/Effect.jsx b/apps/presentationeditor/mobile/src/controller/edit/Effect.jsx index 147b57e61..65f529a03 100644 --- a/apps/presentationeditor/mobile/src/controller/edit/Effect.jsx +++ b/apps/presentationeditor/mobile/src/controller/edit/Effect.jsx @@ -1,16 +1,16 @@ -import React, { Component } from "react"; -import Effect from "../../view/edit/Effect"; +// import React, { Component } from "react"; +// import Effect from "../../view/edit/Effect"; -class EffectController extends Component { - constructor(props) { - super(props); - } +// class EffectController extends Component { +// constructor(props) { +// super(props); +// } - render() { - return ( - - ); - } -} +// render() { +// return ( +// +// ); +// } +// } -export default EffectController; \ No newline at end of file +// export default EffectController; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx index 9e97aa536..e8df180f7 100644 --- a/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx +++ b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx @@ -1,10 +1,9 @@ import React, { Component } from "react"; -import Transition from "../../view/edit/Transition"; - +import {Transition} from "../../view/edit/Transition"; class TransitionController extends Component { constructor(props) { super(props); - } + }; onApplyAll() { const api = Common.EditorApi.get(); @@ -13,8 +12,9 @@ class TransitionController extends Component { changeDuration(duration) { const api = Common.EditorApi.get(); + let props = new Asc.CAscSlideProps(), - timing = new Asc.CAscSlideTransition(); + timing = new Asc.CAscSlideTransition(), _effectDuration = duration * 1000; timing.put_TransitionDuration(_effectDuration); @@ -24,6 +24,7 @@ class TransitionController extends Component { onStartClick(value) { const api = Common.EditorApi.get(); + let props = new Asc.CAscSlideProps(), timing = new Asc.CAscSlideTransition(); @@ -34,6 +35,7 @@ class TransitionController extends Component { onDelayCheck(value, _effectDelay) { const api = Common.EditorApi.get(); + let props = new Asc.CAscSlideProps(), timing = new Asc.CAscSlideTransition(); @@ -41,10 +43,11 @@ class TransitionController extends Component { timing.put_SlideAdvanceDuration(_effectDelay); props.put_transition(timing); api.SetSlideProps(props); - } + }; onDelay(value) { const api = Common.EditorApi.get(); + let props = new Asc.CAscSlideProps(), timing = new Asc.CAscSlideTransition(), _effectDelay = value * 1000; @@ -54,13 +57,29 @@ class TransitionController extends Component { api.SetSlideProps(props); }; + onEffectClick(value) { + const api = Common.EditorApi.get(); + + // let props = new Asc.CAscSlideProps(), + // timing = new Asc.CAscSlideTransition(), + // _effectType = this.fillEffectTypes(value); + + // timing.put_TransitionType(value); + // timing.put_TransitionOption(_effectType); + // props.put_transition(timing); + // api.SetSlideProps(props); + + }; + render() { return ( ); } diff --git a/apps/presentationeditor/mobile/src/store/effect.js b/apps/presentationeditor/mobile/src/store/effect.js deleted file mode 100644 index aee5a0782..000000000 --- a/apps/presentationeditor/mobile/src/store/effect.js +++ /dev/null @@ -1,5 +0,0 @@ -import {action, observable} from 'mobx'; - -export class storeEffect { - -} \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/store/focusObjects.js b/apps/presentationeditor/mobile/src/store/focusObjects.js index c3be75a17..12ac4d517 100644 --- a/apps/presentationeditor/mobile/src/store/focusObjects.js +++ b/apps/presentationeditor/mobile/src/store/focusObjects.js @@ -52,4 +52,19 @@ export class storeFocusObjects { } return resultArr; } + + @computed get slideObject() { + const slides = []; + for (let object of this._focusObjects) { + if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Slide) { + slides.push(object); + } + } + if (slides.length > 0) { + const object = slides[slides.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 604465a0a..a022c8999 100644 --- a/apps/presentationeditor/mobile/src/store/mainStore.js +++ b/apps/presentationeditor/mobile/src/store/mainStore.js @@ -9,8 +9,6 @@ import {storePresentationSettings} from './presentationSettings'; import { storeLayout } from './layout'; import { storeTransition } from './transition'; import { storeTheme } from './theme'; -import { storeEffect } from './effect'; -import { storeType } from './type'; // import {storeTextSettings} from "./textSettings"; // import {storeParagraphSettings} from "./paragraphSettings"; // import {storeShapeSettings} from "./shapeSettings"; @@ -28,9 +26,7 @@ export const stores = { storePresentationSettings: new storePresentationSettings(), storeLayout: new storeLayout(), storeTransition: new storeTransition(), - storeTheme: new storeTheme(), - storeEffect: new storeEffect(), - storeType: new storeType() + storeTheme: new storeTheme() // storeTextSettings: new storeTextSettings(), // storeParagraphSettings: new storeParagraphSettings(), // storeShapeSettings: new storeShapeSettings(), diff --git a/apps/presentationeditor/mobile/src/store/transition.js b/apps/presentationeditor/mobile/src/store/transition.js index e7e511942..e6f3e6d17 100644 --- a/apps/presentationeditor/mobile/src/store/transition.js +++ b/apps/presentationeditor/mobile/src/store/transition.js @@ -1,20 +1,10 @@ import {action, observable} from 'mobx'; export class storeTransition { - - @observable transition = {}; - @observable isDelay = false; - @observable isStartOnClick = true; - @action toggleDelay() { - this.isDelay = !this.isDelay; - } - - @action toggleStartOnClick() { - this.isStartOnClick = !this.isStartOnClick; - } - - @action addTransition(obj) { - this.transition = obj; + @observable effect; + + @action changeEffect(value) { + this.effect = value; } } \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/store/type.js b/apps/presentationeditor/mobile/src/store/type.js deleted file mode 100644 index a019c6a94..000000000 --- a/apps/presentationeditor/mobile/src/store/type.js +++ /dev/null @@ -1,5 +0,0 @@ -import {action, observable} from 'mobx'; - -export class storeType { - -} \ 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 db47714e8..cc14da078 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Edit.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Edit.jsx @@ -10,8 +10,8 @@ import EditTextController from "../../controller/edit/EditText"; import LayoutController from "../../controller/edit/Layout"; import TransitionController from '../../controller/edit/Transition'; import ThemeController from '../../controller/edit/Theme'; -import EffectController from '../../controller/edit/Effect'; -import TypeController from '../../controller/edit/Type'; +import { Effect } from './Transition'; +import { Type } from './Transition'; //import EditShapeController from "../../controller/edit/EditShape"; //import EditImageController from "../../controller/edit/EditImage"; //import EditTableController from "../../controller/edit/EditTable"; @@ -33,11 +33,11 @@ const routes = [ }, { path: '/effect/', - component: EffectController + component: Effect }, { path: '/type/', - component: TypeController + component: Type } ]; diff --git a/apps/presentationeditor/mobile/src/view/edit/Effect.jsx b/apps/presentationeditor/mobile/src/view/edit/Effect.jsx index 0a6924890..1557bf4a5 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Effect.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Effect.jsx @@ -1,24 +1,32 @@ -import React, {useState} from "react"; -import { observer, inject } from "mobx-react"; -import { Page, Navbar, List, ListItem, NavRight, Link, Toggle, Range, ListItemCell } from "framework7-react"; -import { useTranslation } from "react-i18next"; +// import React, {useState} from "react"; +// import { observer, inject } from "mobx-react"; +// import { Page, Navbar, List, ListItem } from "framework7-react"; +// import { useTranslation } from "react-i18next"; -const PageEffect= props => { - const { t } = useTranslation(); - const _t = t("View.Edit", { returnObjects: true }); +// const PageEffect= props => { +// const { t } = useTranslation(); +// const _t = t("View.Edit", { returnObjects: true }); +// console.log(props); +// const arrEffect = props.arrEffect; +// const effect = props.effect; - return ( - - - - - - - - - ); -}; +// return ( +// +// +// {arrEffect.length ? ( +// +// {arrEffect.map((elem, index) => { +// return ( +// +// ) +// })} +// +// ) : null} +// +// ); +// }; -const Effect = inject("storeEffect")(observer(PageEffect)); +// const Effect = inject("storeEffect")(observer(PageEffect)); -export default Effect; \ No newline at end of file +// export default Effect; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/view/edit/Layout.jsx b/apps/presentationeditor/mobile/src/view/edit/Layout.jsx index bb2ed0d5a..b74547b5d 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Layout.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Layout.jsx @@ -6,9 +6,11 @@ import { useTranslation } from "react-i18next"; const PageLayout = props => { const { t } = useTranslation(); const _t = t("View.Edit", { returnObjects: true }); - const store = props.storeLayout; - const arrayLayouts = JSON.parse(JSON.stringify(store.arrayLayouts)); - const slideLayoutIndex = store.slideLayoutIndex; + const storeFocusObjects = props.storeFocusObjects; + const storeLayout = props.storeLayout; + storeLayout.changeSlideLayoutIndex(storeFocusObjects.slideObject.get_LayoutIndex()); + const arrayLayouts = JSON.parse(JSON.stringify(storeLayout.arrayLayouts)); + const slideLayoutIndex = storeLayout.slideLayoutIndex; console.log(slideLayoutIndex); console.log(arrayLayouts); @@ -26,7 +28,7 @@ const PageLayout = props => { return ( { - store.changeSlideLayoutIndex(index); + storeLayout.changeSlideLayoutIndex(index); props.onLayoutClick(index); }}> @@ -39,6 +41,6 @@ const PageLayout = props => { ); }; -const Layout = inject("storeLayout")(observer(PageLayout)); +const Layout = inject("storeLayout", "storeFocusObjects")(observer(PageLayout)); export default Layout; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/view/edit/Transition.jsx b/apps/presentationeditor/mobile/src/view/edit/Transition.jsx index b388794c7..4dc1dd91b 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Transition.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Transition.jsx @@ -6,17 +6,6 @@ import { useTranslation } from "react-i18next"; const PageTransition = props => { const { t } = useTranslation(); const _t = t("View.Edit", { returnObjects: true }); - const store = props.storeTransition; - const transition = store.transition; - const _effect = transition.get_TransitionType(); - - let _arrCurrentEffectTypes; - let _effectDelay = transition.get_SlideAdvanceDuration(); - - const [stateRange, changeRange] = useState((_effectDelay !== null && _effectDelay !== undefined) ? parseInt(_effectDelay / 1000.) : 0); - const isDelay = store.isDelay; - const isStartOnClick = store.isStartOnClick; - const _arrEffect = [ {displayValue: _t.textNone, value: Asc.c_oAscSlideTransitionTypes.None}, {displayValue: _t.textFade, value: Asc.c_oAscSlideTransitionTypes.Fade}, @@ -28,7 +17,6 @@ const PageTransition = props => { {displayValue: _t.textClock, value: Asc.c_oAscSlideTransitionTypes.Clock}, {displayValue: _t.textZoom, value: Asc.c_oAscSlideTransitionTypes.Zoom} ]; - const _arrEffectType = [ {displayValue: _t.textSmoothly, value: Asc.c_oAscSlideTransitionParams.Fade_Smoothly}, {displayValue: _t.textBlack, value: Asc.c_oAscSlideTransitionParams.Fade_Through_Black}, @@ -52,6 +40,8 @@ const PageTransition = props => { {displayValue: _t.textZoomRotate, value: Asc.c_oAscSlideTransitionParams.Zoom_AndRotate} ]; + let _arrCurrentEffectTypes = []; + const fillEffectTypes = type => { _arrCurrentEffectTypes = []; switch (type) { @@ -82,14 +72,14 @@ const PageTransition = props => { } return (_arrCurrentEffectTypes.length > 0) ? _arrCurrentEffectTypes[0].value : -1; }; - + const getEffectName = effect => { for (var i=0; i < _arrEffect.length; i++) { if (_arrEffect[i].value == effect) return _arrEffect[i].displayValue; } return ''; }; - + const getEffectTypeName = type => { for (var i=0; i < _arrCurrentEffectTypes.length; i++) { if (_arrCurrentEffectTypes[i].value == type) return _arrCurrentEffectTypes[i].displayValue; @@ -97,16 +87,22 @@ const PageTransition = props => { return ''; }; - const nameEffect = getEffectName(_effect); - const arrTypesEffect = fillEffectTypes(_effect); - const _effectType = transition.get_TransitionOption(); - const nameEffectType = getEffectTypeName(_effectType); - const _effectDuration = transition.get_TransitionDuration(); + const storeFocusObjects = props.storeFocusObjects; + const storeTransition = props.storeTransition; + const transitionObj = storeFocusObjects.slideObject.get_transition(); + storeTransition.changeEffect(transitionObj.get_TransitionType()); + const _effect = storeTransition.effect; - // console.log(_effectType); - // console.log(_effectDuration); - // console.log(transition.get_SlideAdvanceOnMouseClick()); - // console.log(transition.get_SlideAdvanceAfter()); + let _effectDelay = transitionObj.get_SlideAdvanceDuration(); + + const [stateRange, changeRange] = useState((_effectDelay !== null && _effectDelay !== undefined) ? parseInt(_effectDelay / 1000.) : 0); + const isDelay = transitionObj.get_SlideAdvanceAfter(); + const isStartOnClick = transitionObj.get_SlideAdvanceOnMouseClick(); + const nameEffect = getEffectName(_effect); + const arrEffectType = fillEffectTypes(_effect); + const _effectType = transitionObj.get_TransitionOption(); + const nameEffectType = getEffectTypeName(_effectType); + const _effectDuration = transitionObj.get_TransitionDuration(); return ( @@ -116,7 +112,10 @@ const PageTransition = props => { - + @@ -143,17 +142,11 @@ const PageTransition = props => { {_t.textStartOnClick} - { - store.toggleStartOnClick(); - props.onStartClick(isStartOnClick); - }} /> + {props.onStartClick(!isStartOnClick)}} /> {_t.textDelay} - { - store.toggleDelay(); - props.onDelayCheck(isDelay, _effectDelay); - }} /> + {props.onDelayCheck(!isDelay, _effectDelay)}} /> @@ -175,6 +168,58 @@ const PageTransition = props => { ); }; -const Transition = inject("storeTransition")(observer(PageTransition)); -export default Transition; \ No newline at end of file +const PageEffect = props => { + const { t } = useTranslation(); + const _t = t("View.Edit", { returnObjects: true }); + const storeTransition = props.storeTransition; + const _effect = storeTransition.effect; + const _arrEffect = props._arrEffect; + + return ( + + + {_arrEffect.length ? ( + + {_arrEffect.map((elem, index) => { + return ( + { + storeTransition.changeEffect(elem.value); + props.onEffectClick(elem.value); + }}> + ) + })} + + ) : null} + + ); +}; + +const PageType= props => { + const { t } = useTranslation(); + const _t = t("View.Edit", { returnObjects: true }); + console.log(props); + const storeTransition = props.storeTransition; + + return ( + + + + + + + + + + + + + ); +}; + +const Effect = inject("storeTransition", "storeFocusObjects")(observer(PageEffect)); +const Type = inject("storeTransition", "storeFocusObjects")(observer(PageType)); +const Transition = inject("storeTransition", "storeFocusObjects")(observer(PageTransition)); + +export {Transition, Effect, Type}; \ No newline at end of file From 4feecef046663e241a8556fa806bd67e003d1ebe Mon Sep 17 00:00:00 2001 From: SergeyEzhin Date: Mon, 11 Jan 2021 17:29:59 +0300 Subject: [PATCH 08/17] [PE mobile] Maked Layout, Theme and Transition Settings --- apps/common/mobile/resources/less/common.less | 119 +++++++++--------- .../mobile/src/controller/edit/Transition.jsx | 30 +++-- .../mobile/src/store/transition.js | 5 + .../mobile/src/view/edit/Layout.jsx | 6 +- .../mobile/src/view/edit/Theme.jsx | 6 +- .../mobile/src/view/edit/Transition.jsx | 61 ++++++--- 6 files changed, 131 insertions(+), 96 deletions(-) diff --git a/apps/common/mobile/resources/less/common.less b/apps/common/mobile/resources/less/common.less index 3a1cd4156..9bc7c4338 100644 --- a/apps/common/mobile/resources/less/common.less +++ b/apps/common/mobile/resources/less/common.less @@ -74,7 +74,7 @@ // Layout .slide-layout { - .list { + &__list { margin: auto; } ul { @@ -115,25 +115,21 @@ // Theme -.slide-theme .item-theme { - background-image: url(../img/themes/themes.png); -} - .slide-theme { + &__list { + margin: auto; + ul { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + padding-left: 18px; + padding-right: 18px; + padding-bottom: 14px; + } + } .item-inner:after { display: none; } - .list { - margin: auto; - } - ul { - display: flex; - justify-content: space-between; - flex-wrap: wrap; - padding-left: 18px; - padding-right: 18px; - padding-bottom: 14px; - } .item-theme { position: relative; margin: 0; @@ -141,6 +137,7 @@ width: 85px; height: 38px; margin-top: 14px; + background-image: url(../img/themes/themes.png); } .item-theme.active:before { content: ''; @@ -182,54 +179,50 @@ border-radius: 0 5px 5px 0; } } - // .range-slider { - // .range-bar { - // height: 2px; - // } - // .range-bar-active { - // background: transparent; - // } - // } - .range-slider-delay { - width: 100%; - margin: 4px 0 5px 0; - appearance: none; - background: linear-gradient(to right,#b7b8b7 0,#b7b8b7 100%); - background-position: center; - background-size: 100% 2px; - background-repeat: no-repeat; - outline: 0; - border: none; - box-sizing: content-box; - &:disabled { - opacity: .55; - } - &::-webkit-slider-thumb { - appearance: none; - height: 28px; - width: 28px; - border-radius: 50%; - background: @white; - cursor: pointer; - box-shadow: 0 2px 4px rgba(0, 0, 0, .3); - } - &::-ms-thumb { - appearance: none; - height: 28px; - width: 28px; - border-radius: 50%; - background: @white; - cursor: pointer; - box-shadow: 0 2px 4px rgba(0, 0, 0, .3); - } +} + +.range-slider-delay { + width: 100%; + margin: 4px 0 5px 0; + appearance: none; + background: linear-gradient(to right,#b7b8b7 0,#b7b8b7 100%); + background-position: center; + background-size: 100% 2px; + background-repeat: no-repeat; + outline: 0; + border: none; + box-sizing: content-box; + &:disabled { + opacity: .55; } - .slide-apply-all { - color: @themeColor; - border: 0; - .item-inner { - justify-content: center; - } - .item-inner::before { + &::-webkit-slider-thumb { + appearance: none; + height: 28px; + width: 28px; + border-radius: 50%; + background: @white; + cursor: pointer; + box-shadow: 0 2px 4px rgba(0, 0, 0, .3); + } + &::-ms-thumb { + appearance: none; + height: 28px; + width: 28px; + border-radius: 50%; + background: @white; + cursor: pointer; + box-shadow: 0 2px 4px rgba(0, 0, 0, .3); + } +} + +.apply-all { + color: @themeColor; + border: 0; + .item-inner { + justify-content: center; + } + &__elem { + .item-link .item-inner::before { display: none; } } diff --git a/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx index e8df180f7..d9a217472 100644 --- a/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx +++ b/apps/presentationeditor/mobile/src/controller/edit/Transition.jsx @@ -57,20 +57,31 @@ class TransitionController extends Component { api.SetSlideProps(props); }; - onEffectClick(value) { + onEffectClick(value, effectType) { const api = Common.EditorApi.get(); - // let props = new Asc.CAscSlideProps(), - // timing = new Asc.CAscSlideTransition(), - // _effectType = this.fillEffectTypes(value); + let props = new Asc.CAscSlideProps(), + timing = new Asc.CAscSlideTransition(); + // _effectType = this.fillEffectTypes(value); - // timing.put_TransitionType(value); - // timing.put_TransitionOption(_effectType); - // props.put_transition(timing); - // api.SetSlideProps(props); - + timing.put_TransitionType(value); + timing.put_TransitionOption(effectType); + props.put_transition(timing); + api.SetSlideProps(props); }; + onEffectTypeClick(value, effect) { + const api = Common.EditorApi.get(); + + let props = new Asc.CAscSlideProps(), + timing = new Asc.CAscSlideTransition(); + + timing.put_TransitionType(effect); + timing.put_TransitionOption(value); + props.put_transition(timing); + api.SetSlideProps(props); + } + render() { return ( ); } diff --git a/apps/presentationeditor/mobile/src/store/transition.js b/apps/presentationeditor/mobile/src/store/transition.js index e6f3e6d17..d537e66e6 100644 --- a/apps/presentationeditor/mobile/src/store/transition.js +++ b/apps/presentationeditor/mobile/src/store/transition.js @@ -3,8 +3,13 @@ import {action, observable} from 'mobx'; export class storeTransition { @observable effect; + @observable type; @action changeEffect(value) { this.effect = value; } + + @action changeType(value) { + this.type = value; + } } \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/view/edit/Layout.jsx b/apps/presentationeditor/mobile/src/view/edit/Layout.jsx index b74547b5d..b543fcbce 100644 --- a/apps/presentationeditor/mobile/src/view/edit/Layout.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/Layout.jsx @@ -12,8 +12,8 @@ const PageLayout = props => { const arrayLayouts = JSON.parse(JSON.stringify(storeLayout.arrayLayouts)); const slideLayoutIndex = storeLayout.slideLayoutIndex; - console.log(slideLayoutIndex); - console.log(arrayLayouts); + // console.log(slideLayoutIndex); + // console.log(arrayLayouts); return ( @@ -23,7 +23,7 @@ const PageLayout = props => { {arrayLayouts.length ? ( - + {arrayLayouts.map((elem, index) => { return ( { const defaultThemes = arrayThemes[0]; const docThemes = arrayThemes[1]; - console.log(slideThemeIndex); - console.log(arrayThemes); + // console.log(slideThemeIndex); + // console.log(arrayThemes); return ( @@ -23,7 +23,7 @@ const PageTheme = props => { {arrayThemes.length ? ( - + {defaultThemes.map((elem, index) => { return ( { } return (_arrCurrentEffectTypes.length > 0) ? _arrCurrentEffectTypes[0].value : -1; }; - + const getEffectName = effect => { for (var i=0; i < _arrEffect.length; i++) { if (_arrEffect[i].value == effect) return _arrEffect[i].displayValue; @@ -90,16 +90,25 @@ const PageTransition = props => { const storeFocusObjects = props.storeFocusObjects; const storeTransition = props.storeTransition; const transitionObj = storeFocusObjects.slideObject.get_transition(); - storeTransition.changeEffect(transitionObj.get_TransitionType()); - const _effect = storeTransition.effect; + if(!storeTransition.effect) { + storeTransition.changeEffect(transitionObj.get_TransitionType()); + } + + const _effect = storeTransition.effect; + const valueEffectTypes = fillEffectTypes(_effect); + + if(!storeTransition.type) { + storeTransition.changeType(valueEffectTypes); + } + let _effectDelay = transitionObj.get_SlideAdvanceDuration(); const [stateRange, changeRange] = useState((_effectDelay !== null && _effectDelay !== undefined) ? parseInt(_effectDelay / 1000.) : 0); const isDelay = transitionObj.get_SlideAdvanceAfter(); const isStartOnClick = transitionObj.get_SlideAdvanceOnMouseClick(); const nameEffect = getEffectName(_effect); - const arrEffectType = fillEffectTypes(_effect); + const _effectType = transitionObj.get_TransitionOption(); const nameEffectType = getEffectTypeName(_effectType); const _effectDuration = transitionObj.get_TransitionDuration(); @@ -114,12 +123,15 @@ const PageTransition = props => { - -
+ disabled={_effect == Asc.c_oAscSlideTransitionTypes.None} routeProps={{ + _arrCurrentEffectTypes, + onEffectTypeClick: props.onEffectTypeClick + }}>
@@ -161,8 +173,8 @@ const PageTransition = props => { - - {_t.textApplyAll} + + {_t.textApplyAll} ); @@ -175,7 +187,7 @@ const PageEffect = props => { const storeTransition = props.storeTransition; const _effect = storeTransition.effect; const _arrEffect = props._arrEffect; - + return ( @@ -186,7 +198,9 @@ const PageEffect = props => { { storeTransition.changeEffect(elem.value); - props.onEffectClick(elem.value); + let valueEffectTypes = props.fillEffectTypes(elem.value); + storeTransition.changeType(valueEffectTypes); + props.onEffectClick(elem.value, valueEffectTypes); }}> ) })} @@ -199,8 +213,10 @@ const PageEffect = props => { const PageType= props => { const { t } = useTranslation(); const _t = t("View.Edit", { returnObjects: true }); - console.log(props); + const _arrCurrentEffectTypes = props._arrCurrentEffectTypes; const storeTransition = props.storeTransition; + const _effect = storeTransition.effect; + const type = storeTransition.type; return ( @@ -209,11 +225,20 @@ const PageType= props => { - - - - - + {_arrCurrentEffectTypes.length ? ( + + {_arrCurrentEffectTypes.map((elem, index) => { + return ( + { + storeTransition.changeType(elem.value); + props.onEffectTypeClick(elem.value, _effect); + }}> + + ) + })} + + ) : null} ); }; From ec952c8cf3232c4db518aa072b741287eb449780 Mon Sep 17 00:00:00 2001 From: Maxim Kadushkin Date: Tue, 12 Jan 2021 14:06:39 +0300 Subject: [PATCH 09/17] [PE mobile] removed build warning --- .../mobile/src/controller/settings/PresentationSettings.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/presentationeditor/mobile/src/controller/settings/PresentationSettings.jsx b/apps/presentationeditor/mobile/src/controller/settings/PresentationSettings.jsx index 144d4a66e..1a1099035 100644 --- a/apps/presentationeditor/mobile/src/controller/settings/PresentationSettings.jsx +++ b/apps/presentationeditor/mobile/src/controller/settings/PresentationSettings.jsx @@ -1,4 +1,4 @@ -import React, {Component} from 'React'; +import React, {Component} from 'react'; import { observer, inject } from "mobx-react"; import {PresentationSettings} from '../../view/settings/PresentationSettings'; From 9d02e5ef86c8283dbc2b08155dd363aa9dfcf355 Mon Sep 17 00:00:00 2001 From: SergeyEzhin Date: Tue, 12 Jan 2021 16:51:57 +0300 Subject: [PATCH 10/17] [PE mobile] Start to make Style Settings --- apps/presentationeditor/mobile/locale/en.json | 11 ++++- .../mobile/src/controller/Main.jsx | 4 ++ .../mobile/src/controller/edit/Style.jsx | 16 +++++++ .../mobile/src/store/mainStore.js | 6 ++- .../mobile/src/store/palette.js | 9 ++++ .../mobile/src/store/style.js | 23 ++++++++++ .../mobile/src/view/edit/Edit.jsx | 5 +++ .../mobile/src/view/edit/EditSlide.jsx | 2 +- .../mobile/src/view/edit/Style.jsx | 43 +++++++++++++++++++ 9 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 apps/presentationeditor/mobile/src/controller/edit/Style.jsx create mode 100644 apps/presentationeditor/mobile/src/store/palette.js create mode 100644 apps/presentationeditor/mobile/src/store/style.js create mode 100644 apps/presentationeditor/mobile/src/view/edit/Style.jsx diff --git a/apps/presentationeditor/mobile/locale/en.json b/apps/presentationeditor/mobile/locale/en.json index 0e99c1e05..94050c126 100644 --- a/apps/presentationeditor/mobile/locale/en.json +++ b/apps/presentationeditor/mobile/locale/en.json @@ -122,7 +122,16 @@ "textZoomIn": "Zoom In", "textZoomOut": "Zoom Out", "textZoomRotate": "Zoom and Rotate", - "textSec": "s" + "textSec": "s", + "textAddCustomColor": "Add Custom Color", + "textFill": "Fill" + } + }, + "Common": { + "ThemeColorPalette": { + "textThemeColors": "Theme Colors", + "textStandardColors": "Standard Colors", + "textCustomColors": "Custom Colors" } } } \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx index 0cda019e2..8ff4b3297 100644 --- a/apps/presentationeditor/mobile/src/controller/Main.jsx +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -224,6 +224,10 @@ class MainController extends Component { storeLayout.addArrayLayouts(layouts); }); + this.api.asc_registerCallback('asc_onSendThemeColors', (colors, standart_colors) => { + Common.Utils.ThemeColor.setColors(colors, standart_colors); + }); + } _onDocumentContentReady() { diff --git a/apps/presentationeditor/mobile/src/controller/edit/Style.jsx b/apps/presentationeditor/mobile/src/controller/edit/Style.jsx new file mode 100644 index 000000000..67567013e --- /dev/null +++ b/apps/presentationeditor/mobile/src/controller/edit/Style.jsx @@ -0,0 +1,16 @@ +import React, { Component } from "react"; +import Style from "../../view/edit/Style"; + +class StyleController extends Component { + constructor(props) { + super(props); + } + + render() { + return ( +