- {(account.accountType === ACCOUNT_MICROSOFT) && (
-
+ {(account.accountType != ACCOUNT_OFFLINE) && (
{
dispatch(openModal('AddAccount'))}>
- Добавить профиль
+ Добавить аккаунт
diff --git a/src/common/modals/ActionConfirmation.js b/src/common/modals/ActionConfirmation.js
index 0b09f07a2..429d94650 100644
--- a/src/common/modals/ActionConfirmation.js
+++ b/src/common/modals/ActionConfirmation.js
@@ -68,14 +68,14 @@ export default function ActionConfirmation({
applyChoice('abort', abortCallback, fileName, dispatch, delay);
}}
>
- Abort
+ Отмена
diff --git a/src/common/modals/AddInstance/CurseForgeModpacks/index.js b/src/common/modals/AddInstance/CurseForgeModpacks/index.js
index e4ffd63b0..00f3c77d8 100644
--- a/src/common/modals/AddInstance/CurseForgeModpacks/index.js
+++ b/src/common/modals/AddInstance/CurseForgeModpacks/index.js
@@ -1,5 +1,6 @@
/* eslint-disable no-nested-ternary */
import React, { useState, useEffect, useRef } from 'react';
+import { ipcRenderer } from 'electron';
import styled from 'styled-components';
import { Select, Input } from 'antd';
import { useDebouncedCallback } from 'use-debounce';
@@ -9,7 +10,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBomb, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
import { getSearch } from '../../../api';
import ModpacksListWrapper from './ModpacksListWrapper';
-import Oxfortpacks from '../Oxfortpacks';
let lastRequest;
const CurseForgeModpacks = ({ setStep, setVersion, setModpack }) => {
@@ -70,6 +70,8 @@ const CurseForgeModpacks = ({ setStep, setVersion, setModpack }) => {
};
useEffect(() => {
+ const discordRPCDetails = `Смотрит сборки CurseForge`;
+ ipcRenderer.invoke('update-discord-rpc', discordRPCDetails);
updateModpacks();
}, [searchText, sortBy, minecraftVersion, categoryId]);
diff --git a/src/common/modals/AddInstance/FTBModpacks/index.js b/src/common/modals/AddInstance/FTBModpacks/index.js
index 45285f09c..9788b18bd 100644
--- a/src/common/modals/AddInstance/FTBModpacks/index.js
+++ b/src/common/modals/AddInstance/FTBModpacks/index.js
@@ -1,5 +1,6 @@
/* eslint-disable */
import React, { useState, useEffect, useRef } from 'react';
+import { ipcRenderer } from 'electron';
import styled from 'styled-components';
import { Input } from 'antd';
import { useDebouncedCallback } from 'use-debounce';
@@ -25,6 +26,8 @@ const FTBModpacks = ({ setStep, setModpack, setVersion }) => {
const [error, setError] = useState(false);
useEffect(() => {
+ const discordRPCDetails = `Смотрит сборки FTB`;
+ ipcRenderer.invoke('update-discord-rpc', discordRPCDetails);
const init = async () => {
let data;
if (searchText.length < 3) {
diff --git a/src/common/modals/AddInstance/Oxfortpacks/index.js b/src/common/modals/AddInstance/Oxfortpacks/index.js
index abe2be134..d999e1ee6 100644
--- a/src/common/modals/AddInstance/Oxfortpacks/index.js
+++ b/src/common/modals/AddInstance/Oxfortpacks/index.js
@@ -1,5 +1,6 @@
/* eslint-disable no-nested-ternary */
import React, { useState, useEffect, useRef } from 'react';
+import { ipcRenderer } from 'electron';
import styled from 'styled-components';
import { Select, Input } from 'antd';
import { useDebouncedCallback } from 'use-debounce';
@@ -69,6 +70,8 @@ const Oxfortpacks = ({ setStep, setVersion, setModpack }) => {
};
useEffect(() => {
+ const discordRPCDetails = `Смотрит сборки OxFORTPACK`;
+ ipcRenderer.invoke('update-discord-rpc', discordRPCDetails);
updateModpacks();
}, [searchText, sortBy, minecraftVersion, categoryId]);
diff --git a/src/common/modals/ChangeLogs/changeLog.js b/src/common/modals/ChangeLogs/changeLog.js
index 119b4417f..483d350f0 100644
--- a/src/common/modals/ChangeLogs/changeLog.js
+++ b/src/common/modals/ChangeLogs/changeLog.js
@@ -1,20 +1,40 @@
module.exports = {
new: [
- {
- header: 'Поддержка авторизации OxAUTH и ElyBy',
+ {
+ header: 'Менеджер скриншотов со всех сборок',
+ content: "на главном экране лаунчера"
// content: 'модпаков CurseForge для OxMIRROR',
- },
+ }
// {
// header: 'Поддержка Discord RPC',
// content: '(отображение активности в лаунчере)',
- //advanced: { cm: '4eec052e' }
+ // advanced: { cm: '4eec052e' }
// }
],
improvements: [
- // {
- // header: 'Изменён текст в некоторых диалогах',
- //content: 'сборок OxMODPACK'
- // },
+ {
+ header: 'Отображение скинов для профилей',
+ content: 'OxAUTH и Ely.by'
+ },
+ {
+ header: 'Цветовое выделение кнопки профиля',
+ content: 'в зависимости от типа аккаунта'
+ },
+ {
+ header: 'Увеличена ширина превью изображений',
+ content: 'на вкладке Скриншоты'
+ },
+ {
+ header: 'Кнопка открытия меню скриншотов',
+ content: 'в контекстном меню сборок'
+ },
+ {
+ header: 'Изменена сортировка вкладок',
+ content: 'в боковом меню управления сборкой'
+ },
+ {
+ header: 'Больше статусов для Discord RPC'
+ }
// {
// header: 'Добавлена кнопка отключения активностей Discord',
// }
@@ -35,16 +55,16 @@ module.exports = {
// }
],
bugfixes: [
- {
- header: 'Убран лишний отступ от верхнего края окна лаунчера',
- content: 'на главном экране со списком клиентов'
+ {
+ header: 'Исправлено окно просмотра изображений'
+ // content: 'на главном экране со списком клиентов'
// advanced: { cm: '8ec97baa', pr: '1382' }
- },
- // {
- // header: 'Исправлена установка модпаков',
- // content: 'без папки overrides.'
- // advanced: { cm: '8ec97baa', pr: '1382' }
- // }
+ },
+ {
+ header: 'Исправлено удаление изображений',
+ // content: 'без папки overrides.'
+ // advanced: { cm: '8ec97baa', pr: '1382' }
+ }
// {
// header: 'Добавление аккаунта Microsoft',
// content: 'через Менеджер аккаунтов.',
diff --git a/src/common/modals/InfoModal.js b/src/common/modals/InfoModal.js
index 157394b08..df9940e01 100644
--- a/src/common/modals/InfoModal.js
+++ b/src/common/modals/InfoModal.js
@@ -10,10 +10,10 @@ const InfoModal = ({ modName, error, preventClose }) => {
overflow-x: hidden;
`}
preventClose={preventClose}
- title="Mod failed to download"
+ title="Не удалось загрузить модификацию"
>
- The mod ${modName || ''} failed to download
+ Модификацию ${modName || ''} не удалось загрузить
props.theme.palette.grey[900]};
diff --git a/src/common/modals/InstanceManager/Screenshots.js b/src/common/modals/InstanceManager/Screenshots.js
index 6c9e7c8ad..4320df693 100644
--- a/src/common/modals/InstanceManager/Screenshots.js
+++ b/src/common/modals/InstanceManager/Screenshots.js
@@ -215,7 +215,7 @@ const Screenshots = ({ instanceName }) => {
onClick={() => {
if (selectedItems.length) {
dispatch(
- openModal('Подтверждение удаления', {
+ openModal('ActionConfirmation', {
message: 'Вы уверены, что хотите удалить эти изображения?',
confirmCallback: deleteFile,
title: 'Подтвердить'
@@ -261,7 +261,7 @@ const Screenshots = ({ instanceName }) => {
dispatch(
- openModal('Скриншот', {
+ openModal('Screenshot', {
screenshotsPath,
file
})
@@ -304,7 +304,7 @@ const Screenshots = ({ instanceName }) => {
diff --git a/src/common/modals/ModsBrowser.js b/src/common/modals/ModsBrowser.js
index 902f556ce..6eec968ed 100644
--- a/src/common/modals/ModsBrowser.js
+++ b/src/common/modals/ModsBrowser.js
@@ -375,6 +375,8 @@ const ModsBrowser = ({ instanceName, gameVersions }) => {
}, [filterType, categoryId]);
useEffect(() => {
+ const discordRPCDetails = `Ищет интересные моды`;
+ ipcRenderer.invoke('update-discord-rpc', discordRPCDetails);
loadMoreMods();
}, []);
diff --git a/src/common/modals/Screenshot.js b/src/common/modals/Screenshot.js
index e259b67f6..178c84fa0 100644
--- a/src/common/modals/Screenshot.js
+++ b/src/common/modals/Screenshot.js
@@ -1,7 +1,26 @@
-import React from 'react';
+import React, { useEffect, useState, useCallback, useRef } from 'react';
import path from 'path';
+import fse from 'fs-extra';
+import { clipboard, ipcRenderer } from 'electron';
import styled from 'styled-components';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { useSelector, useDispatch } from 'react-redux';
+import {
+ ContextMenuTrigger,
+ ContextMenu,
+ MenuItem,
+ hideMenu
+} from 'react-contextmenu';
+import {
+ faTrash,
+ faCopy,
+ faLink,
+ faFolder,
+ faImage
+} from '@fortawesome/free-solid-svg-icons';
+
import Modal from '../components/Modal';
+import { openModal } from '../reducers/modals/actions';
const Container = styled.div`
display: flex;
@@ -17,7 +36,33 @@ const Img = styled.img`
`;
export default function Screenshot({ screenshotsPath, file }) {
- const image = `file:///${path.join(screenshotsPath, file.name)}`;
+ const imagePath = `${path.join(screenshotsPath, file.name)}`
+ const image = `file:///${imagePath}`;
+ const [progressUpdate, setProgressUpdate] = useState(null);
+ const [uploadingFileName, setUploadingFileName] = useState(null);
+ const dispatch = useDispatch();
+
+ const isImageCopied = progressUpdate => {
+ if (
+ progressUpdate === 100 &&
+ uploadingFileName !== null
+ ) {
+ return 'Изображение скопировано в буфер обмена!';
+ } else if (
+ uploadingFileName != null
+ ) {
+ return 'Подождите загрузки предыдущего изображения';
+ } else return 'Поделиться ссылкой на изображение';
+ };
+
+ const deleteFile = useCallback(
+ async() => {
+ await fse.remove(
+ imagePath
+ );
+ },
+ []
+ );
return (
-
-
-
+
+
+
+
+
+
+
+ {true && (
+ <>
+ {
+ clipboard.writeImage(
+ path.join(file.screenshotsPath, file.name)
+ );
+ }}
+ >
+
+ Копировать картинку
+
+ {
+ dispatch(
+ openModal('ActionConfirmation', {
+ message:
+ 'Вы уверены, что хотите удалить это изображение?',
+ fileName: file.name,
+ confirmCallback: deleteFile,
+ title: 'Подтвердить'
+ })
+ );
+ }}
+ >
+
+ Удалить
+
+ >
+ )}
+
);
}
+
+const StyledContexMenu = styled(ContextMenu)`
+ svg {
+ margin: 0 7px 0 0;
+ }
+`;
+
+const ImgurShareMenuItem = styled(MenuItem)`
+ overflow: hidden;
+ position: relative;
+ padding: 0 !important;
+`;
+
+const MenuShareLink = styled.div`
+ padding: 4px 10px;
+ position: relative;
+ svg {
+ margin: 0 7px 0 0;
+ }
+`;
+
+const LoadingSlider = styled.div`
+ position: absolute;
+ bottom: 4px;
+ z-index: -1;
+ width: 100%;
+ height: 100%;
+ transform: ${props =>
+ props.uploadingFileName != null
+ ? `translate(${props.translateAmount}%)`
+ : 'translate(-100%)'};
+ transition: transform 0.1s ease-in-out;
+ background: ${props => props.theme.palette.primary.main};
+`;
\ No newline at end of file
diff --git a/src/common/modals/ScreenshotManager.js b/src/common/modals/ScreenshotManager.js
new file mode 100644
index 000000000..15c234000
--- /dev/null
+++ b/src/common/modals/ScreenshotManager.js
@@ -0,0 +1,608 @@
+/* eslint-disable */
+import React, { useEffect, useState, useCallback, useRef } from 'react';
+import { promises as fs, watch, createReadStream } from 'fs';
+import { clipboard, ipcRenderer } from 'electron';
+import fse from 'fs-extra';
+import path from 'path';
+import base64 from 'base64-stream';
+import getStream from 'get-stream';
+import styled from 'styled-components';
+import makeDir from 'make-dir';
+import { Checkbox } from 'antd';
+import { useSelector, useDispatch } from 'react-redux';
+import groupBy from 'lodash/groupBy';
+import isEqual from 'lodash/isEqual';
+import sortBy from 'lodash/sortBy';
+import Modal from '../components/Modal';
+import {
+ ContextMenuTrigger,
+ ContextMenu,
+ MenuItem,
+ hideMenu
+} from 'react-contextmenu';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import {
+ faTrash,
+ faCopy,
+ faLink,
+ faImage
+} from '@fortawesome/free-solid-svg-icons';
+import { _getInstancesPath, _getInstances } from '../utils/selectors';
+import { openModal } from '../reducers/modals/actions';
+import { imgurPost } from '../api';
+
+const getScreenshots = async (instancesPath, instance) => {
+ const screenshotsPath = path.join(instancesPath, instance.name, 'screenshots');
+ await makeDir(screenshotsPath);
+ const files = await fs.readdir(screenshotsPath);
+ const screenshots = [];
+ try {
+ await Promise.all(
+ files.map(async element => {
+ const stats = await fs.stat(path.join(screenshotsPath, element));
+ const fileBirthdate = new Date(stats.birthtimeMs);
+ const timeDiff = Date.now() - fileBirthdate;
+ const days = parseInt(Math.floor(timeDiff / 1000) / 60 / 60 / 24, 10);
+
+ screenshots.push({
+ name: element,
+ screenshotsPath: screenshotsPath,
+ days,
+ timestamp: fileBirthdate,
+ size: stats.size
+ });
+ })
+ );
+ return screenshots.sort((a, b) => a.timestamp - b.timestamp);
+ } catch (e) {
+ console.error(e);
+ }
+};
+
+const getImgurLink = async (imagePath, fileSize, setProgressUpdate) => {
+ const updateProgress = progressEvent => {
+ setProgressUpdate(
+ Math.round((progressEvent.loaded * 100) / progressEvent.total)
+ );
+ };
+
+ const imageReadStream = createReadStream(imagePath);
+ const encodedData = new base64.Base64Encode();
+ const b64s = imageReadStream.pipe(encodedData);
+ const base64String = await getStream(b64s);
+
+ if (fileSize < 10485760) {
+ console.log(imagePath)
+ console.log(base64String)
+ const res = await imgurPost(base64String, updateProgress);
+
+ if (res.status == 200) {
+ clipboard.writeText(res.data.data.link);
+ }
+ }
+};
+
+const getTitle = days => {
+ const parsedDays = Number.parseInt(days, 10);
+ if (parsedDays === 0) return 'Сегодня';
+ else if (parsedDays === 1) return 'Вчера';
+ else if (parsedDays > 1 && parsedDays < 30) return `${days} дней назад`;
+ else if (parsedDays >= 30 && parsedDays < 365)
+ return `${Math.floor(days / 30)} мес. назад`;
+ else if (parsedDays >= 365) return `${Math.floor(days / 365)} лет назад`;
+};
+
+const getScreenshotsCount = groups =>
+ Object.values(groups).reduce((prev, curr) => (prev += curr.length), 0);
+
+const getScreenshotsList = groups =>
+ Object.values(groups).reduce((prev, curr) => prev.concat(curr), []);
+
+let watcher;
+
+const ScreenshotManager = () => {
+ const instancesPath = useSelector(_getInstancesPath);
+ const instances = useSelector(_getInstances);
+ const [dateGroups, setDateGroups] = useState({});
+ const [selectedItems, setSelectedItems] = useState([]);
+ const [selectedItemsPath, setSelectedItemsPath] = useState([]);
+ const [progressUpdate, setProgressUpdate] = useState(null);
+ const [uploadingFileName, setUploadingFileName] = useState(null);
+ const [contextMenuOpen, setContextMenuOpen] = useState(false);
+ const dispatch = useDispatch();
+
+ const isImageCopied = progressUpdate => {
+ if (
+ progressUpdate === 100 &&
+ uploadingFileName !== null &&
+ selectedItems.includes(uploadingFileName)
+ ) {
+ return 'Изображение скопировано в буфер обмена!';
+ } else if (
+ uploadingFileName != null &&
+ selectedItems[0] != uploadingFileName
+ ) {
+ return 'Подождите загрузки предыдущего изображения';
+ } else return 'Поделиться ссылкой на изображение';
+ };
+
+ const containerRef = useRef(null);
+
+ const selectAll = useCallback(() => {
+ if (
+ isEqual(
+ sortBy(getScreenshotsList(dateGroups).map(x => x.name)),
+ sortBy(selectedItems)
+ )
+ ) {
+ setSelectedItems([]);
+ setSelectedItemsPath([]);
+ } else {
+ setSelectedItems(getScreenshotsList(dateGroups).map(x => x.name));
+ setSelectedPath(getScreenshotsList(dateGroups).map(x => x.screenshotsPath));
+ }
+ }, [selectedItems, selectedItemsPath, dateGroups, setSelectedItems, setSelectedItemsPath]);
+
+ const deleteFile = useCallback(
+ async fileName => {
+ if (selectedItems.length === 1) {
+ console.log(selectedItemsPath[0])
+ await fse.remove(
+ path.join(
+ selectedItemsPath[0],
+ selectedItems[0]
+ )
+ );
+ } else if (selectedItems.length > 1) {
+ await Promise.all(
+ selectedItems.map(screenFolder => {
+ selectedItems.map(async screenShot => {
+ await fse.remove(
+ path.join(screenFolder, screenShot)
+ );
+ })
+ })
+ );
+ }
+ }
+ );
+
+ const startListener = async () => {
+ var screenshots = [];
+ console.log(instances)
+ instances.forEach(async(instance) => {
+ const screenshotsPath = path.join(instancesPath, instance.name, 'screenshots');
+ await makeDir(screenshotsPath);
+ const instanceScreenshots = await getScreenshots(instancesPath, instance);
+ screenshots = screenshots.concat(instanceScreenshots);
+ console.log(screenshotsPath)
+ setDateGroups(groupBy(screenshots, 'days'));
+ watcher = watch(screenshotsPath, async (event, filename) => {
+ if (filename) {
+ setDateGroups(groupBy(screenshots, 'days'));
+ }
+ });
+ })
+ console.log(screenshots)
+ setDateGroups(groupBy(screenshots, 'days'));
+ };
+
+ useEffect(() => {
+ startListener();
+
+ const discordRPCDetails = `Любуется скриншотами`;
+ ipcRenderer.invoke('update-discord-rpc', discordRPCDetails);
+
+ return () => watcher?.close();
+ }, []);
+
+ useEffect(() => {
+ if (containerRef.current) {
+ const eventHandler = e => {
+ if (contextMenuOpen) {
+ e.preventDefault();
+ containerRef.current.scrollTop = 0;
+ }
+ };
+ containerRef?.current?.addEventListener('wheel', eventHandler);
+ return () =>
+ containerRef?.current?.removeEventListener('wheel', eventHandler);
+ }
+ }, [containerRef.current, contextMenuOpen]);
+
+ return (
+
+
+
+ {Object.entries(dateGroups).length > 0 ? (
+ Object.entries(dateGroups).map(([key, group]) => {
+ return (
+
+ {getTitle(key.toString())}
+
+ {group.map(file => (
+
+
+
+
+ {
+ setSelectedItems(
+ selectedItems.indexOf(file.name) > -1
+ ? selectedItems.filter(x => x != file.name)
+ : selectedItems.concat([file.name])
+ );
+ setSelectedItemsPath(
+ selectedItemsPath.indexOf(file.screenshotsPath) > -1
+ ? selectedItemsPath.filter(x => x != file.screenshotsPath)
+ : selectedItemsPath.concat([file.screenshotsPath])
+ );
+ }}
+ checked={selectedItems.indexOf(file.name) > -1}
+ selected={selectedItems.indexOf(file.name) > -1}
+ />
+
+
+ dispatch(
+ openModal('Screenshot', {
+ screenshotsPath: file.screenshotsPath,
+ file: file
+ })
+ )
+ }
+ selected={selectedItems.indexOf(file.name) > -1}
+ src={`file:///${path.join(
+ file.screenshotsPath,
+ file.name
+ )}`}
+ />
+
+
+ {
+ setContextMenuOpen(true);
+ if (
+ selectedItems.length === 0 ||
+ !selectedItems.includes(file.name)
+ ) {
+ setSelectedItems([file.name]);
+ setSelectedItemsPath([file.screenshotsPath]);
+ } else if (
+ selectedItems.length === 1 &&
+ !selectedItems.includes(file.name)
+ ) {
+ setSelectedItems([...selectedItems, file.name]);
+ setSelectedItemsPath([...selectedItemsPath, file.screenshotsPath]);
+ }
+ }}
+ onHide={() => {
+ setContextMenuOpen(false);
+ if (!selectedItems.includes(file.name)) {
+ setSelectedItems([file.name]);
+ setSelectedItemsPath([file.screenshotsPath]);
+ }
+ }}
+ >
+ {selectedItems.length > 1 &&
+ selectedItems.length <
+ getScreenshotsCount(dateGroups) ? (
+ {
+ dispatch(
+ openModal('ActionConfirmation', {
+ message:
+ 'Вы уверены, что хотите удалить этот скриншот?',
+ screenshotsPath: file.screenshotsPath,
+ confirmCallback: deleteFile,
+ title: 'Подтвердить'
+ })
+ );
+ }}
+ >
+
+ {`Удалить ${selectedItems.length} изобр.`}
+
+ ) : (
+ selectedItems.length ===
+ getScreenshotsCount(dateGroups) &&
+ getScreenshotsCount(dateGroups) > 1 && (
+ {
+ dispatch(
+ openModal('ActionConfirmation', {
+ message:
+ 'Вы уверены, что хотите удалить этот скриншот?',
+ screenshotsPath: file.screenshotsPath,
+ confirmCallback: deleteFile,
+ title: 'Подтвердить'
+ })
+ );
+ }}
+ >
+
+ Удалить все
+
+ )
+ )}
+
+ {selectedItems.length < 2 && (
+ <>
+
+ dispatch(
+ openModal('Screenshot', {
+ screenshotsPath: file.screenshotsPath,
+ file
+ })
+ )
+ }
+ >
+
+ Просмотр
+
+ {
+ clipboard.writeImage(
+ path.join(file.screenshotsPath, file.name)
+ );
+ }}
+ >
+
+ Копировать картинку
+
+ {
+ if (file.size < 10485760) {
+ setUploadingFileName(file.name);
+ try {
+ await getImgurLink(
+ path.join(file.screenshotsPath, file.name),
+ file.size,
+ setProgressUpdate
+ );
+ } finally {
+ setUploadingFileName(null);
+ }
+ }
+ setTimeout(() => {
+ hideMenu();
+ }, 1000);
+ }}
+ >
+
+
+ {file.size < 10485760
+ ? isImageCopied(
+ progressUpdate,
+ uploadingFileName,
+ selectedItems
+ )
+ : `Изображение слишком большое... ${Math.floor(
+ file.size / 1024 / 1024
+ )}МБ`}
+
+
+
+ {
+ dispatch(
+ openModal('ActionConfirmation', {
+ message:
+ 'Вы уверены, что хотите удалить это изображение?',
+ screenshotsPath: file.screenshotsPath,
+ confirmCallback: deleteFile,
+ title: 'Подтвердить'
+ })
+ );
+ }}
+ >
+
+ Удалить
+
+ >
+ )}
+
+
+ ))}
+
+
+ );
+ })
+ ) : (
+ Скриншоты не найдены
+ )}
+
+
+
+ );
+};
+
+export default ScreenshotManager;
+
+const ExternalContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ height: 100%;
+`;
+
+const Container = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ width: 100%;
+ background: ${props => props.theme.palette.secondary.main};
+ overflow-y: auto;
+ overflow-x: hidden;
+ height: ${props => (props.groupsCount !== 0 ? 'auto' : '100%')};
+`;
+
+const Bar = styled.div`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ min-height: 40px;
+ max-height: 40px;
+ width: 100%;
+ background: ${props => props.theme.palette.secondary.main};
+`;
+
+const GlobalCheckbox = styled(Checkbox)`
+ margin: 7px;
+`;
+
+const DateSection = styled.div`
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap-reverse;
+ padding: 50px 10px 20px 10px;
+ background: ${props => props.theme.palette.secondary.dark};
+ margin: 10px 0 0 0;
+`;
+
+const NoScreenAvailable = styled.div`
+ height: 100%;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+`;
+
+const StyledContexMenu = styled(ContextMenu)`
+ svg {
+ margin: 0 7px 0 0;
+ }
+`;
+
+const DeleteButton = styled(({ selectedItems, ...props }) => (
+ // eslint-disable-next-line react/jsx-props-no-spreading
+
+))`
+ margin: 0 10px;
+ transition: color 0.3s ease-in-out;
+ &:hover {
+ path {
+ color: ${props =>
+ props.selectedItems.length > 0 ? props.theme.palette.colors.red : ''};
+ }
+ }
+ cursor: ${props => (props.selectedItems.length > 0 ? 'pointer' : '')};
+`;
+
+const DataSectionContainer = styled.span`
+ &:first-child {
+ margin-top: -45px;
+ }
+`;
+
+const TitleDataSection = styled.h2`
+ position: relative;
+ top: 50px;
+ left: 20px;
+`;
+
+const LoadingSlider = styled.div`
+ position: absolute;
+ bottom: 4px;
+ z-index: -1;
+ width: 100%;
+ height: 100%;
+ transform: ${props =>
+ props.uploadingFileName != null
+ ? `translate(${props.translateAmount}%)`
+ : 'translate(-100%)'};
+ transition: transform 0.1s ease-in-out;
+ background: ${props => props.theme.palette.primary.main};
+`;
+
+const Photo = styled.img`
+ height: 144px;
+ max-height: 144px;
+ width: 256px;
+ max-width: 256px;
+ margin: 10px;
+ object-fit: cover;
+ background: ${props => props.theme.palette.secondary.light};
+ border-radius: 5px;
+ transition: transform 0.2s ease-in-out;
+ filter: brightness(80%);
+ border: ${props =>
+ props.selected ? `solid 2px ${props.theme.palette.colors.blue}` : ''};
+`;
+
+const SelectCheckBoxContainer = styled.div`
+ height: 10px;
+ width: 10px;
+ position: absolute;
+ top: 0px;
+ left: 0px;
+`;
+
+const SelectCheckBox = styled(Checkbox)`
+ opacity: 0;
+ position: absolute;
+ top: 10px;
+ left: 15px;
+ z-index: 2;
+ opacity: ${props => (props.selected ? 1 : 0)};
+`;
+
+const ImgurShareMenuItem = styled(MenuItem)`
+ overflow: hidden;
+ position: relative;
+ padding: 0 !important;
+`;
+
+const MenuShareLink = styled.div`
+ padding: 4px 10px;
+ position: relative;
+ svg {
+ margin: 0 7px 0 0;
+ }
+`;
+const PhotoContainer = styled.div`
+ position: relative;
+ height: 144px;
+ max-height: 144px;
+ width: 256px;
+ max-width: 256px;
+ margin: 10px;
+ background: transparent;
+ border-radius: 5px;
+ transition: transform 0.2s ease-in-out;
+ filter: brightness(80%);
+ transform: ${props =>
+ props.selectedItems.indexOf(props.name) > -1 ? 'scale(1.1)' : 'scale(1)'};
+ &:hover {
+ transform: scale(1.1);
+ ${SelectCheckBox} {
+ opacity: 1;
+ }
+ }
+`;
diff --git a/src/common/modals/Settings/index.js b/src/common/modals/Settings/index.js
index 0721977f0..b650d3e74 100644
--- a/src/common/modals/Settings/index.js
+++ b/src/common/modals/Settings/index.js
@@ -1,12 +1,13 @@
import React, { useState, lazy } from 'react';
import styled from 'styled-components';
+import { ipcRenderer } from 'electron';
import { Button } from 'antd';
import { useDispatch } from 'react-redux';
import Modal from '../../components/Modal';
import AsyncComponent from '../../components/AsyncComponent';
import CloseButton from '../../components/CloseButton';
import SocialButtons from '../../components/SocialButtons';
-import { closeModal, openModal } from '../../reducers/modals/actions';
+import { closeModal } from '../../reducers/modals/actions';
import KoFiButton from '../../assets/ko-fi.png';
const Container = styled.div`
@@ -105,6 +106,9 @@ export default function Settings() {
const dispatch = useDispatch();
const ContentComponent = pages[page].component;
+ const discordRPCDetails = `Настраивает лаунчер`;
+ ipcRenderer.invoke('update-discord-rpc', discordRPCDetails);
+
return (
- OxLAUNCHER 1.4.0
+ OxLAUNCHER 1.4.1
by Proxwian