diff --git a/apps/presentationeditor/mobile/index.html b/apps/presentationeditor/mobile/index.html
deleted file mode 100644
index f10e8f8c0..000000000
--- a/apps/presentationeditor/mobile/index.html
+++ /dev/null
@@ -1,274 +0,0 @@
-
-
-
-
-
-
-
-
-
- ONLYOFFICE Presentations
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/presentationeditor/mobile/src/app.js b/apps/presentationeditor/mobile/src/app.js
new file mode 100644
index 000000000..048ac06ae
--- /dev/null
+++ b/apps/presentationeditor/mobile/src/app.js
@@ -0,0 +1,42 @@
+// Import React and ReactDOM
+import React, { Suspense } from 'react';
+import ReactDOM from 'react-dom';
+
+// Import Framework7
+import Framework7 from 'framework7/framework7-lite.esm.bundle.js';
+
+// Import Framework7-React Plugin
+import Framework7React from 'framework7-react';
+
+import jQuery from 'jquery';
+window.jQuery = jQuery;
+window.$ = jQuery;
+
+// Import Framework7 Styles
+import 'framework7/css/framework7.bundle.css';
+
+// Import App Custom Styles
+import './less/app.less';
+
+// Import App Component
+import App from './page/app';
+import { I18nextProvider } from 'react-i18next';
+import i18n from './lib/i18n.js';
+
+import { Provider } from 'mobx-react'
+import { stores } from './store/mainStore'
+
+// Init F7 React Plugin
+Framework7.use(Framework7React)
+
+// Mount React App
+ReactDOM.render(
+
+
+
+
+
+
+ ,
+ document.getElementById('app'),
+);
\ No newline at end of file
diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx
new file mode 100644
index 000000000..06c2b87c1
--- /dev/null
+++ b/apps/presentationeditor/mobile/src/controller/Main.jsx
@@ -0,0 +1,205 @@
+
+import React, { Component } from 'react'
+import { inject } from "mobx-react";
+import { withTranslation } from 'react-i18next';
+import CollaborationController from '../../../../common/mobile/lib/controller/Collaboration.jsx'
+
+class MainController extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ initSdk() {
+ const script = document.createElement("script");
+ script.src = "../../../../sdkjs/develop/sdkjs/slide/scripts.js";
+ script.async = true;
+ script.onload = () => {
+ let dep_scripts = [
+ '../../../vendor/xregexp/xregexp-all-min.js',
+ '../../../vendor/sockjs/sockjs.min.js'];
+ dep_scripts.push(...sdk_scripts);
+
+ const promise_get_script = (scriptpath) => {
+ return new Promise((resolve, reject) => {
+ const script = document.createElement("script");
+ script.src = scriptpath;
+ script.onload = () => {
+ resolve('ok');
+ };
+ script.onerror = () => {
+ reject('error');
+ };
+
+ document.body.appendChild(script);
+ });
+ };
+
+ const loadConfig = data => {
+ let me = this;
+ console.log('load config');
+
+ me.editorConfig = Object.assign({}, this.editorConfig, data.config);
+ me.appOptions.user = Common.Utils.fillUserInfo(me.editorConfig.user, me.editorConfig.lang, "Local.User"/*me.textAnonymous*/);
+ };
+
+ const loadDocument = data => {
+ this.permissions = {};
+ this.document = data.doc;
+
+ let docInfo = {};
+
+ if (data.doc) {
+ this.permissions = Object.assign(this.permissions, data.doc.permissions);
+
+ let _permissions = Object.assign({}, data.doc.permissions),
+ _user = new Asc.asc_CUserInfo();
+ _user.put_Id(this.appOptions.user.id);
+ _user.put_FullName(this.appOptions.user.fullname);
+
+ docInfo = new Asc.asc_CDocInfo();
+ docInfo.put_Id(data.doc.key);
+ docInfo.put_Url(data.doc.url);
+ docInfo.put_Title(data.doc.title);
+ docInfo.put_Format(data.doc.fileType);
+ docInfo.put_VKey(data.doc.vkey);
+ docInfo.put_Options(data.doc.options);
+ docInfo.put_UserInfo(_user);
+ docInfo.put_CallbackUrl(this.editorConfig.callbackUrl);
+ docInfo.put_Token(data.doc.token);
+ docInfo.put_Permissions(_permissions);
+ docInfo.put_EncryptedInfo(this.editorConfig.encryptionKeys);
+
+ // var enable = !this.editorConfig.customization || (this.editorConfig.customization.macros!==false);
+ // docInfo.asc_putIsEnabledMacroses(!!enable);
+ // enable = !this.editorConfig.customization || (this.editorConfig.customization.plugins!==false);
+ // docInfo.asc_putIsEnabledPlugins(!!enable);
+ }
+
+ this.api.asc_registerCallback('asc_onGetEditorPermissions', onEditorPermissions);
+ // this.api.asc_registerCallback('asc_onLicenseChanged', _.bind(this.onLicenseChanged, this));
+ // this.api.asc_registerCallback('asc_onRunAutostartMacroses', _.bind(this.onRunAutostartMacroses, this));
+ this.api.asc_setDocInfo(docInfo);
+ this.api.asc_getEditorPermissions(this.editorConfig.licenseUrl, this.editorConfig.customerId);
+
+ // Common.SharedSettings.set('document', data.doc);
+
+ // if (data.doc) {
+ // DE.getController('Toolbar').setDocumentTitle(data.doc.title);
+ // if (data.doc.info) {
+ // data.doc.info.author && console.log("Obsolete: The 'author' parameter of the document 'info' section is deprecated. Please use 'owner' instead.");
+ // data.doc.info.created && console.log("Obsolete: The 'created' parameter of the document 'info' section is deprecated. Please use 'uploaded' instead.");
+ // }
+ // }
+ };
+
+ const onEditorPermissions = params => {
+ let me = this;
+ const licType = params.asc_getLicenseType();
+
+ me.appOptions.canLicense = (licType === Asc.c_oLicenseResult.Success || licType === Asc.c_oLicenseResult.SuccessLimit);
+ // me.appOptions.canEdit = (me.permissions.edit !== false || me.permissions.review === true) && // can edit or review
+ // (me.editorConfig.canRequestEditRights || me.editorConfig.mode !== 'view') && // if mode=="view" -> canRequestEditRights must be defined
+ // (!me.appOptions.isReviewOnly || me.appOptions.canLicense) && // if isReviewOnly==true -> canLicense must be true
+ // me.isSupportEditFeature();
+ // me.appOptions.isEdit = me.appOptions.canLicense && me.appOptions.canEdit && me.editorConfig.mode !== 'view';
+
+ // me.api.asc_setViewMode(!me.appOptions.isEdit);
+ me.api.asc_setViewMode(false);
+ me.api.asc_LoadDocument();
+ };
+
+ const _process_array = (array, fn) => {
+ let results = [];
+ return array.reduce(function(p, item) {
+ return p.then(function() {
+ return fn(item).then(function(data) {
+ results.push(data);
+ return results;
+ });
+ });
+ }, Promise.resolve());
+ };
+
+ _process_array(dep_scripts, promise_get_script)
+ .then ( result => {
+ const {t} = this.props;
+ this.api = new Asc.asc_docs_api({
+ 'id-view': 'editor_sdk',
+ 'mobile': true,
+ 'translate': t('Controller.Main.SDK', {returnObjects:true})
+ });
+
+ this.appOptions = {};
+ this.bindEvents();
+
+ let value = null /*Common.localStorage.getItem("pe-settings-fontrender")*/;
+ if (value===null) value = window.devicePixelRatio > 1 ? '1' : '3';
+ this.api.SetFontRenderingMode(parseInt(value));
+ this.api.SetDrawingFreeze(true);
+ this.api.SetThemesPath("../../../../sdkjs/slide/themes/");
+ // Common.Utils.Metric.setCurrentMetric(1); //pt
+
+ Common.Gateway.on('init', loadConfig);
+ // Common.Gateway.on('showmessage', _.bind(me.onExternalMessage, me));
+ Common.Gateway.on('opendocument', loadDocument);
+ Common.Gateway.appReady();
+
+ Common.Notifications.trigger('engineCreated', this.api);
+ Common.EditorApi = {get: () => this.api};
+ }, error => {
+ console.log('promise failed ' + error);
+ });
+ };
+
+ script.onerror = () => {
+ console.log('error');
+ };
+
+ document.body.appendChild(script);
+ }
+
+ bindEvents() {
+ const me = this;
+ // me.api.asc_registerCallback('asc_onError', _.bind(me.onError, me));
+ me.api.asc_registerCallback('asc_onDocumentContentReady', me._onDocumentContentReady.bind(me));
+ me.api.asc_registerCallback('asc_onOpenDocumentProgress', me._onOpenDocumentProgress.bind(me));
+ // me.api.asc_registerCallback('asc_onDocumentUpdateVersion', _.bind(me.onUpdateVersion, me));
+ // me.api.asc_registerCallback('asc_onServerVersion', _.bind(me.onServerVersion, me));
+ // me.api.asc_registerCallback('asc_onAdvancedOptions', _.bind(me.onAdvancedOptions, me));
+ // me.api.asc_registerCallback('asc_onDocumentName', _.bind(me.onDocumentName, me));
+ // me.api.asc_registerCallback('asc_onPrintUrl', _.bind(me.onPrintUrl, me));
+ // me.api.asc_registerCallback('asc_onThumbnailsShow', _.bind(me.onThumbnailsShow, me));
+ // me.api.asc_registerCallback('asc_onMeta', _.bind(me.onMeta, me));
+ }
+
+ _onDocumentContentReady() {
+ const me = this;
+ me.api.SetDrawingFreeze(false);
+
+ me.api.Resize();
+ me.api.zoomFitToPage();
+ // me.api.asc_GetDefaultTableStyles && _.defer(function () {me.api.asc_GetDefaultTableStyles()});
+
+ Common.Gateway.documentReady();
+ }
+
+ _onOpenDocumentProgress(progress) {
+ // if (this.loadMask) {
+ // var $title = $$(this.loadMask).find('.modal-title'),
+ // const proc = (progress.asc_getCurrentFont() + progress.asc_getCurrentImage())/(progress.asc_getFontsCount() + progress.asc_getImagesCount());
+
+ // $title.text(this.textLoadingDocument + ': ' + Math.min(Math.round(proc * 100), 100) + '%');
+ // }
+ }
+
+ render() {
+ return
+ }
+
+ componentDidMount() {
+ this.initSdk();
+ }
+}
+
+const translated = withTranslation()(MainController);
+export {translated as MainController};
diff --git a/apps/presentationeditor/mobile/src/index_dev.html b/apps/presentationeditor/mobile/src/index_dev.html
new file mode 100644
index 000000000..4342a52b6
--- /dev/null
+++ b/apps/presentationeditor/mobile/src/index_dev.html
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+ Presentation Editor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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
new file mode 100644
index 000000000..a1575794a
--- /dev/null
+++ b/apps/presentationeditor/mobile/src/less/app-ios.less
@@ -0,0 +1,5 @@
+
+.device-ios {
+
+
+}
diff --git a/apps/presentationeditor/mobile/src/less/app-material.less b/apps/presentationeditor/mobile/src/less/app-material.less
new file mode 100644
index 000000000..879f3a67c
--- /dev/null
+++ b/apps/presentationeditor/mobile/src/less/app-material.less
@@ -0,0 +1,24 @@
+
+// Colors
+@themeColorLight: #a2bdde;
+@navBarIconColor: #fff;
+
+
+.device-android {
+ --f7-navbar-bg-color: @themeColor;
+ --f7-navbar-link-color: @navBarIconColor;
+ --f7-navbar-text-color: @navBarIconColor;
+
+ // Main Toolbar
+ #editor-navbar.navbar .right {
+ padding-right: 4px;
+ }
+ #editor-navbar.navbar .right a.link,
+ #editor-navbar.navbar .left a.link {
+ padding: 0 13px;
+ justify-content: space-between;
+ box-sizing: border-box;
+ align-items: center;
+ width: auto;
+ }
+}
\ No newline at end of file
diff --git a/apps/presentationeditor/mobile/src/less/app.less b/apps/presentationeditor/mobile/src/less/app.less
new file mode 100644
index 000000000..24c5dc0fb
--- /dev/null
+++ b/apps/presentationeditor/mobile/src/less/app.less
@@ -0,0 +1,47 @@
+@themeColor: #446995;
+
+@import '../../../../common/mobile/resources/less/_mixins.less';
+@import '../../../../common/mobile/resources/less/collaboration.less';
+@import '../../../../common/mobile/resources/less/common.less';
+@import '../../../../common/mobile/resources/less/common-ios.less';
+@import '../../../../common/mobile/resources/less/common-material.less';
+@import './app-material.less';
+@import './app-ios.less';
+@import './icons-ios.less';
+@import './icons-material.less';
+
+/* Left Panel right border when it is visible by breakpoint */
+.panel-left.panel-in-breakpoint:before {
+ position: absolute;
+ right: 0;
+ top: 0;
+ height: 100%;
+ width: 1px;
+ background: rgba(0,0,0,0.1);
+ content: '';
+ z-index: 6000;
+}
+
+/* Hide navbar link which opens left panel when it is visible by breakpoint */
+.panel-left.panel-in-breakpoint ~ .view .navbar .panel-open[data-panel="left"] {
+ display: none;
+}
+
+/*
+ Extra borders for main view and left panel for iOS theme when it behaves as panel (before breakpoint size)
+*/
+.ios .panel-left:not(.panel-in-breakpoint).panel-in ~ .view-main:before,
+.ios .panel-left:not(.panel-in-breakpoint).panel-closing ~ .view-main:before {
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 100%;
+ width: 1px;
+ background: rgba(0,0,0,0.1);
+ content: '';
+ z-index: 6000;
+}
+
+:root {
+ --f7-popover-width: 360px;
+}
diff --git a/apps/presentationeditor/mobile/src/lib/i18n.js b/apps/presentationeditor/mobile/src/lib/i18n.js
new file mode 100644
index 000000000..b3d3566ee
--- /dev/null
+++ b/apps/presentationeditor/mobile/src/lib/i18n.js
@@ -0,0 +1,17 @@
+import i18n from 'i18next'
+import {initReactI18next} from 'react-i18next'
+import Fetch from 'i18next-fetch-backend'
+
+i18n.use(initReactI18next)
+ .use(Fetch)
+ .init({
+ lng: Common.Locale.currentLang,
+ fallbackLng: "en",
+ escapeValue: false,
+ backend: {
+ loadPath: './locale/{{lng}}.json'
+ },
+ interpolation: { escapeValue: false },
+ });
+
+export default i18n;
\ No newline at end of file
diff --git a/apps/presentationeditor/mobile/src/page/app.jsx b/apps/presentationeditor/mobile/src/page/app.jsx
new file mode 100644
index 000000000..d8451deb7
--- /dev/null
+++ b/apps/presentationeditor/mobile/src/page/app.jsx
@@ -0,0 +1,44 @@
+import React from 'react';
+
+import {App,Panel,Views,View,Popup,Page,Navbar,Toolbar,NavRight,Link,Block,BlockTitle,List,ListItem,ListInput,ListButton,BlockFooter} from 'framework7-react';
+
+import routes from '../router/routes.js';
+
+import '../../../../common/Gateway.js';
+import '../../../../common/main/lib/util/utils.js';
+import Notifications from '../../../../common/mobile/utils/notifications.js'
+import {MainController} from '../controller/Main';
+
+export default class extends React.Component {
+ constructor() {
+ super();
+
+ this.state = {
+ // Framework7 Parameters
+ f7params: {
+ name: 'Presentation Editor', // App name
+ theme: 'auto', // Automatic theme detection
+
+ // App routes
+ routes: routes,
+ },
+ }
+
+ Common.Notifications = new Notifications();
+ }
+ render() {
+ return (
+
+ {/* Your main view, should have "view-main" class */}
+
+
+
+ )
+ }
+
+ componentDidMount() {
+ this.$f7ready((f7) => {
+ // Call F7 APIs here
+ });
+ }
+}
diff --git a/apps/presentationeditor/mobile/src/page/main.jsx b/apps/presentationeditor/mobile/src/page/main.jsx
new file mode 100644
index 000000000..b2bb7fdde
--- /dev/null
+++ b/apps/presentationeditor/mobile/src/page/main.jsx
@@ -0,0 +1,80 @@
+import React, { Component } from 'react';
+import { Page, View, Navbar, NavLeft, NavRight, Link, Icon } from 'framework7-react';
+
+// import EditOptions from '../view/edit/Edit';
+// import Settings from '../view/settings/Settings';
+import CollaborationView from '../../../../common/mobile/lib/view/Collaboration.jsx'
+
+export default class MainPage extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ editOptionsVisible: false,
+ settingsVisible: false,
+ collaborationVisible: false,
+ };
+ }
+
+ handleClickToOpenOptions = opts => {
+ this.setState(state => {
+ if ( opts == 'edit' )
+ return {editOptionsVisible: true};
+ else
+ if ( opts == 'settings' )
+ return {settingsVisible: true};
+ else
+ if ( opts == 'coauth' )
+ return {collaborationVisible: true}
+ });
+ };
+
+ handleOptionsViewClosed = opts => {
+ (async () => {
+ await 1 && this.setState(state => {
+ if ( opts == 'edit' )
+ return {editOptionsVisible: false};
+ else
+ if ( opts == 'settings' )
+ return {settingsVisible: false};
+ else
+ if ( opts == 'coauth' )
+ return {collaborationVisible: false}
+ })
+ })();
+ };
+
+ render() {
+ console.log(this.$f7router)
+ return (
+
+ {/* Top Navbar */}
+
+
+
+
+
+
+
+ this.handleClickToOpenOptions('edit')}>
+ this.handleClickToOpenOptions('coauth')}>
+ this.handleClickToOpenOptions('settings')}>
+
+
+ {/* Page content */}
+
+ {/*{*/}
+ {/*!this.state.editOptionsVisible ? null :*/}
+ {/**/}
+ {/*}*/}
+ {/*{*/}
+ {/*!this.state.settingsVisible ? null :*/}
+ {/**/}
+ {/*}*/}
+ {
+ !this.state.collaborationVisible ? null :
+
+ }
+
+ )
+ }
+};
\ No newline at end of file
diff --git a/apps/presentationeditor/mobile/src/router/routes.js b/apps/presentationeditor/mobile/src/router/routes.js
new file mode 100644
index 000000000..027d62ae6
--- /dev/null
+++ b/apps/presentationeditor/mobile/src/router/routes.js
@@ -0,0 +1,17 @@
+
+import MainPage from '../page/main';
+
+import { PageCollaboration, PageUsers } from '../../../../common/mobile/lib/view/Collaboration.jsx';
+
+var routes = [
+ {
+ path: '/',
+ component: MainPage,
+ },
+ {
+ path: '/users/',
+ component: PageUsers
+ },
+];
+
+export default routes;
diff --git a/apps/presentationeditor/mobile/src/store/mainStore.js b/apps/presentationeditor/mobile/src/store/mainStore.js
new file mode 100644
index 000000000..05abdf386
--- /dev/null
+++ b/apps/presentationeditor/mobile/src/store/mainStore.js
@@ -0,0 +1,23 @@
+
+// import {storeDocumentSettings} from './documentSettings';
+// import {storeFocusObjects} from "./focusObjects";
+import {storeUsers} from '../../../../common/mobile/lib/store/users';
+// import {storeTextSettings} from "./textSettings";
+// import {storeParagraphSettings} from "./paragraphSettings";
+// import {storeShapeSettings} from "./shapeSettings";
+// import {storeImageSettings} from "./imageSettings";
+// import {storeTableSettings} from "./tableSettings";
+// import {storeChartSettings} from "./chartSettings";
+
+export const stores = {
+ // storeFocusObjects: new storeFocusObjects(),
+ // storeDocumentSettings: new storeDocumentSettings(),
+ users: new storeUsers(),
+ // storeTextSettings: new storeTextSettings(),
+ // storeParagraphSettings: new storeParagraphSettings(),
+ // storeShapeSettings: new storeShapeSettings(),
+ // storeChartSettings: new storeChartSettings(),
+ // storeImageSettings: new storeImageSettings(),
+ // storeTableSettings: new storeTableSettings()
+};
+