Skip to content

Commit

Permalink
Merge pull request #624 from ONLYOFFICE/feature/interface-theme
Browse files Browse the repository at this point in the history
Feature/interface theme
  • Loading branch information
AlexeySafronov authored Apr 21, 2022
2 parents fd9dc93 + 78944a4 commit 750b49f
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 40 deletions.
10 changes: 10 additions & 0 deletions packages/asc-web-common/api/people/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,3 +303,13 @@ export function getSelectorUserList() {
url: "/people/filter.json?fields=id,displayName,groups",
});
}

export function changeTheme(key) {
const data = { Theme: key };

return request({
method: "put",
url: `/people/theme.json`,
data,
});
}
13 changes: 13 additions & 0 deletions packages/asc-web-common/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,16 @@ export const FileStatus = Object.freeze({
export const TenantStatus = Object.freeze({
PortalRestore: 4,
});

/**
* Enum for theme keys.
* @readonly
*/
export const ThemeKeys = Object.freeze({
Base: "0",
BaseStr: "Base",
Dark: "1",
DarkStr: "Dark",
System: "2",
SystemStr: "System",
});
37 changes: 22 additions & 15 deletions packages/asc-web-common/store/SettingsStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import api from "../api";
import { LANGUAGE, TenantStatus } from "../constants";
import { combineUrl } from "../utils";
import FirebaseHelper from "../utils/firebase";
import { AppServerConfig } from "../constants";
import { AppServerConfig, ThemeKeys } from "../constants";
import { version } from "../package.json";
import SocketIOHelper from "../utils/socket";

Expand All @@ -26,9 +26,7 @@ class SettingsStore {
currentProductId = "";
culture = "en";
cultures = [];
theme = !!localStorage.getItem("theme")
? themes[localStorage.getItem("theme")]
: Base;
theme = Base;
trustedDomains = [];
trustedDomainsType = 0;
timezone = "UTC";
Expand Down Expand Up @@ -440,19 +438,28 @@ class SettingsStore {
this.buildVersionInfo.documentServer = "6.4.1";
};

changeTheme = () => {
const currentTheme =
JSON.stringify(this.theme) === JSON.stringify(Base) ? Dark : Base;
localStorage.setItem(
"theme",
JSON.stringify(this.theme) === JSON.stringify(Base) ? "Dark" : "Base"
);
this.theme = currentTheme;
};
setTheme = (key) => {
let theme = null;
switch (key) {
case ThemeKeys.Base:
case ThemeKeys.BaseStr:
theme = ThemeKeys.BaseStr;
break;
case ThemeKeys.Dark:
case ThemeKeys.DarkStr:
theme = ThemeKeys.DarkStr;
break;
case ThemeKeys.System:
case ThemeKeys.SystemStr:
default:
theme =
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
? ThemeKeys.DarkStr
: ThemeKeys.BaseStr;
}

setTheme = (theme) => {
this.theme = themes[theme];
localStorage.setItem("theme", theme);
};

setMailDomainSettings = async (data) => {
Expand Down
12 changes: 12 additions & 0 deletions packages/asc-web-common/store/UserStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ class UserStore {
this.setIsLoading(false);
};

changeTheme = async (key) => {
this.setIsLoading(true);

const { theme } = await api.people.changeTheme(key);

this.user.theme = theme;

this.setIsLoading(false);

return theme;
};

setUserIsUpdate = (isUpdate) => {
//console.log("setUserIsUpdate");
this.userIsUpdate = isUpdate;
Expand Down
4 changes: 4 additions & 0 deletions products/ASC.People/Client/public/locales/en/Profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
"ChangesApplied": "Changes are applied",
"ContactInformation": "Contact Information",
"CountCodesRemaining": "codes remaining",
"DarkTheme": "Dark theme",
"Disconnect": "Disconnect",
"EditPhoto": "Edit photo",
"EditSubscriptionsBtn": "Edit subscriptions",
"EditUser": "Edit profile",
"InterfaceTheme": "Interface theme",
"InviteAgainLbl": "Invite again",
"LightTheme": "Light theme",
"LoginSettings": "Login settings",
"MessageEmailActivationInstuctionsSentOnEmail": "The email activation instructions have been sent to the <strong>{{ email }}</strong> email address",
"PhoneLbl": "Phone",
Expand All @@ -17,6 +20,7 @@
"Subscriptions": "Subscriptions",
"SubscriptionEmailTipsToggleLbl": "Email notification with tips and tricks",
"SubscriptionTurnOffToast": "You have been successfully unsubscribed from the the mailing list. <1>Subscribe again</1>",
"SystemTheme": "Use system theme",
"TfaLoginSettings": "Login settings",
"TwoFactorDescription": "Two-factor authentication via a code-generating app was enabled for all users by the admin."
}
4 changes: 4 additions & 0 deletions products/ASC.People/Client/public/locales/ru/Profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@
"ChangesApplied": "Изменения успешно применены",
"ContactInformation": "Контактные данные",
"CountCodesRemaining": "оставшиеся коды",
"DarkTheme": "Тёмная тема",
"Disconnect": "Отключить",
"EditPhoto": "Изменить фотографию",
"EditSubscriptionsBtn": "Изменить подписки",
"EditUser": "Редактировать",
"InterfaceTheme": "Тема интерфейса",
"InviteAgainLbl": "Активировать адрес email ещё раз",
"LightTheme": "Светлая тема",
"LoginSettings": "Вход через социальные сети",
"MessageEmailActivationInstuctionsSentOnEmail": "Инструкция по активации почты пользователя была отправлена по адресу <strong>{{ email }}</strong>",
"PhoneLbl": "Основной телефон",
"ProviderSuccessfullyConnected": "Провайдер успешно подключен",
"ProviderSuccessfullyDisconnected": "Провайдер успешно отключен",
"ShowBackupCodes": "Показать резервные коды",
"Subscriptions": "Подписки",
"SystemTheme": "Использовать тему системы",
"TfaLoginSettings": "Настройки входа",
"TwoFactorDescription": "Двухфакторная аутентификация с помощью приложения для генерации кодов включена администратором для всех пользователей."
}
70 changes: 64 additions & 6 deletions products/ASC.People/Client/src/pages/Profile/Section/Body/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,16 @@ import {
getUserRole,
} from "../../../../helpers/people-helpers";
import config from "../../../../../package.json";
import { AppServerConfig, providersData } from "@appserver/common/constants";
import { unlinkOAuth, linkOAuth } from "@appserver/common/api/people";
import {
AppServerConfig,
providersData,
ThemeKeys,
} from "@appserver/common/constants";
import {
unlinkOAuth,
linkOAuth,
changeTheme,
} from "@appserver/common/api/people";
import { getAuthProviders } from "@appserver/common/api/settings";
import { Trans, useTranslation } from "react-i18next";
import {
Expand All @@ -37,6 +45,7 @@ import {

import Loaders from "@appserver/common/components/Loaders";
import withLoader from "../../../../HOCs/withLoader";
import RadioButtonGroup from "@appserver/components/radio-button-group";

const ProfileWrapper = styled.div`
display: flex;
Expand Down Expand Up @@ -344,6 +353,18 @@ class SectionBodyContent extends React.PureComponent {
this.props.changeEmailSubscription(checked);
};

onChangeTheme = async (e) => {
const { setIsLoading, changeTheme, setTheme } = this.props;

const value = e.currentTarget.value;

setIsLoading(true);

await changeTheme(value);

setIsLoading(false);
};

render() {
const { resetAppDialogVisible, backupCodesDialogVisible, tfa } = this.state;
const {
Expand All @@ -359,6 +380,8 @@ class SectionBodyContent extends React.PureComponent {
personal,
tipsSubscription,
theme,
setTheme,
selectedTheme,
} = this.props;
const contacts = profile.contacts && getUserContacts(profile.contacts);
const role = getUserRole(profile);
Expand Down Expand Up @@ -483,8 +506,27 @@ class SectionBodyContent extends React.PureComponent {
</ToggleWrapper>
)}

{profile.notes && (
{isSelf && (
<ToggleWrapper>
<ToggleContent label={t("InterfaceTheme")} isOpen={true}>
<RadioButtonGroup
orientation={"vertical"}
name={"interface-theme"}
options={[
{ value: ThemeKeys.SystemStr, label: t("SystemTheme") },
{ value: ThemeKeys.BaseStr, label: t("LightTheme") },
{ value: ThemeKeys.DarkStr, label: t("DarkTheme") },
]}
onClick={this.onChangeTheme}
selected={selectedTheme}
spacing={"10px"}
/>
</ToggleContent>
</ToggleWrapper>
)}

{profile.notes && (
<ToggleWrapper isContacts={true}>
<ToggleContent label={t("Translations:Comments")} isOpen={true}>
<Text className="profile-comments" as="span">
{profile.notes}
Expand Down Expand Up @@ -535,9 +577,21 @@ class SectionBodyContent extends React.PureComponent {
export default withRouter(
inject(({ auth, peopleStore }) => {
const { isAdmin, userStore, settingsStore, tfaStore } = auth;
const { user: viewer } = userStore;
const { isTabletView, getOAuthToken, getLoginLink, theme } = settingsStore;
const { targetUserStore, avatarEditorStore, usersStore } = peopleStore;
const { user: viewer, changeTheme } = userStore;

const {
isTabletView,
getOAuthToken,
getLoginLink,
theme,
setTheme,
} = settingsStore;
const {
targetUserStore,
avatarEditorStore,
usersStore,
loadingStore,
} = peopleStore;
const {
targetUser: profile,
isMe: isSelf,
Expand Down Expand Up @@ -579,6 +633,10 @@ export default withRouter(
changeEmailSubscription,
tipsSubscription,
theme,
setTheme,
changeTheme,
selectedTheme: viewer.theme,
setIsLoading: loadingStore.setIsLoading,
};
})(
observer(
Expand Down
1 change: 0 additions & 1 deletion public/locales/en/Common.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
"Culture_uk": "Ukrainian (Ukraine)",
"Culture_vi": "Vietnamese (Vietnam)",
"Culture_zh-CN": "Chinese (Simplified, PRC)",
"DarkMode": "Dark mode",
"Duplicate": "Create a copy",
"Delete": "Delete",
"Department": "Department",
Expand Down
1 change: 0 additions & 1 deletion public/locales/ru/Common.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
"Culture_uk": "Украинский (Украина)",
"Culture_vi": "Вьетнамский (Вьетнам)",
"Culture_zh-CN": "Китайский (упрощенный, КНР)",
"DarkMode": "Тёмная тема",
"Duplicate": "Создать копию",
"Delete": "Удалить",
"Department": "Отдел",
Expand Down
23 changes: 6 additions & 17 deletions web/ASC.Web.Client/src/Shell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,21 +175,6 @@ const InvalidRoute = (props) => (

const RedirectToHome = () => <Redirect to={PROXY_HOMEPAGE_URL} />;

const checkTheme = () => {
const theme = localStorage.getItem("theme");

if (theme) return theme;

if (
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
) {
return "Dark";
}

return "Base";
};

const Shell = ({ items = [], page = "home", ...rest }) => {
const {
isLoaded,
Expand All @@ -206,6 +191,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
setMaintenanceExist,
roomsMode,
setSnackbarExist,
userTheme,
} = rest;

useEffect(() => {
Expand Down Expand Up @@ -431,8 +417,8 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
}, [page]);

useEffect(() => {
setTheme(checkTheme());
}, []);
if (userTheme) setTheme(userTheme);
}, [userTheme]);

const pathname = window.location.pathname.toLowerCase();
const isEditor = pathname.indexOf("doceditor") !== -1;
Expand Down Expand Up @@ -567,6 +553,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => {

const ShellWrapper = inject(({ auth, backup }) => {
const { init, isLoaded, settingsStore, setProductVersion, language } = auth;

const {
personal,
roomsMode,
Expand Down Expand Up @@ -605,11 +592,13 @@ const ShellWrapper = inject(({ auth, backup }) => {
setTheme,
roomsMode,
setSnackbarExist,
userTheme: auth?.userStore?.user?.theme,
};
})(observer(Shell));

const ThemeProviderWrapper = inject(({ auth }) => {
const { settingsStore } = auth;

return { theme: settingsStore.theme };
})(observer(ThemeProvider));

Expand Down

0 comments on commit 750b49f

Please sign in to comment.