diff --git a/apps/common/mobile/lib/component/ThemeColorPalette.jsx b/apps/common/mobile/lib/component/ThemeColorPalette.jsx new file mode 100644 index 000000000..8b6f4548a --- /dev/null +++ b/apps/common/mobile/lib/component/ThemeColorPalette.jsx @@ -0,0 +1,183 @@ +import React, { useState, useEffect } from 'react'; +import { f7, ListItem, List, Icon } from 'framework7-react'; +import { useTranslation } from 'react-i18next'; + +const ThemeColors = ({ themeColors, onColorClick, curColor }) => { + return ( +
+ {themeColors.map((row, rowIndex) => { + return( +
+ {row.map((effect, index) => { + return( + {onColorClick(effect.color, effect.effectId)}} + > + ) + })} +
+ ) + })} +
+ ) +}; + +const StandartColors = ({ options, standartColors, onColorClick, curColor }) => { + return ( +
+ {standartColors.map((color, index) => { + return( + index === 0 && options.transparent ? + {onColorClick('transparent')}} + > : + {onColorClick(color)}} + > + ) + })} +
+ ) +}; + +const CustomColors = ({ options, customColors, onColorClick, curColor }) => { + const colors = customColors.length > 0 ? customColors : []; + const emptyItems = []; + if (colors.length < options.customcolors) { + for (let i = colors.length; i < options.customcolors; i++) { + emptyItems.push( {onColorClick('empty')}} + >) + } + } + return ( +
+ {colors && colors.length > 0 && colors.map((color, index) => { + return( + {onColorClick(color)}} + > + ) + })} + {emptyItems.length > 0 && emptyItems} +
+ ) +}; + +const ThemeColorPalette = props => { + const {t} = useTranslation(); + const _t = t('Common.ThemeColorPalette', {returnObjects: true}); + const options = { + customcolors: props.customcolors || 10, + standardcolors: props.standardcolors || 10, + themecolors: props.themecolors || 10, + effects: props.effects || 5, + //allowReselect: props.allowReselect !== false, + transparent: props.transparent || false, + value: props.value || '000000', + cls: props.cls || '' + }; + const curColor = props.curColor; + const themeColors = []; + const effectColors = Common.Utils.ThemeColor.getEffectColors(); + let row = -1; + effectColors.forEach((effect, index) => { + if (0 == index % options.themecolors) { + themeColors.push([]); + row++; + } + themeColors[row].push(effect); + }); + const standartColors = Common.Utils.ThemeColor.getStandartColors(); + // custom color + let customColors = props.customColors; + if (customColors.length < 1) { + customColors = localStorage.getItem('mobile-custom-colors'); + customColors = customColors ? customColors.toLowerCase().split(',') : []; + } + + return ( +
+ + +
{ _t.textThemeColors }
+ +
+ +
{ _t.textStandartColors }
+ +
+ +
{ _t.textCustomColors }
+ +
+
+
+ ) +}; + +const CustomColorPicker = props => { + //Function to convert rgb color to hex format + const hexDigits = new Array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"); + const hex = x => { + return isNaN(x) ? "00" : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16]; + }; + const rgb2hex = rgb => { + rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); + return hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); + }; + + let currentColor = props.currentColor; + if (props.autoColor) { + currentColor = rgb2hex(props.autoColor); + } + const countDynamicColors = props.countdynamiccolors || 10; + const [stateColor, setColor] = useState(`#${currentColor}`); + useEffect(() => { + if (document.getElementsByClassName('color-picker-wheel').length < 1) { + const colorPicker = f7.colorPicker.create({ + containerEl: document.getElementsByClassName('color-picker-container')[0], + value: { + hex: `#${currentColor}` + }, + on: { + change: function (value) { + setColor(value.getValue().hex); + } + } + }); + } + }); + const addNewColor = (color) => { + let colors = localStorage.getItem('mobile-custom-colors'); + colors = colors ? colors.split(',') : []; + const newColor = color.slice(1); + if (colors.push(newColor) > countDynamicColors) colors.shift(); // 10 - dynamiccolors + localStorage.setItem('mobile-custom-colors', colors.join().toLowerCase()); + props.onAddNewColor && props.onAddNewColor(colors, newColor); + }; + return( +
+
+
+
+
+
+
+ {addNewColor(stateColor)}}> + + +
+
+ ) +}; + +export { ThemeColorPalette, CustomColorPicker }; \ No newline at end of file diff --git a/apps/common/mobile/resources/less/common-ios.less b/apps/common/mobile/resources/less/common-ios.less index 8305d3245..bb1dad5ee 100644 --- a/apps/common/mobile/resources/less/common-ios.less +++ b/apps/common/mobile/resources/less/common-ios.less @@ -160,6 +160,19 @@ } .list { + .item-content { + .color-preview { + width: 22px; + height: 8px; + display: inline-block; + margin-top: 21px; + box-sizing: border-box; + box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset; + &.auto { + background-color: @autoColor; + } + } + } li.no-indicator { .item-link { .item-inner:before { @@ -299,4 +312,15 @@ .dialog { background-color: rgba(var(--f7-dialog-bg-color-rgb), 1); } + + #color-picker { + .right-block { + .button-round { + .icon { + height: 30px; + width: 30px; + } + } + } + } } diff --git a/apps/common/mobile/resources/less/common-material.less b/apps/common/mobile/resources/less/common-material.less index d9c3c5825..514521372 100644 --- a/apps/common/mobile/resources/less/common-material.less +++ b/apps/common/mobile/resources/less/common-material.less @@ -178,6 +178,18 @@ } } } + .item-content { + .color-preview { + width: 30px; + height: 30px; + border-radius: 16px; + margin-top: -3px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset; + &.auto { + background-color: @autoColor; + } + } + } } // Bullets and numbers .bullets, @@ -230,4 +242,12 @@ } } } + // Color palette + #color-picker { + .right-block { + .button-round { + background-color: @themeColor; + } + } + } } diff --git a/apps/common/mobile/resources/less/common.less b/apps/common/mobile/resources/less/common.less index 9bc7c4338..a80fac332 100644 --- a/apps/common/mobile/resources/less/common.less +++ b/apps/common/mobile/resources/less/common.less @@ -3,7 +3,8 @@ @black: #000000; @gray: #c4c4c4; @green: #4cd964; - +@background-normal: @white; +@autoColor: @black; .popup, .popover, .sheet-modal { .list:first-child { @@ -228,5 +229,107 @@ } } +.item-color-auto { + .color-auto { + width:22px; + height: 22px; + background-color: @autoColor; + } + &.active { + .color-auto { + box-shadow: 0 0 0 1px @background-normal, 0 0 0 4px @themeColor; + border-radius: 1px; + } + } +} +.color-palettes { + .palette { + padding: 8px 0px; + a { + flex-grow: 1; + position: relative; + min-width: 10px; + min-height: 26px; + margin: 1px 1px 0 0; + box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset; + &.active:after { + content: ' '; + position: absolute; + width: 100%; + height: 100%; + box-shadow: 0 0 0 1px @background-normal, 0 0 0 4px @themeColor; + z-index: 1; + border-radius: 1px; + } + &.transparent { + background-repeat: no-repeat; + background-size: 100% 100%; + .encoded-svg-background(""); + } + } + } + .row { + padding: 0; + } + .list .item-inner { + display: block; + } + .standart-colors, .dynamic-colors { + .palette { + display: flex; + } + } + .dynamic-colors { + .empty-color { + background-color: @background-normal; + } + } +} + +#color-picker { + display: flex; + justify-content: space-around; + align-items: center; + max-width: 300px; + margin: 0 auto; + margin-top: 4px; + .color-picker-container { + width: calc(100% - 94px); + position: relative; + max-width: 100%; + height: auto; + font-size: 0; + .color-picker-module-wheel { + margin: 0; + } + } + .right-block { + margin-left: 20px; + .color-hsb-preview { + width: 72px; + height: 72px; + border-radius: 100px; + overflow: hidden; + border: 1px solid @gray; + .new-color-hsb-preview, .current-color-hsb-preview { + width: 100%; + height: 36px; + } + } + .button-round { + height: 72px; + width: 72px; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + border-radius: 100px; + background-color: @white; + box-shadow: 0 4px 4px rgba(0,0,0,.25); + border-color: transparent; + margin-top: 20px; + } + } +} diff --git a/apps/documenteditor/mobile/locale/en.json b/apps/documenteditor/mobile/locale/en.json index 68b5eaa6e..82355eea9 100644 --- a/apps/documenteditor/mobile/locale/en.json +++ b/apps/documenteditor/mobile/locale/en.json @@ -1,4 +1,11 @@ { + "Common": { + "ThemeColorPalette": { + "textThemeColors": "Theme Colors", + "textStandartColors": "Standart Colors", + "textCustomColors": "Custom Colors" + } + }, "Settings": { "textCancel": "Cancel", "textSettings": "Settings", @@ -164,7 +171,11 @@ "textDifferentOddAndEvenPages": "Different odd and even pages", "textLinkToPrevious": "Link to Previous", "textContinueFromPreviousSection": "Continue from previous section", - "textStartAt": "Start at" + "textStartAt": "Start at", + "textFontColors": "Font Colors", + "textAutomatic": "Automatic", + "textAddCustomColor": "Add Custom Color", + "textCustomColor": "Custom Color" }, "Add": { "textTable": "Table", diff --git a/apps/documenteditor/mobile/src/controller/Main.jsx b/apps/documenteditor/mobile/src/controller/Main.jsx index ea56c12ff..2a9db0372 100644 --- a/apps/documenteditor/mobile/src/controller/Main.jsx +++ b/apps/documenteditor/mobile/src/controller/Main.jsx @@ -172,6 +172,10 @@ class MainController extends Component { } bindEvents() { + this.api.asc_registerCallback('asc_onSendThemeColors', (colors, standart_colors) => { + Common.Utils.ThemeColor.setColors(colors, standart_colors); + }); + const storeDocumentSettings = this.props.storeDocumentSettings; this.api.asc_registerCallback('asc_onPageOrient', isPortrait => { storeDocumentSettings.resetPortrait(isPortrait); diff --git a/apps/documenteditor/mobile/src/controller/edit/EditText.jsx b/apps/documenteditor/mobile/src/controller/edit/EditText.jsx index 21fdf96b7..271741f52 100644 --- a/apps/documenteditor/mobile/src/controller/edit/EditText.jsx +++ b/apps/documenteditor/mobile/src/controller/edit/EditText.jsx @@ -33,6 +33,27 @@ class EditTextController extends Component { } } + onTextColorAuto() { + const api = Common.EditorApi.get(); + const color = new Asc.asc_CColor(); + color.put_auto(true); + api.put_TextColor(color); + } + + onTextColor(color) { + const api = Common.EditorApi.get(); + api.put_TextColor(Common.Utils.ThemeColor.getRgbColor(color)); + } + + onBackgroundColor(color) { + const api = Common.EditorApi.get(); + if (color == 'transparent') { + api.put_ParagraphShade(false); + } else { + api.put_ParagraphShade(true, Common.Utils.ThemeColor.getRgbColor(color)); + } + } + toggleBold(value) { const api = Common.EditorApi.get(); if (api) { @@ -174,6 +195,9 @@ class EditTextController extends Component { return ( '); } + &.icon-text-color { + width: 22px; + height: 22px; + .encoded-svg-background(''); + } + &.icon-text-selection { + width: 22px; + height: 22px; + .encoded-svg-background(''); + } // Align &.icon-text-align-left { width: 22px; diff --git a/apps/documenteditor/mobile/src/css/icons-material.less b/apps/documenteditor/mobile/src/css/icons-material.less index e58d655ef..12edf3dc4 100644 --- a/apps/documenteditor/mobile/src/css/icons-material.less +++ b/apps/documenteditor/mobile/src/css/icons-material.less @@ -60,6 +60,11 @@ } } i.icon { + &.icon-plus { + width: 24px; + height: 24px; + .encoded-svg-background(''); + } &.icon-expand-down { width: 17px; height: 17px; diff --git a/apps/documenteditor/mobile/src/store/mainStore.js b/apps/documenteditor/mobile/src/store/mainStore.js index a8390c1e1..ffa31bf47 100644 --- a/apps/documenteditor/mobile/src/store/mainStore.js +++ b/apps/documenteditor/mobile/src/store/mainStore.js @@ -11,6 +11,7 @@ import {storeChartSettings} from "./chartSettings"; import {storeDocumentInfo} from "./documentInfo"; import {storeApplicationSettings} from './applicationSettings'; import {storeAppOptions} from "./appOptions"; +import {storePalette} from "./palette"; export const stores = { storeAppOptions: new storeAppOptions(), @@ -24,6 +25,7 @@ export const stores = { storeImageSettings: new storeImageSettings(), storeTableSettings: new storeTableSettings(), storeDocumentInfo: new storeDocumentInfo(), - storeApplicationSettings: new storeApplicationSettings() + storeApplicationSettings: new storeApplicationSettings(), + storePalette: new storePalette() }; diff --git a/apps/documenteditor/mobile/src/store/palette.js b/apps/documenteditor/mobile/src/store/palette.js new file mode 100644 index 000000000..f5e40e59b --- /dev/null +++ b/apps/documenteditor/mobile/src/store/palette.js @@ -0,0 +1,9 @@ +import {action, observable} from 'mobx'; + +export class storePalette { + @observable customColors = []; + + @action changeCustomColors (colors) { + this.customColors = colors; + } +} \ No newline at end of file diff --git a/apps/documenteditor/mobile/src/store/textSettings.js b/apps/documenteditor/mobile/src/store/textSettings.js index 75b892eb2..48d42403b 100644 --- a/apps/documenteditor/mobile/src/store/textSettings.js +++ b/apps/documenteditor/mobile/src/store/textSettings.js @@ -14,6 +14,7 @@ export class storeTextSettings { @observable typeNumbers = undefined; @observable paragraphAlign = undefined; @observable textColor = undefined; + @observable customTextColors = []; @observable lineSpacing = undefined; @observable backgroundColor = undefined; @@ -97,7 +98,7 @@ export class storeTextSettings { let value; if (color) { if (color.get_auto()) { - value = '000000'; + value = 'auto'; } else { if (color.get_type() == Asc.c_oAscColor.COLOR_TYPE_SCHEME) { value = { @@ -112,6 +113,10 @@ export class storeTextSettings { this.textColor = value; } + @action changeCustomTextColors (colors) { + this.customTextColors = colors; + } + @action resetLineSpacing (vc) { let line = (vc.get_Line() === null || vc.get_LineRule() === null || vc.get_LineRule() != 1) ? -1 : vc.get_Line(); this.lineSpacing = line; diff --git a/apps/documenteditor/mobile/src/view/app.jsx b/apps/documenteditor/mobile/src/view/app.jsx index 64a7a3ab9..da82af4b7 100644 --- a/apps/documenteditor/mobile/src/view/app.jsx +++ b/apps/documenteditor/mobile/src/view/app.jsx @@ -31,51 +31,9 @@ export default class extends React.Component { return ( - {/* Left panel with cover effect when hidden */} - - - - - Left View Navigation - - - - - - - - - - {/* Right panel with reveal effect*/} - - - - - Right panel content goes here - - - - - {/* Your main view, should have "view-main" class */} - - {/* Popup */} - - - - - - Close - - - -

Popup content goes here.

-
-
-
-
) } diff --git a/apps/documenteditor/mobile/src/view/edit/Edit.jsx b/apps/documenteditor/mobile/src/view/edit/Edit.jsx index 06e1e674e..a9c47e248 100644 --- a/apps/documenteditor/mobile/src/view/edit/Edit.jsx +++ b/apps/documenteditor/mobile/src/view/edit/Edit.jsx @@ -14,7 +14,7 @@ import EditChartController from "../../controller/edit/EditChart"; import EditHyperlinkController from "../../controller/edit/EditHyperlink"; import EditHeaderController from "../../controller/edit/EditHeader"; -import {PageAdditionalFormatting, PageBullets, PageFonts, PageLineSpacing, PageNumbers} from "./EditText"; +import {PageTextFonts, PageTextAddFormatting, PageTextBullets, PageTextNumbers, PageTextLineSpacing, PageTextFontColor, PageTextCustomFontColor, PageTextBackgroundColor, PageTextCustomBackColor} from "./EditText"; import {PageAdvancedSettings} from "./EditParagraph"; import {PageWrap, PageReorder, PageReplace} from "./EditShape"; import {PageImageReorder, PageImageReplace, PageImageWrap, PageLinkSettings} from "./EditImage"; @@ -25,23 +25,39 @@ const routes = [ //Edit text { path: '/edit-text-fonts/', - component: PageFonts, + component: PageTextFonts, }, { path: '/edit-text-add-formatting/', - component: PageAdditionalFormatting, + component: PageTextAddFormatting, }, { path: '/edit-text-bullets/', - component: PageBullets, + component: PageTextBullets, }, { path: '/edit-text-numbers/', - component: PageNumbers, + component: PageTextNumbers, }, { path: '/edit-text-line-spacing/', - component: PageLineSpacing, + component: PageTextLineSpacing, + }, + { + path: '/edit-text-font-color/', + component: PageTextFontColor, + }, + { + path: '/edit-text-custom-font-color/', + component: PageTextCustomFontColor, + }, + { + path: '/edit-text-background-color/', + component: PageTextBackgroundColor, + }, + { + path: '/edit-text-custom-back-color/', + component: PageTextCustomBackColor, }, //Edit paragraph { diff --git a/apps/documenteditor/mobile/src/view/edit/EditText.jsx b/apps/documenteditor/mobile/src/view/edit/EditText.jsx index a0b830c4f..3ad6f5aaa 100644 --- a/apps/documenteditor/mobile/src/view/edit/EditText.jsx +++ b/apps/documenteditor/mobile/src/view/edit/EditText.jsx @@ -1,9 +1,11 @@ -import React, {Fragment, useState} from 'react'; +import React, {Fragment, useState } from 'react'; import {observer, inject} from "mobx-react"; -import {List, ListItem, Icon, Row, Button, Page, Navbar, Segmented, BlockTitle} from 'framework7-react'; +import {f7, List, ListItem, Icon, Row, Button, Page, Navbar, Segmented, BlockTitle} from 'framework7-react'; import { useTranslation } from 'react-i18next'; import {Device} from '../../../../../common/mobile/utils/device'; +import { ThemeColorPalette, CustomColorPicker } from '../../../../../common/mobile/lib/component/ThemeColorPalette.jsx'; + const PageFonts = props => { const isAndroid = Device.android; const { t } = useTranslation(); @@ -208,18 +210,136 @@ const PageLineSpacing = props => { ) }; +const PageCustomFontColor = props => { + const { t } = useTranslation(); + const _t = t('Edit', {returnObjects: true}); + const store = props.storeTextSettings; + let textColor = store.textColor; + if (typeof textColor === 'object') { + textColor = textColor.color; + } + const autoColor = textColor === 'auto' ? window.getComputedStyle(document.getElementById('font-color-auto')).backgroundColor : null; + const onAddNewColor = (colors, color) => { + props.storePalette.changeCustomColors(colors); + props.onTextColor(color); + props.f7router.back(); + }; + return( + + + + + ) +}; + +const PageFontColor = props => { + const { t } = useTranslation(); + const _t = t('Edit', {returnObjects: true}); + const textColor = props.storeTextSettings.textColor; + const customColors = props.storePalette.customColors; + const changeColor = (color, effectId) => { + if (color !== 'empty') { + if (effectId !==undefined ) { + props.onTextColor({color: color, effectId: effectId}); + } else { + props.onTextColor(color); + } + } else { + // open custom color menu + props.f7router.navigate('/edit-text-custom-font-color/'); + } + }; + return( + + + + { + props.onTextColorAuto(); + }}> +
+
+
+
+
+ + + + +
+ ) +}; + +const PageCustomBackColor = props => { + const { t } = useTranslation(); + const _t = t('Edit', {returnObjects: true}); + let backgroundColor = props.storeTextSettings.backgroundColor; + if (typeof backgroundColor === 'object') { + backgroundColor = backgroundColor.color; + } + const onAddNewColor = (colors, color) => { + props.storePalette.changeCustomColors(colors); + props.onBackgroundColor(color); + props.f7router.back(); + }; + return( + + + + + ) +}; + +const PageBackgroundColor = props => { + const { t } = useTranslation(); + const _t = t('Edit', {returnObjects: true}); + const backgroundColor = props.storeTextSettings.backgroundColor; + const customColors = props.storePalette.customColors; + const changeColor = (color, effectId) => { + if (color !== 'empty') { + if (effectId !==undefined ) { + props.onBackgroundColor({color: color, effectId: effectId}); + } else { + props.onBackgroundColor(color); + } + } else { + // open custom color menu + props.f7router.navigate('/edit-text-custom-back-color/'); + } + }; + return( + + + + + + + + ) +}; + const EditText = props => { const isAndroid = Device.android; const { t } = useTranslation(); const storeTextSettings = props.storeTextSettings; const fontName = storeTextSettings.fontName || t('Edit.textFonts'); const fontSize = storeTextSettings.fontSize; + const fontColor = storeTextSettings.textColor; + const backgroundColor = storeTextSettings.backgroundColor; const displaySize = typeof fontSize === 'undefined' ? t('Edit.textAuto') : fontSize + ' ' + t('Edit.textPt'); const isBold = storeTextSettings.isBold; const isItalic = storeTextSettings.isItalic; const isUnderline = storeTextSettings.isUnderline; const isStrikethrough = storeTextSettings.isStrikethrough; const paragraphAlign = storeTextSettings.paragraphAlign; + + const fontColorPreview = fontColor !== 'auto' ? + : + ; + return ( @@ -235,12 +355,22 @@ const EditText = props => { {props.toggleStrikethrough(!isStrikethrough)}} style={{textDecoration: "line-through"}}>S - - {!isAndroid && } - + + {!isAndroid ? + {fontColorPreview} : + fontColorPreview + } - - {!isAndroid && } + + {!isAndroid ? + : + + } { }; const EditTextContainer = inject("storeTextSettings", "storeFocusObjects")(observer(EditText)); -const PageFontsContainer = inject("storeTextSettings", "storeFocusObjects")(observer(PageFonts)); -const PageAddFormattingContainer = inject("storeTextSettings", "storeFocusObjects")(observer(PageAdditionalFormatting)); -const PageBulletsContainer = inject("storeTextSettings")(observer(PageBullets)); -const PageNumbersContainer = inject("storeTextSettings")(observer(PageNumbers)); -const PageLineSpacingContainer = inject("storeTextSettings")(observer(PageLineSpacing)); +const PageTextFonts = inject("storeTextSettings", "storeFocusObjects")(observer(PageFonts)); +const PageTextAddFormatting = inject("storeTextSettings", "storeFocusObjects")(observer(PageAdditionalFormatting)); +const PageTextBullets = inject("storeTextSettings")(observer(PageBullets)); +const PageTextNumbers = inject("storeTextSettings")(observer(PageNumbers)); +const PageTextLineSpacing = inject("storeTextSettings")(observer(PageLineSpacing)); +const PageTextFontColor = inject("storeTextSettings", "storePalette")(observer(PageFontColor)); +const PageTextCustomFontColor = inject("storeTextSettings", "storePalette")(observer(PageCustomFontColor)); +const PageTextBackgroundColor = inject("storeTextSettings", "storePalette")(observer(PageBackgroundColor)); +const PageTextCustomBackColor = inject("storeTextSettings", "storePalette")(observer(PageCustomBackColor)); -export {EditTextContainer as EditText, - PageFontsContainer as PageFonts, - PageAddFormattingContainer as PageAdditionalFormatting, - PageBulletsContainer as PageBullets, - PageNumbersContainer as PageNumbers, - PageLineSpacingContainer as PageLineSpacing}; \ No newline at end of file + +export { + EditTextContainer as EditText, + PageTextFonts, + PageTextAddFormatting, + PageTextBullets, + PageTextNumbers, + PageTextLineSpacing, + PageTextFontColor, + PageTextCustomFontColor, + PageTextBackgroundColor, + PageTextCustomBackColor +}; \ No newline at end of file diff --git a/apps/spreadsheeteditor/mobile/src/controller/Statusbar.jsx b/apps/spreadsheeteditor/mobile/src/controller/Statusbar.jsx index d177b3323..81f22e0ed 100644 --- a/apps/spreadsheeteditor/mobile/src/controller/Statusbar.jsx +++ b/apps/spreadsheeteditor/mobile/src/controller/Statusbar.jsx @@ -1,9 +1,79 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import StatusbarView from '../view/Statusbar'; +import { inject } from 'mobx-react'; -const Statusbar = props => { - return -}; +const Statusbar = inject('sheets')(props => { + const {sheets} = props; + + useEffect(() => { + console.log("status bar did mount"); + + Common.Notifications.on('document:ready', onApiSheetsChanged); + Common.Notifications.on('engineCreated', api => { + api.asc_registerCallback('asc_onSheetsChanged', onApiSheetsChanged.bind(api)); + }); + }, []); + + const onApiSheetsChanged = api => { + console.log('on api sheets changed'); + + !api && (api = Common.EditorApi.get()); + + const sheets_count = api.asc_getWorksheetsCount(); + const active_index = api.asc_getActiveWorksheetIndex(); + let i = -1, items = []; + + while ( ++i < sheets_count ) { + const tab = { + index : i, + active : active_index == i, + name : api.asc_getWorksheetName(i), + locked : api.asc_isWorksheetLockedOrDeleted(i), + hidden : api.asc_isWorksheetHidden(i), + color : api.asc_getWorksheetTabColor(i) + }; + + items.push(tab); + } + + sheets.reset(items); + // this.hiddensheets.reset(hiddentems); + + // this.updateTabsColors(); + }; + + const onTabClicked = i => { + const model = sheets.at(i); + + const api = Common.EditorApi.get(); + api.asc_showWorksheet(model.index); + sheets.setActiveWorksheet(i); + }; + + const onAddTabClicked = () => { + const api = Common.EditorApi.get(); + api.asc_closeCellEditor(); + + const createSheetName = () => { + let items = [], wc = api.asc_getWorksheetsCount(); + while (wc--) { + items.push(api.asc_getWorksheetName(wc).toLowerCase()); + } + + let index = 0, name; + while(++index < 1000) { + name = /*this.strSheet*/ 'Sheet' + index; + if (items.indexOf(name.toLowerCase()) < 0) break; + } + + return name; + }; + + api.asc_addWorksheet(createSheetName()); + }; + + return +}); export default Statusbar; \ No newline at end of file diff --git a/apps/spreadsheeteditor/mobile/src/less/app.less b/apps/spreadsheeteditor/mobile/src/less/app.less index 00f6e282f..5403bdf9d 100644 --- a/apps/spreadsheeteditor/mobile/src/less/app.less +++ b/apps/spreadsheeteditor/mobile/src/less/app.less @@ -1,6 +1,9 @@ @themeColor: #40865c; +@import '../../../../common/mobile/resources/less/variables.less'; +@import '../../../../../vendor/framework7-react/node_modules/framework7/less/mixins.less'; + @import '../../../../common/mobile/resources/less/_mixins.less'; @import '../../../../common/mobile/resources/less/collaboration.less'; @import '../../../../common/mobile/resources/less/common.less'; @@ -12,6 +15,7 @@ @import './icons-material.less'; @import './icons-common.less'; @import './celleditor.less'; +@import './statusbar.less'; .page[data-name='home'] { .page-content { diff --git a/apps/spreadsheeteditor/mobile/src/less/statusbar.less b/apps/spreadsheeteditor/mobile/src/less/statusbar.less new file mode 100644 index 000000000..a142d2bb9 --- /dev/null +++ b/apps/spreadsheeteditor/mobile/src/less/statusbar.less @@ -0,0 +1,58 @@ +@statusbar-height: 30px; +@fontColor: #000; + +.statusbar { + .hairline(top, @border-regular-control); + height: @statusbar-height; + min-height: @statusbar-height; + background-color: @background-normal; + + display: flex; + + .tab { + border: 0 none; + border-radius: 0; + font-size: 18px; + line-height: inherit; + min-width: 48px; + + display: inline-block; + padding: 0 10px; + text-align: center; + height: 100%; + position: relative; + + .hairline(right, @border-regular-control); + } + + .statusbar--box-tabs { + > ul { + padding: 0; + margin: 0; + height: 100%; + white-space: pre; + overflow: hidden; + + > li { + a { + font-size: 12px; + padding: 0 10px 0; + line-height: @statusbar-height; + color: @text-normal; + } + + &:not(.active) { + a { + opacity: 0.5; + } + } + } + } + } + + i.icon { + &.icon-plus { + .encoded-svg-background(''); + } + } +} diff --git a/apps/spreadsheeteditor/mobile/src/store/mainStore.js b/apps/spreadsheeteditor/mobile/src/store/mainStore.js index 05abdf386..a54c22e56 100644 --- a/apps/spreadsheeteditor/mobile/src/store/mainStore.js +++ b/apps/spreadsheeteditor/mobile/src/store/mainStore.js @@ -2,6 +2,7 @@ // import {storeDocumentSettings} from './documentSettings'; // import {storeFocusObjects} from "./focusObjects"; import {storeUsers} from '../../../../common/mobile/lib/store/users'; +import {storeWorksheets} from './sheets'; // import {storeTextSettings} from "./textSettings"; // import {storeParagraphSettings} from "./paragraphSettings"; // import {storeShapeSettings} from "./shapeSettings"; @@ -13,6 +14,7 @@ export const stores = { // storeFocusObjects: new storeFocusObjects(), // storeDocumentSettings: new storeDocumentSettings(), users: new storeUsers(), + sheets: new storeWorksheets() // storeTextSettings: new storeTextSettings(), // storeParagraphSettings: new storeParagraphSettings(), // storeShapeSettings: new storeShapeSettings(), diff --git a/apps/spreadsheeteditor/mobile/src/store/sheets.js b/apps/spreadsheeteditor/mobile/src/store/sheets.js new file mode 100644 index 000000000..2b8515041 --- /dev/null +++ b/apps/spreadsheeteditor/mobile/src/store/sheets.js @@ -0,0 +1,52 @@ + +import {observable, action} from 'mobx'; + +class Worksheet { + @observable sheet = { + index : -1, + active : false, + name : '', + locked : false, + hidden : false, + color : '' + }; + + constructor(data = {}) { + this.sheet.merge(data); + } +} + +export class storeWorksheets { + @observable sheets; + + constructor() { + this.sheets = []; + } + + @action reset(sheets) { + this.sheets = Object.values(sheets) + } + + @action setActiveWorksheet(i) { + if ( !this.sheets[i].active ) { + this.sheets.forEach(model => { + if ( model.active ) + model.active = false; + }); + + this.sheets[i].active = true; + } + } + + at(i) { + return this.sheets[i] + } + + hasHiddenWorksheet() { + return this.sheets.some(model => model.hidden); + } + + hiddenWorksheets() { + return this.sheets.filter(model => model.hidden); + } +} diff --git a/apps/spreadsheeteditor/mobile/src/view/Statusbar.jsx b/apps/spreadsheeteditor/mobile/src/view/Statusbar.jsx index 6c7d19fad..666c3ebb5 100644 --- a/apps/spreadsheeteditor/mobile/src/view/Statusbar.jsx +++ b/apps/spreadsheeteditor/mobile/src/view/Statusbar.jsx @@ -1,17 +1,34 @@ import React from 'react'; -import { View, Toolbar, Link } from 'framework7-react'; +import { View, Toolbar, Link, Icon } from 'framework7-react'; +import { observer, inject } from "mobx-react"; const viewStyle = { height: 30 }; -const StatusbarView = props => { - return - - Sheet 1 - Sheet 2 - +const StatusbarView = inject('sheets')(observer(props => { + const { sheets } = props; + + const getTabClassList = model => + `tab ${model.active ? 'active':''} ${model.locked ? 'locked':''}`; + + return +
+ props.onAddTabClicked()}> + + +
+
+ +
; -}; +})); export default StatusbarView;