mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-22 10:22:31 +01:00
add preference for color intensity
https://github.com/mifi/lossless-cut/discussions/1507
This commit is contained in:
parent
10f8092d15
commit
0afa76a165
@ -123,6 +123,7 @@ const defaults = {
|
||||
},
|
||||
allowMultipleInstances: false,
|
||||
darkMode: true,
|
||||
preferStrongColors: false,
|
||||
};
|
||||
|
||||
// For portable app: https://github.com/mifi/lossless-cut/issues/645
|
||||
|
14
src/App.jsx
14
src/App.jsx
@ -26,7 +26,7 @@ import useFrameCapture from './hooks/useFrameCapture';
|
||||
import useSegments from './hooks/useSegments';
|
||||
import useDirectoryAccess, { DirectoryAccessDeclinedError } from './hooks/useDirectoryAccess';
|
||||
|
||||
import UserSettingsContext from './contexts/UserSettingsContext';
|
||||
import { UserSettingsContext, SegColorsContext } from './contexts';
|
||||
|
||||
import NoFileLoaded from './NoFileLoaded';
|
||||
import Canvas from './Canvas';
|
||||
@ -50,6 +50,7 @@ import OutputFormatSelect from './components/OutputFormatSelect';
|
||||
|
||||
import { loadMifiLink, runStartupCheck } from './mifi';
|
||||
import { controlsBackground, darkModeTransition } from './colors';
|
||||
import { getSegColor } from './util/colors';
|
||||
import {
|
||||
getStreamFps, isCuttingStart, isCuttingEnd,
|
||||
readFileMeta, getSmarterOutFormat, renderThumbnails as ffmpegRenderThumbnails,
|
||||
@ -175,7 +176,7 @@ const App = memo(() => {
|
||||
const allUserSettings = useUserSettingsRoot();
|
||||
|
||||
const {
|
||||
captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMovData, setPreserveMovData, movFastStart, setMovFastStart, avoidNegativeTs, autoMerge, timecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, askBeforeClose, enableAskForImportChapters, enableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, wheelSensitivity, invertTimelineScroll, language, ffmpegExperimental, hideNotifications, autoLoadTimecode, autoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, setSimpleMode, outSegTemplate, setOutSegTemplate, keyboardSeekAccFactor, keyboardNormalSeekSpeed, enableTransferTimestamps, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, segmentsToChaptersOnly, keyBindings, setKeyBindings, resetKeyBindings, enableSmartCut, customFfPath, storeProjectInWorkingDir, setStoreProjectInWorkingDir, enableOverwriteOutput, mouseWheelZoomModifierKey, captureFrameMethod, captureFrameQuality, captureFrameFileNameFormat, enableNativeHevc, cleanupChoices, setCleanupChoices, darkMode, setDarkMode,
|
||||
captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMovData, setPreserveMovData, movFastStart, setMovFastStart, avoidNegativeTs, autoMerge, timecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, askBeforeClose, enableAskForImportChapters, enableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, wheelSensitivity, invertTimelineScroll, language, ffmpegExperimental, hideNotifications, autoLoadTimecode, autoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, setSimpleMode, outSegTemplate, setOutSegTemplate, keyboardSeekAccFactor, keyboardNormalSeekSpeed, enableTransferTimestamps, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, segmentsToChaptersOnly, keyBindings, setKeyBindings, resetKeyBindings, enableSmartCut, customFfPath, storeProjectInWorkingDir, setStoreProjectInWorkingDir, enableOverwriteOutput, mouseWheelZoomModifierKey, captureFrameMethod, captureFrameQuality, captureFrameFileNameFormat, enableNativeHevc, cleanupChoices, setCleanupChoices, darkMode, setDarkMode, preferStrongColors,
|
||||
} = allUserSettings;
|
||||
|
||||
useEffect(() => {
|
||||
@ -510,6 +511,13 @@ const App = memo(() => {
|
||||
...allUserSettings, toggleCaptureFormat, changeOutDir, toggleKeyframeCut, togglePreserveMovData, toggleMovFastStart, toggleExportConfirmEnabled, toggleSegmentsToChapters, togglePreserveMetadataOnMerge, toggleSimpleMode, toggleSafeOutputFileName, effectiveExportMode,
|
||||
}), [allUserSettings, changeOutDir, effectiveExportMode, toggleCaptureFormat, toggleExportConfirmEnabled, toggleKeyframeCut, toggleMovFastStart, togglePreserveMetadataOnMerge, togglePreserveMovData, toggleSafeOutputFileName, toggleSegmentsToChapters, toggleSimpleMode]);
|
||||
|
||||
const segColorsContext = useMemo(() => ({
|
||||
getSegColor: (seg) => {
|
||||
const color = getSegColor(seg);
|
||||
return preferStrongColors ? color.desaturate(0.2) : color.desaturate(0.6);
|
||||
},
|
||||
}), [preferStrongColors]);
|
||||
|
||||
const isCopyingStreamId = useCallback((path, streamId) => (
|
||||
!!(copyStreamIdsByFile[path] || {})[streamId]
|
||||
), [copyStreamIdsByFile]);
|
||||
@ -2153,6 +2161,7 @@ const App = memo(() => {
|
||||
// throw new Error('Test error boundary');
|
||||
|
||||
return (
|
||||
<SegColorsContext.Provider value={segColorsContext}>
|
||||
<UserSettingsContext.Provider value={userSettingsContext}>
|
||||
<ThemeProvider value={theme}>
|
||||
<div className={darkMode ? 'dark-theme' : undefined} style={{ display: 'flex', flexDirection: 'column', height: '100vh', color: 'var(--gray12)', background: 'var(--gray1)', transition: darkModeTransition }}>
|
||||
@ -2416,6 +2425,7 @@ const App = memo(() => {
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</UserSettingsContext.Provider>
|
||||
</SegColorsContext.Provider>
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -18,7 +18,8 @@ import Select from './components/Select';
|
||||
import SimpleModeButton from './components/SimpleModeButton';
|
||||
import { withBlur, mirrorTransform, checkAppPath } from './util';
|
||||
import { toast } from './swal';
|
||||
import { getSegColor } from './util/colors';
|
||||
import { getSegColor as getSegColorRaw } from './util/colors';
|
||||
import { useSegColors } from './contexts';
|
||||
import { formatDuration, parseDuration, isExactDurationMatch } from './util/duration';
|
||||
import useUserSettings from './hooks/useUserSettings';
|
||||
|
||||
@ -31,6 +32,7 @@ const leftRightWidth = 100;
|
||||
|
||||
const CutTimeInput = memo(({ darkMode, cutTime, setCutTime, startTimeOffset, seekAbs, currentCutSeg, currentApparentCutSeg, isStart }) => {
|
||||
const { t } = useTranslation();
|
||||
const { getSegColor } = useSegColors();
|
||||
|
||||
const [cutTimeManual, setCutTimeManual] = useState();
|
||||
|
||||
@ -41,8 +43,10 @@ const CutTimeInput = memo(({ darkMode, cutTime, setCutTime, startTimeOffset, see
|
||||
|
||||
const isCutTimeManualSet = () => cutTimeManual !== undefined;
|
||||
|
||||
const border = useMemo(() => {
|
||||
const segColor = getSegColor(currentCutSeg);
|
||||
const border = `.1em solid ${darkMode ? segColor.desaturate(0.9).lightness(50).string() : segColor.desaturate(0.7).lightness(60).string()}`;
|
||||
return `.1em solid ${darkMode ? segColor.desaturate(0.4).lightness(50).string() : segColor.desaturate(0.2).lightness(60).string()}`;
|
||||
}, [currentCutSeg, darkMode, getSegColor]);
|
||||
|
||||
const cutTimeInputStyle = {
|
||||
border, borderRadius: 5, backgroundColor: 'var(--gray5)', transition: darkModeTransition, fontSize: 13, textAlign: 'center', padding: '1px 5px', marginTop: 0, marginBottom: 0, marginLeft: isStart ? 0 : 5, marginRight: isStart ? 5 : 0, boxSizing: 'border-box', fontFamily: 'inherit', width: 90, outline: 'none',
|
||||
@ -142,6 +146,7 @@ const BottomBar = memo(({
|
||||
toggleEnableThumbnails, toggleWaveformMode, waveformMode, showThumbnails,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { getSegColor } = useSegColors();
|
||||
|
||||
// ok this is a bit over-engineered but what the hell!
|
||||
const loopSelectedSegmentsButtonStyle = useMemo(() => {
|
||||
@ -149,7 +154,7 @@ const BottomBar = memo(({
|
||||
const selectedSegmentsSafe = (selectedSegments.length > 1 ? selectedSegments : [selectedSegments[0], selectedSegments[0]]).slice(0, 10);
|
||||
|
||||
const gradientColors = selectedSegmentsSafe.map((seg, i) => {
|
||||
const segColor = getSegColor(seg);
|
||||
const segColor = getSegColorRaw(seg);
|
||||
// make colors stronger, the more segments
|
||||
return `${segColor.alpha(Math.max(0.4, Math.min(0.8, selectedSegmentsSafe.length / 3))).string()} ${((i / (selectedSegmentsSafe.length - 1)) * 100).toFixed(1)}%`;
|
||||
}).join(', ');
|
||||
@ -191,7 +196,7 @@ const BottomBar = memo(({
|
||||
const newIndex = currentSegIndexSafe + direction;
|
||||
const seg = cutSegments[newIndex];
|
||||
|
||||
const backgroundColor = seg && getSegColor(seg).desaturate(0.9).lightness(darkMode ? 35 : 55).string();
|
||||
const backgroundColor = seg && getSegColor(seg).desaturate(0.6).lightness(darkMode ? 35 : 55).string();
|
||||
const opacity = seg ? undefined : 0.5;
|
||||
const text = seg ? `${newIndex + 1}` : '-';
|
||||
const wide = text.length > 1;
|
||||
|
@ -12,7 +12,7 @@ import Swal from './swal';
|
||||
import useContextMenu from './hooks/useContextMenu';
|
||||
import useUserSettings from './hooks/useUserSettings';
|
||||
import { saveColor, controlsBackground, primaryTextColor, darkModeTransition } from './colors';
|
||||
import { getSegColor } from './util/colors';
|
||||
import { useSegColors } from './contexts';
|
||||
import { mySpring } from './animations';
|
||||
|
||||
const buttonBaseStyle = {
|
||||
@ -24,6 +24,7 @@ const neutralButtonColor = 'var(--gray8)';
|
||||
|
||||
const Segment = memo(({ darkMode, seg, index, currentSegIndex, formatTimecode, getFrameCount, updateOrder, invertCutSegments, onClick, onRemovePress, onRemoveSelected, onLabelSelectedSegments, onReorderPress, onLabelPress, selected, onSelectSingleSegment, onToggleSegmentSelected, onDeselectAllSegments, onSelectSegmentsByLabel, onSelectAllSegments, jumpSegStart, jumpSegEnd, addSegment, onViewSegmentTags, onExtractSegmentFramesAsImages, onInvertSelectedSegments }) => {
|
||||
const { t } = useTranslation();
|
||||
const { getSegColor } = useSegColors();
|
||||
|
||||
const ref = useRef();
|
||||
|
||||
@ -81,7 +82,7 @@ const Segment = memo(({ darkMode, seg, index, currentSegIndex, formatTimecode, g
|
||||
|
||||
const segColor = getSegColor(seg);
|
||||
|
||||
const color = segColor.desaturate(0.75).lightness(darkMode ? 35 : 55);
|
||||
const color = segColor.desaturate(0.25).lightness(darkMode ? 35 : 55);
|
||||
const borderColor = darkMode ? color.lighten(0.5) : color.darken(0.3);
|
||||
|
||||
return <b style={{ cursor: 'grab', color: 'white', padding: '0 4px', marginRight: 3, marginLeft: -3, background: color.string(), border: `1px solid ${isActive ? borderColor.string() : 'transparent'}`, borderRadius: 10, fontSize: 12 }}>{index + 1}</b>;
|
||||
@ -154,6 +155,7 @@ const SegmentList = memo(({
|
||||
jumpSegStart, jumpSegEnd, onViewSegmentTags,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { getSegColor } = useSegColors();
|
||||
|
||||
const { invertCutSegments, simpleMode, darkMode } = useUserSettings();
|
||||
|
||||
@ -198,7 +200,7 @@ const SegmentList = memo(({
|
||||
}
|
||||
|
||||
function renderFooter() {
|
||||
const getButtonColor = (seg) => getSegColor(seg).desaturate(0.8).lightness(darkMode ? 45 : 55).string();
|
||||
const getButtonColor = (seg) => getSegColor(seg).desaturate(0.3).lightness(darkMode ? 45 : 55).string();
|
||||
const currentSegColor = getButtonColor(currentCutSeg);
|
||||
const segAtCursorColor = getButtonColor(segmentAtCursor);
|
||||
|
||||
|
@ -12,8 +12,6 @@ import useUserSettings from './hooks/useUserSettings';
|
||||
|
||||
import { timelineBackground, darkModeTransition } from './colors';
|
||||
|
||||
import { getSegColor } from './util/colors';
|
||||
|
||||
const currentTimeWidth = 1;
|
||||
|
||||
const Waveform = memo(({ waveform, calculateTimelinePercent, durationSafe }) => {
|
||||
@ -295,8 +293,6 @@ const Timeline = memo(({
|
||||
)}
|
||||
|
||||
{apparentCutSegments.map((seg, i) => {
|
||||
const segColor = getSegColor(seg);
|
||||
|
||||
if (seg.start === 0 && seg.end === 0) return null; // No video loaded
|
||||
|
||||
const selected = invertCutSegments || isSegmentSelected({ segId: seg.segId });
|
||||
@ -304,14 +300,11 @@ const Timeline = memo(({
|
||||
return (
|
||||
<TimelineSeg
|
||||
key={seg.segId}
|
||||
seg={seg}
|
||||
segNum={i}
|
||||
segColor={segColor}
|
||||
onSegClick={setCurrentSegIndex}
|
||||
isActive={i === currentSegIndexSafe}
|
||||
duration={durationSafe}
|
||||
name={seg.name}
|
||||
cutStart={seg.start}
|
||||
cutEnd={seg.end}
|
||||
invertCutSegments={invertCutSegments}
|
||||
formatTimecode={formatTimecode}
|
||||
selected={selected}
|
||||
|
@ -4,13 +4,18 @@ import { FaTrashAlt } from 'react-icons/fa';
|
||||
|
||||
import { mySpring } from './animations';
|
||||
import useUserSettings from './hooks/useUserSettings';
|
||||
import { useSegColors } from './contexts';
|
||||
|
||||
|
||||
const TimelineSeg = memo(({
|
||||
duration, cutStart, cutEnd, isActive, segNum, name,
|
||||
onSegClick, invertCutSegments, segColor, formatTimecode, selected,
|
||||
seg, duration, isActive, segNum, onSegClick, invertCutSegments, formatTimecode, selected,
|
||||
}) => {
|
||||
const { darkMode } = useUserSettings();
|
||||
const { getSegColor } = useSegColors();
|
||||
|
||||
const segColor = useMemo(() => getSegColor(seg), [getSegColor, seg]);
|
||||
|
||||
const { name, start: cutStart, end: cutEnd } = seg;
|
||||
|
||||
const cutSectionWidth = `${((cutEnd - cutStart) / duration) * 100}%`;
|
||||
|
||||
@ -18,13 +23,13 @@ const TimelineSeg = memo(({
|
||||
|
||||
const markerBorder = useMemo(() => {
|
||||
if (!isActive) return '2px solid transparent';
|
||||
return `2px solid ${(darkMode ? segColor.desaturate(0.6).lightness(70) : segColor.desaturate(0.9).lightness(20)).string()}`;
|
||||
return `2px solid ${darkMode ? segColor.desaturate(0.1).lightness(70).string() : segColor.desaturate(0.2).lightness(40).string()}`;
|
||||
}, [darkMode, isActive, segColor]);
|
||||
|
||||
const backgroundColor = useMemo(() => {
|
||||
if (invertCutSegments || !selected) return darkMode ? segColor.desaturate(0.9).lightness(25).string() : segColor.desaturate(0.9).lightness(80).string();
|
||||
if (isActive) return darkMode ? segColor.desaturate(0.7).lightness(50).string() : segColor.desaturate(0.7).lightness(40).string();
|
||||
return darkMode ? segColor.desaturate(0.7).lightness(40).string() : segColor.desaturate(0.9).lightness(55).string();
|
||||
if (invertCutSegments || !selected) return darkMode ? segColor.desaturate(0.4).lightness(25).string() : segColor.desaturate(0.4).lightness(83).string();
|
||||
if (isActive) return darkMode ? segColor.desaturate(0.2).lightness(50).string() : segColor.desaturate(0.2).lightness(60).string();
|
||||
return darkMode ? segColor.desaturate(0.2).lightness(40).string() : segColor.desaturate(0.5).lightness(65).string();
|
||||
}, [darkMode, invertCutSegments, isActive, segColor, selected]);
|
||||
const markerBorderRadius = 5;
|
||||
|
||||
|
@ -1,15 +1,16 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { getSegColor } from '../util/colors';
|
||||
import { useSegColors } from '../contexts';
|
||||
import useUserSettings from '../hooks/useUserSettings';
|
||||
|
||||
const SegmentCutpointButton = ({ currentCutSeg, side, Icon, onClick, title, style }) => {
|
||||
const { darkMode } = useUserSettings();
|
||||
const segColor = getSegColor(currentCutSeg);
|
||||
const { getSegColor } = useSegColors();
|
||||
const segColor = useMemo(() => getSegColor(currentCutSeg), [currentCutSeg, getSegColor]);
|
||||
|
||||
const start = side === 'start';
|
||||
const border = `3px solid ${segColor.desaturate(0.9).lightness(darkMode ? 45 : 35).string()}`;
|
||||
const backgroundColor = segColor.desaturate(0.9).lightness(darkMode ? 35 : 55).string();
|
||||
const border = `3px solid ${segColor.desaturate(0.6).lightness(darkMode ? 45 : 35).string()}`;
|
||||
const backgroundColor = segColor.desaturate(0.6).lightness(darkMode ? 35 : 55).string();
|
||||
|
||||
return (
|
||||
<Icon
|
||||
|
@ -38,7 +38,7 @@ const Settings = memo(({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { customOutDir, changeOutDir, keyframeCut, toggleKeyframeCut, timecodeFormat, setTimecodeFormat, invertCutSegments, setInvertCutSegments, askBeforeClose, setAskBeforeClose, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction, autoSaveProjectFile, setAutoSaveProjectFile, invertTimelineScroll, setInvertTimelineScroll, language, setLanguage, ffmpegExperimental, setFfmpegExperimental, hideNotifications, setHideNotifications, autoLoadTimecode, setAutoLoadTimecode, enableTransferTimestamps, setEnableTransferTimestamps, enableAutoHtml5ify, setEnableAutoHtml5ify, customFfPath, setCustomFfPath, storeProjectInWorkingDir, enableOverwriteOutput, setEnableOverwriteOutput, mouseWheelZoomModifierKey, setMouseWheelZoomModifierKey, captureFrameMethod, setCaptureFrameMethod, captureFrameQuality, setCaptureFrameQuality, captureFrameFileNameFormat, setCaptureFrameFileNameFormat, enableNativeHevc, setEnableNativeHevc, enableUpdateCheck, setEnableUpdateCheck, allowMultipleInstances, setAllowMultipleInstances } = useUserSettings();
|
||||
const { customOutDir, changeOutDir, keyframeCut, toggleKeyframeCut, timecodeFormat, setTimecodeFormat, invertCutSegments, setInvertCutSegments, askBeforeClose, setAskBeforeClose, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction, autoSaveProjectFile, setAutoSaveProjectFile, invertTimelineScroll, setInvertTimelineScroll, language, setLanguage, ffmpegExperimental, setFfmpegExperimental, hideNotifications, setHideNotifications, autoLoadTimecode, setAutoLoadTimecode, enableTransferTimestamps, setEnableTransferTimestamps, enableAutoHtml5ify, setEnableAutoHtml5ify, customFfPath, setCustomFfPath, storeProjectInWorkingDir, enableOverwriteOutput, setEnableOverwriteOutput, mouseWheelZoomModifierKey, setMouseWheelZoomModifierKey, captureFrameMethod, setCaptureFrameMethod, captureFrameQuality, setCaptureFrameQuality, captureFrameFileNameFormat, setCaptureFrameFileNameFormat, enableNativeHevc, setEnableNativeHevc, enableUpdateCheck, setEnableUpdateCheck, allowMultipleInstances, setAllowMultipleInstances, preferStrongColors, setPreferStrongColors } = useUserSettings();
|
||||
|
||||
const onLangChange = useCallback((e) => {
|
||||
const { value } = e.target;
|
||||
@ -311,6 +311,15 @@ const Settings = memo(({
|
||||
</td>
|
||||
</Row>
|
||||
|
||||
<Header title={t('User interface')} />
|
||||
|
||||
<Row>
|
||||
<KeyCell>{t('Prefer strong colors')}</KeyCell>
|
||||
<td>
|
||||
<Switch checked={preferStrongColors} onCheckedChange={setPreferStrongColors} />
|
||||
</td>
|
||||
</Row>
|
||||
|
||||
<Header title={t('Advanced options')} />
|
||||
|
||||
{!isMasBuild && (
|
||||
|
6
src/contexts.js
Normal file
6
src/contexts.js
Normal file
@ -0,0 +1,6 @@
|
||||
import React, { useContext } from 'react';
|
||||
|
||||
export const UserSettingsContext = React.createContext();
|
||||
export const SegColorsContext = React.createContext();
|
||||
|
||||
export const useSegColors = () => useContext(SegColorsContext);
|
@ -1,3 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
export default React.createContext();
|
@ -1,5 +1,5 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import UserSettingsContext from '../contexts/UserSettingsContext';
|
||||
import { UserSettingsContext } from '../contexts';
|
||||
|
||||
export default () => useContext(UserSettingsContext);
|
||||
|
@ -135,6 +135,8 @@ export default () => {
|
||||
useEffect(() => safeSetConfig({ allowMultipleInstances }), [allowMultipleInstances]);
|
||||
const [darkMode, setDarkMode] = useState(safeGetConfigInitial('darkMode'));
|
||||
useEffect(() => safeSetConfig({ darkMode }), [darkMode]);
|
||||
const [preferStrongColors, setPreferStrongColors] = useState(safeGetConfigInitial('preferStrongColors'));
|
||||
useEffect(() => safeSetConfig({ preferStrongColors }), [preferStrongColors]);
|
||||
|
||||
|
||||
const resetKeyBindings = useCallback(() => {
|
||||
@ -248,5 +250,7 @@ export default () => {
|
||||
setAllowMultipleInstances,
|
||||
darkMode,
|
||||
setDarkMode,
|
||||
preferStrongColors,
|
||||
setPreferStrongColors,
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user