Choose times for Automatic Dark Mode #2747
7 changed files with 138 additions and 46 deletions
|
@ -47,35 +47,31 @@ export class FormFieldPrice extends React.PureComponent<Props> {
|
|||
|
||||
return (
|
||||
<fieldset-group class="fieldset-group--smushed">
|
||||
<fieldset-section>
|
||||
<FormField
|
||||
name={`${name}_amount`}
|
||||
label={__('Price')}
|
||||
type="number"
|
||||
className="form-field--price-amount"
|
||||
min={min}
|
||||
value={price.amount}
|
||||
onChange={this.handleAmountChange}
|
||||
placeholder={placeholder || 5}
|
||||
disabled={disabled}
|
||||
step={step || 'any'}
|
||||
/>
|
||||
</fieldset-section>
|
||||
<fieldset-section>
|
||||
<FormField
|
||||
label={__('Currency')}
|
||||
name={`${name}_currency`}
|
||||
type="select"
|
||||
id={`${name}_currency`}
|
||||
className="input--currency-select"
|
||||
disabled={disabled}
|
||||
onChange={this.handleCurrencyChange}
|
||||
value={price.currency}
|
||||
>
|
||||
<option value="LBC">{__('LBRY Credits (LBC)')}</option>
|
||||
<option value="USD">{__('US Dollars')}</option>
|
||||
</FormField>
|
||||
</fieldset-section>
|
||||
<FormField
|
||||
name={`${name}_amount`}
|
||||
label={__('Price')}
|
||||
type="number"
|
||||
className="form-field--price-amount"
|
||||
min={min}
|
||||
value={price.amount}
|
||||
onChange={this.handleAmountChange}
|
||||
placeholder={placeholder || 5}
|
||||
disabled={disabled}
|
||||
step={step || 'any'}
|
||||
/>
|
||||
<FormField
|
||||
label={__('Currency')}
|
||||
name={`${name}_currency`}
|
||||
type="select"
|
||||
id={`${name}_currency`}
|
||||
className="input--currency-select"
|
||||
disabled={disabled}
|
||||
onChange={this.handleCurrencyChange}
|
||||
value={price.currency}
|
||||
>
|
||||
<option value="LBC">{__('LBRY Credits (LBC)')}</option>
|
||||
<option value="USD">{__('US Dollars')}</option>
|
||||
</FormField>
|
||||
</fieldset-group>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -20,3 +20,4 @@ export const SUPPORT_OPTION = 'supportOption';
|
|||
export const HIDE_BALANCE = 'hideBalance';
|
||||
export const HIDE_SPLASH_ANIMATION = 'hideSplashAnimation';
|
||||
export const FLOATING_PLAYER = 'floatingPlayer';
|
||||
export const DARK_MODE_TIMES = 'darkModeTimes';
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
import { connect } from 'react-redux';
|
||||
import * as settings from 'constants/settings';
|
||||
import { doClearCache, doNotifyEncryptWallet, doNotifyDecryptWallet } from 'redux/actions/app';
|
||||
import { doSetDaemonSetting, doSetClientSetting, doGetThemes, doChangeLanguage } from 'redux/actions/settings';
|
||||
import {
|
||||
doSetDaemonSetting,
|
||||
doSetClientSetting,
|
||||
doGetThemes,
|
||||
doChangeLanguage,
|
||||
doSetDarkTime,
|
||||
} from 'redux/actions/settings';
|
||||
import { doSetPlayingUri } from 'redux/actions/content';
|
||||
import {
|
||||
makeSelectClientSetting,
|
||||
|
@ -30,6 +36,7 @@ const select = state => ({
|
|||
userBlockedChannelsCount: selectBlockedChannelsCount(state),
|
||||
hideBalance: makeSelectClientSetting(settings.HIDE_BALANCE)(state),
|
||||
floatingPlayer: makeSelectClientSetting(settings.FLOATING_PLAYER)(state),
|
||||
darkModeTimes: makeSelectClientSetting(settings.DARK_MODE_TIMES)(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
@ -42,6 +49,7 @@ const perform = dispatch => ({
|
|||
decryptWallet: () => dispatch(doNotifyDecryptWallet()),
|
||||
updateWalletStatus: () => dispatch(doWalletStatus()),
|
||||
clearPlayingUri: () => dispatch(doSetPlayingUri(null)),
|
||||
setDarkTime: (time, options) => dispatch(doSetDarkTime(time, options)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
|
|
|
@ -16,6 +16,16 @@ type Price = {
|
|||
|
||||
type SetDaemonSettingArg = boolean | string | number | Price;
|
||||
|
||||
type DarkModeTimes = {
|
||||
from: { hour: string, min: string, formattedTime: string },
|
||||
to: { hour: string, min: string, formattedTime: string },
|
||||
};
|
||||
|
||||
type OptionTimes = {
|
||||
fromTo: string,
|
||||
time: string,
|
||||
};
|
||||
|
||||
type DaemonSettings = {
|
||||
download_dir: string,
|
||||
share_usage_data: boolean,
|
||||
|
@ -52,6 +62,8 @@ type Props = {
|
|||
hideBalance: boolean,
|
||||
floatingPlayer: boolean,
|
||||
clearPlayingUri: () => void,
|
||||
darkModeTimes: DarkModeTimes,
|
||||
setDarkTime: (string, {}) => void,
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
@ -74,6 +86,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
|||
(this: any).onAutomaticDarkModeChange = this.onAutomaticDarkModeChange.bind(this);
|
||||
(this: any).onLanguageChange = this.onLanguageChange.bind(this);
|
||||
(this: any).clearCache = this.clearCache.bind(this);
|
||||
(this: any).onChangeTime = this.onChangeTime.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -130,6 +143,20 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
onChangeTime(event: SyntheticInputEvent<*>, options: OptionTimes) {
|
||||
const { value } = event.target;
|
||||
|
||||
this.props.setDarkTime(value, options);
|
||||
}
|
||||
|
||||
to12Hour(time: string) {
|
||||
const now = new Date(0, 0, 0, Number(time));
|
||||
|
||||
const hour = now.toLocaleTimeString('en-US', { hour12: true, hour: '2-digit' });
|
||||
|
||||
return hour;
|
||||
}
|
||||
|
||||
setDaemonSetting(name: string, value: ?SetDaemonSettingArg): void {
|
||||
this.props.setDaemonSetting(name, value);
|
||||
}
|
||||
|
@ -169,6 +196,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
|||
userBlockedChannelsCount,
|
||||
floatingPlayer,
|
||||
clearPlayingUri,
|
||||
darkModeTimes,
|
||||
} = this.props;
|
||||
|
||||
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
|
||||
|
@ -177,6 +205,8 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
|||
|
||||
const disableMaxKeyFee = !(daemonSettings && daemonSettings.max_key_fee);
|
||||
const connectionOptions = [1, 2, 4, 6, 10, 20];
|
||||
const startHours = ['18', '19', '20', '21'];
|
||||
const endHours = ['5', '6', '7', '8'];
|
||||
|
||||
return (
|
||||
<Page>
|
||||
|
@ -420,8 +450,38 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
|||
name="automatic_dark_mode"
|
||||
onChange={() => this.onAutomaticDarkModeChange(!automaticDarkModeEnabled)}
|
||||
checked={automaticDarkModeEnabled}
|
||||
label={__('Automatic dark mode (9pm to 8am)')}
|
||||
label={__('Automatic dark mode')}
|
||||
/>
|
||||
{automaticDarkModeEnabled && (
|
||||
<fieldset-group class="fieldset-group--smushed">
|
||||
<FormField
|
||||
type="select"
|
||||
name="automatic_dark_mode_range"
|
||||
onChange={value => this.onChangeTime(value, { fromTo: 'from', time: 'hour' })}
|
||||
value={darkModeTimes.from.hour}
|
||||
label={__('From')}
|
||||
>
|
||||
{startHours.map(time => (
|
||||
<option key={time} value={time}>
|
||||
{this.to12Hour(time)}
|
||||
</option>
|
||||
))}
|
||||
</FormField>
|
||||
<FormField
|
||||
type="select"
|
||||
name="automatic_dark_mode_range"
|
||||
label={__('To')}
|
||||
onChange={value => this.onChangeTime(value, { fromTo: 'to', time: 'hour' })}
|
||||
value={darkModeTimes.to.hour}
|
||||
>
|
||||
{endHours.map(time => (
|
||||
<option key={time} value={time}>
|
||||
{this.to12Hour(time)}
|
||||
</option>
|
||||
))}
|
||||
</FormField>
|
||||
</fieldset-group>
|
||||
)}
|
||||
</fieldset-section>
|
||||
</Form>
|
||||
</section>
|
||||
|
|
|
@ -3,11 +3,11 @@ import fs from 'fs';
|
|||
import http from 'http';
|
||||
// @endif
|
||||
import { Lbry, ACTIONS, SETTINGS } from 'lbry-redux';
|
||||
import * as DESKTOP_SETTINGS from 'constants/settings';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import moment from 'moment';
|
||||
import analytics from 'analytics';
|
||||
|
||||
const UPDATE_IS_NIGHT_INTERVAL = 10 * 60 * 1000;
|
||||
const UPDATE_IS_NIGHT_INTERVAL = 5 * 60 * 1000;
|
||||
|
||||
export function doFetchDaemonSettings() {
|
||||
return dispatch => {
|
||||
|
@ -60,16 +60,8 @@ export function doGetThemes() {
|
|||
}
|
||||
|
||||
export function doUpdateIsNight() {
|
||||
const momentNow = moment();
|
||||
return {
|
||||
type: ACTIONS.UPDATE_IS_NIGHT,
|
||||
data: {
|
||||
isNight: (() => {
|
||||
const startNightMoment = moment('21:00', 'HH:mm');
|
||||
const endNightMoment = moment('8:00', 'HH:mm');
|
||||
return !(momentNow.isAfter(endNightMoment) && momentNow.isBefore(startNightMoment));
|
||||
})(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -147,3 +139,25 @@ export function doChangeLanguage(language) {
|
|||
i18n.setLocale(language);
|
||||
};
|
||||
}
|
||||
|
||||
export function doSetDarkTime(value, options) {
|
||||
const { fromTo, time } = options;
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const { darkModeTimes } = state.settings.clientSettings;
|
||||
const { hour, min } = darkModeTimes[fromTo];
|
||||
const newHour = time === 'hour' ? value : hour;
|
||||
const newMin = time === 'min' ? value : min;
|
||||
const modifiedTimes = {
|
||||
[fromTo]: {
|
||||
hour: newHour,
|
||||
min: newMin,
|
||||
formattedTime: newHour + ':' + newMin,
|
||||
},
|
||||
};
|
||||
const mergedTimes = { ...darkModeTimes, ...modifiedTimes };
|
||||
|
||||
dispatch(doSetClientSetting(DESKTOP_SETTINGS.DARK_MODE_TIMES, mergedTimes));
|
||||
dispatch(doUpdateIsNight());
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
import LANGUAGES from 'constants/languages';
|
||||
import * as SETTINGS from 'constants/settings';
|
||||
import moment from 'moment';
|
||||
|
||||
function getLocalStorageSetting(setting, fallback) {
|
||||
const localStorageVal = localStorage.getItem(`setting_${setting}`);
|
||||
|
@ -32,6 +33,10 @@ const defaultState = {
|
|||
[SETTINGS.HIDE_BALANCE]: Boolean(getLocalStorageSetting(SETTINGS.HIDE_BALANCE, false)),
|
||||
[SETTINGS.HIDE_SPLASH_ANIMATION]: Boolean(getLocalStorageSetting(SETTINGS.HIDE_SPLASH_ANIMATION, false)),
|
||||
[SETTINGS.FLOATING_PLAYER]: Boolean(getLocalStorageSetting(SETTINGS.FLOATING_PLAYER, true)),
|
||||
[SETTINGS.DARK_MODE_TIMES]: getLocalStorageSetting(SETTINGS.DARK_MODE_TIMES, {
|
||||
from: { hour: '21', min: '00', formattedTime: '21:00' },
|
||||
to: { hour: '8', min: '00', formattedTime: '8:00' },
|
||||
}),
|
||||
},
|
||||
isNight: false,
|
||||
languages: { en: 'English', pl: 'Polish', id: 'Bahasa Indonesia' }, // temporarily hard code these so we can advance i18n testing
|
||||
|
@ -59,10 +64,17 @@ reducers[ACTIONS.CLIENT_SETTING_CHANGED] = (state, action) => {
|
|||
});
|
||||
};
|
||||
|
||||
reducers[ACTIONS.UPDATE_IS_NIGHT] = (state, action) =>
|
||||
Object.assign({}, state, {
|
||||
isNight: action.data.isNight,
|
||||
reducers[ACTIONS.UPDATE_IS_NIGHT] = state => {
|
||||
const { from, to } = state.clientSettings.darkModeTimes;
|
||||
const momentNow = moment();
|
||||
const startNightMoment = moment(from.formattedTime, 'HH:mm');
|
||||
const endNightMoment = moment(to.formattedTime, 'HH:mm');
|
||||
const isNight = !(momentNow.isAfter(endNightMoment) && momentNow.isBefore(startNightMoment));
|
||||
|
||||
return Object.assign({}, state, {
|
||||
isNight,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[ACTIONS.DOWNLOAD_LANGUAGE_SUCCEEDED] = (state, action) => {
|
||||
const languages = Object.assign({}, state.languages);
|
||||
|
|
|
@ -118,8 +118,9 @@ fieldset-group {
|
|||
width: auto;
|
||||
margin-bottom: 0;
|
||||
|
||||
&:first-of-type {
|
||||
input {
|
||||
&:first-child {
|
||||
input,
|
||||
select {
|
||||
border-right: none;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
|
|
Loading…
Reference in a new issue