Skip to content
This repository has been archived by the owner on Jun 16, 2022. It is now read-only.

add experimental feature in settings #861

Merged
merged 1 commit into from Apr 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 0 additions & 5 deletions src/actions/settings.js
Expand Up @@ -59,11 +59,6 @@ export const setReportErrors = (reportErrorsEnabled: boolean) => ({
reportErrorsEnabled,
});

export const setDeveloperMode = (developerModeEnabled: boolean) => ({
type: "SETTINGS_SET_DEVELOPER_MODE",
developerModeEnabled,
});

export const setAnalytics = (analyticsEnabled: boolean) => ({
type: "SETTINGS_SET_ANALYTICS",
analyticsEnabled,
Expand Down
104 changes: 104 additions & 0 deletions src/experimental.js
@@ -0,0 +1,104 @@
// @flow
import Config from "react-native-config";
import { AsyncStorage } from "react-native";
import { concatMap } from "rxjs/operators";
import {
setEnvUnsafe,
isEnvDefault,
changes,
} from "@ledgerhq/live-common/lib/env";
import type { EnvName } from "@ledgerhq/live-common/lib/env";

import logger from "./logger";

export type FeatureCommon = {
name: EnvName,
title: string,
description: string,
shadow?: boolean,
};

export type FeatureToggle = {
type: "toggle",
valueOn?: any,
valueOff?: any,
};

export type Feature = FeatureCommon & FeatureToggle;

export const experimentalFeatures: Feature[] = [
{
type: "toggle",
name: "MANAGER_DEV_MODE",
title: "Dev mode",
description: "enables developer apps in manager",
},
{
shadow: true,
type: "toggle",
name: "EXPERIMENTAL_EXPLORERS",
title: "Experimental explorers",
description: "switch to the new version of explorers",
},
{
shadow: true,
type: "toggle",
name: "FORCE_PROVIDER",
valueOn: 4,
valueOff: 1,
title: "Manager test app provider=4",
description: "enables yet `unreleased` apps in manager",
},
];

const storageKey = "experimentalFlags";

export const getStorageEnv = async () => {
try {
const maybeData = await AsyncStorage.getItem(storageKey);
return maybeData ? JSON.parse(maybeData) : {};
} catch (error) {
logger.critical(error);
return {};
}
};

export const setStorageEnvs = async (key: EnvName, val: string) => {
try {
const envs = await getStorageEnv();
envs[key] = val;
await AsyncStorage.setItem(storageKey, JSON.stringify(envs));
} catch (error) {
logger.critical(error);
}
};

export const isReadOnly = (key: EnvName) => key in Config;

export const enabledExperimentalFeatures = (): string[] =>
// $FlowFixMe
experimentalFeatures.map(e => e.name).filter(k => isEnvDefault(k));

(async () => {
const envs = await getStorageEnv();

/* eslint-disable guard-for-in */
for (const k in envs) {
setEnvUnsafe(k, envs[k]);
}

for (const k in Config) {
setEnvUnsafe(k, Config[k]);
}
/* eslint-enable guard-for-in */

const saveEnvs = async (name, value) => {
if (experimentalFeatures.find(f => f.name === name) && !isReadOnly(name)) {
await setStorageEnvs(name, value);
valpinkman marked this conversation as resolved.
Show resolved Hide resolved
}
};

changes
.pipe(concatMap(({ name, value }) => saveEnvs(name, value)))
.subscribe();
})();
18 changes: 18 additions & 0 deletions src/icons/Atom.js
@@ -0,0 +1,18 @@
// @flow

import React from "react";
import Svg, { Path } from "react-native-svg";

type Props = {
size: number,
color: string,
};

export default ({ size = 16, color }: Props) => (
<Svg viewBox="0 0 16 16" height={size} width={size}>
<Path
fill={color}
d="M15.246.803c-.954-.95-2.618-1.02-4.695-.195-.827.33-1.689.81-2.551 1.375C7.138 1.418 6.276.938 5.449.608 3.377-.217 1.71-.15.754.803-.615 2.166-.058 5.007 1.926 8.018-.058 11.028-.615 13.87.754 15.233c.513.51 1.231.767 2.108.767.754 0 1.627-.19 2.587-.572.827-.33 1.689-.81 2.551-1.375.862.565 1.724 1.045 2.551 1.375.96.382 1.832.572 2.588.572.876 0 1.594-.256 2.107-.767 1.369-1.363.812-4.204-1.172-7.215 1.984-3.01 2.541-5.852 1.172-7.215zm-4.268.864c1.597-.636 2.857-.656 3.459-.058.82.816.46 2.934-1.07 5.401a22.166 22.166 0 0 0-2.03-2.315A22.114 22.114 0 0 0 9.01 2.697c.667-.411 1.33-.776 1.969-1.03zm-9.414-.058c.291-.29.737-.434 1.3-.434.601 0 1.335.164 2.159.492.638.254 1.301.618 1.969 1.03a22.186 22.186 0 0 0-2.329 1.998 22.166 22.166 0 0 0-2.03 2.315c-1.53-2.467-1.89-4.585-1.07-5.4zm3.458 12.76c-1.595.636-2.855.657-3.459.057-.82-.815-.46-2.933 1.07-5.4a22.166 22.166 0 0 0 2.03 2.314c.75.747 1.536 1.403 2.328 1.999-.667.411-1.33.776-1.969 1.03zm.45-3.835a20.63 20.63 0 0 1-2.157-2.516A20.87 20.87 0 0 1 8 3.36a20.897 20.897 0 0 1 4.685 4.658A20.87 20.87 0 0 1 8 12.676a20.93 20.93 0 0 1-2.527-2.142zm8.964 3.892c-.602.6-1.862.58-3.459-.057-.638-.254-1.301-.619-1.969-1.03a22.186 22.186 0 0 0 2.329-1.999 22.166 22.166 0 0 0 2.03-2.315c1.53 2.468 1.89 4.586 1.07 5.401zM8 6.022a2.002 2.002 0 0 0-2.005 1.996c0 1.1.9 1.995 2.005 1.995a2.002 2.002 0 0 0 2.005-1.995c0-1.1-.9-1.996-2.005-1.996zm0 2.851a.857.857 0 0 1-.859-.855c0-.473.385-.855.859-.855.475 0 .859.382.859.855A.857.857 0 0 1 8 8.873z"
/>
</Svg>
);
1 change: 1 addition & 0 deletions src/live-common-setup.js
Expand Up @@ -14,6 +14,7 @@ import { logsObservable } from "@ledgerhq/react-native-hw-transport-ble/lib/debu
import BluetoothTransport from "./react-native-hw-transport-ble";

import network from "./api/network";
import "./experimental";

if (Config.DEBUG_SOCKET) {
logs.subscribe(e => {
Expand Down
5 changes: 5 additions & 0 deletions src/locales/en/common.json
Expand Up @@ -750,6 +750,11 @@
"hardResetDesc": "Erase all Ledger Live data stored on your phone, including accounts and settings.",
"repairDevice": "Repair your Ledger device",
"repairDeviceDesc": "If you encountered some issue while updating your device and cannot resume the update process, you can try this option to repair your device"
},
"experimental": {
"title": "Experimental features",
"desc": "Try out experimental features and let us know what you think",
"disclaimer": "These are experimental features we provide on an “as is” basis for our community to test. They may change, break or be removed at any time. By enabling them, you agree to use them at your own risk. Your crypto assets remain secured by your Ledger hardware wallet."
}
},
"transfer": {
Expand Down
47 changes: 47 additions & 0 deletions src/logic/withEnv.js
@@ -0,0 +1,47 @@
// @flow
import React from "react";
import { changes, getAllEnvs } from "@ledgerhq/live-common/lib/env";
import type { EnvName } from "@ledgerhq/live-common/lib/env";
import hoistNonReactStatics from "hoist-non-react-statics";

const withEnv = (name: EnvName, propName: string = "env") => (Comp: any) => {
class WithEnv extends React.Component<*, { env: any }> {
state = {
env: getAllEnvs()[name],
};

sub: *;

componentDidMount() {
this.subscribe();
}

componentWillUnmount() {
if (this.sub) {
this.sub.unsubscribe();
}
}

subscribe = () => {
this.sub = changes.subscribe(({ name: envName, value }) => {
if (envName === name) {
this.setState({ env: value });
}
});
};

render() {
const { env } = this.state;
const envProps = {
[propName]: env,
};
return <Comp {...this.props} {...envProps} />;
}
}

hoistNonReactStatics(WithEnv, Comp);

return WithEnv;
};

export default withEnv;
42 changes: 42 additions & 0 deletions src/logic/withEnvs.js
@@ -0,0 +1,42 @@
// @flow
import React from "react";
import { changes, getAllEnvs } from "@ledgerhq/live-common/lib/env";
import hoistNonReactStatics from "hoist-non-react-statics";

const withEnvs = (Comp: any) => {
class WithEnvs extends React.Component<*, { envs: { [string]: any } }> {
state = {
envs: getAllEnvs(),
};

sub: *;

componentDidMount() {
this.subscribe();
}

componentWillUnmount() {
if (this.sub) {
this.sub.unsubscribe();
}
}

subscribe = () => {
this.sub = changes.subscribe(() => {
const envs = getAllEnvs();
this.setState({ envs });
});
};

render() {
const { envs } = this.state;
return <Comp {...this.props} envs={envs} />;
}
}

hoistNonReactStatics(WithEnvs, Comp);

return WithEnvs;
};

export default withEnvs;
11 changes: 2 additions & 9 deletions src/navigators.js
Expand Up @@ -41,6 +41,7 @@ import ConfirmPassword from "./screens/Settings/General/ConfirmPassword";
import GeneralSettings from "./screens/Settings/General";
import AboutSettings from "./screens/Settings/About";
import HelpSettings from "./screens/Settings/Help";
import ExperimentalSettings from "./screens/Settings/Experimental";
import DebugSettings, {
DebugDevices,
DebugMocks,
Expand Down Expand Up @@ -123,27 +124,19 @@ const SettingsStack = createStackNavigator(
CurrenciesList,
CurrencySettings,
RepairDevice,
// $FlowFixMe
ExperimentalSettings,
DebugSettings,
// $FlowFixMe
DebugDevices,
DebugMocks,
DebugBLE,
// $FlowFixMe
DebugBLEBenchmark,
// $FlowFixMe
DebugCrash,
DebugStore,
DebugHttpTransport,
// $FlowFixMe
DebugIcons,
// $FlowFixMe
DebugLottie,
// $FlowFixMe
DebugSVG,
// $FlowFixMe
DebugWSImport,
// $FlowFixMe
BenchmarkQRStream,
},
stackNavigatorConfig,
Expand Down
15 changes: 0 additions & 15 deletions src/reducers/settings.js
Expand Up @@ -54,7 +54,6 @@ export type SettingsState = {
hasCompletedOnboarding: boolean,
hasAcceptedTradingWarning: boolean,
hasInstalledAnyApp: boolean,
developerModeEnabled: boolean,
readOnlyModeEnabled: boolean,
experimentalUSBEnabled: boolean,
countervalueFirst: boolean,
Expand All @@ -65,7 +64,6 @@ const INITIAL_STATE: SettingsState = {
counterValueExchange: null,
privacy: null,
reportErrorsEnabled: true,
developerModeEnabled: false,
analyticsEnabled: true,
currenciesSettings: {},
selectedTimeRange: "month",
Expand Down Expand Up @@ -132,14 +130,6 @@ const handlers: Object = {
reportErrorsEnabled,
}),

SETTINGS_SET_DEVELOPER_MODE: (
state: SettingsState,
{ developerModeEnabled },
) => ({
...state,
developerModeEnabled,
}),

SETTINGS_SET_ANALYTICS: (state: SettingsState, { analyticsEnabled }) => ({
...state,
analyticsEnabled,
Expand Down Expand Up @@ -273,11 +263,6 @@ export const reportErrorsEnabledSelector = createSelector(
s => s.reportErrorsEnabled,
);

export const developerModeEnabledSelector = createSelector(
storeSelector,
s => s.developerModeEnabled,
);

export const analyticsEnabledSelector = createSelector(
storeSelector,
s => s.analyticsEnabled,
Expand Down
22 changes: 11 additions & 11 deletions src/screens/AddAccounts/01-SelectCrypto.js
Expand Up @@ -4,12 +4,11 @@ import React, { Component } from "react";
import { translate, Trans } from "react-i18next";
import { StyleSheet, View } from "react-native";
import { SafeAreaView, FlatList } from "react-navigation";
import i18next from "i18next";
import { compose } from "redux";
import type { NavigationScreenProp } from "react-navigation";
import type { CryptoCurrency } from "@ledgerhq/live-common/lib/types";
import { createStructuredSelector } from "reselect";
import i18next from "i18next";

import { connect } from "react-redux";
import { listCryptoCurrencies } from "../../cryptocurrencies";
import { TrackScreen } from "../../analytics";
import FilteredSearchBar from "../../components/FilteredSearchBar";
Expand All @@ -19,21 +18,17 @@ import CurrencyRow from "../../components/CurrencyRow";
import LText from "../../components/LText";

import colors from "../../colors";
import { developerModeEnabledSelector } from "../../reducers/settings";
import withEnv from "../../logic/withEnv";

const SEARCH_KEYS = ["name", "ticker"];

type Props = {
developerModeEnabled: boolean,
devMode: boolean,
navigation: NavigationScreenProp<{
params: {},
}>,
};

const mapStateToProps = createStructuredSelector({
developerModeEnabled: developerModeEnabledSelector,
});

type State = {};

class AddAccountsSelectCrypto extends Component<Props, State> {
Expand All @@ -49,7 +44,7 @@ class AddAccountsSelectCrypto extends Component<Props, State> {
),
};

cryptocurrencies = listCryptoCurrencies(this.props.developerModeEnabled);
cryptocurrencies = listCryptoCurrencies(this.props.devMode);

keyExtractor = currency => currency.id;

Expand Down Expand Up @@ -123,4 +118,9 @@ const styles = StyleSheet.create({
},
});

export default connect(mapStateToProps)(translate()(AddAccountsSelectCrypto));
const enhancer = compose(
translate(),
withEnv("MANAGER_DEV_MODE", "devMode"),
);

export default enhancer(AddAccountsSelectCrypto);