privacy changes:
users see welcome screen once and choose preference SETTINGS moved to redux took steps toward eliminating unwanted analytics in app based on preferences settings page update to privacy controls and copy persist welcome version default tv on cleanup clean up appstrings populate prefs app only wallet custody, app only router settings on startup welcome sync, 3p share sync, emojis bump redux cleanup fix app not building fix sync bug, remove tvWelcomeVersion cleanup disable internalshare setting while signed in
This commit is contained in:
parent
45bbd77109
commit
6e13fcfbd3
24 changed files with 635 additions and 71 deletions
|
@ -7,6 +7,7 @@ const config = {
|
||||||
SITE_TITLE: 'lbry.tv',
|
SITE_TITLE: 'lbry.tv',
|
||||||
LBRY_TV_API: 'https://api.lbry.tv',
|
LBRY_TV_API: 'https://api.lbry.tv',
|
||||||
LBRY_TV_STREAMING_API: 'https://player.lbry.tv',
|
LBRY_TV_STREAMING_API: 'https://player.lbry.tv',
|
||||||
|
WELCOME_VERSION: 1.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
config.URL_LOCAL = `http://localhost:${config.WEB_SERVER_PORT}`;
|
config.URL_LOCAL = `http://localhost:${config.WEB_SERVER_PORT}`;
|
||||||
|
|
|
@ -131,7 +131,7 @@
|
||||||
"imagesloaded": "^4.1.4",
|
"imagesloaded": "^4.1.4",
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
||||||
"lbry-redux": "lbryio/lbry-redux#3d64f8acc6c2ce37252f59feff89e1fc58cb74c1",
|
"lbry-redux": "lbryio/lbry-redux#b4fbc212ca6008ec05c31116182bf6dfa7a1cbcb",
|
||||||
"lbryinc": "lbryio/lbryinc#6a59102c52673502569d2c43bd4ee58c315fb2e4",
|
"lbryinc": "lbryio/lbryinc#6a59102c52673502569d2c43bd4ee58c315fb2e4",
|
||||||
"lint-staged": "^7.0.2",
|
"lint-staged": "^7.0.2",
|
||||||
"localforage": "^1.7.1",
|
"localforage": "^1.7.1",
|
||||||
|
|
|
@ -963,5 +963,24 @@
|
||||||
"Find new channels to follow": "Find new channels to follow",
|
"Find new channels to follow": "Find new channels to follow",
|
||||||
"You aren't currently following any channels. %discover_channels_link%.": "You aren't currently following any channels. %discover_channels_link%.",
|
"You aren't currently following any channels. %discover_channels_link%.": "You aren't currently following any channels. %discover_channels_link%.",
|
||||||
"LBRY Works Better If You Are Following Channels": "LBRY Works Better If You Are Following Channels",
|
"LBRY Works Better If You Are Following Channels": "LBRY Works Better If You Are Following Channels",
|
||||||
"Saved zip archive to %outputPath%": "Saved zip archive to %outputPath%"
|
"Saved zip archive to %outputPath%": "Saved zip archive to %outputPath%",
|
||||||
|
"Share Usage and Diagnostic Data": "Share Usage and Diagnostic Data",
|
||||||
|
"This is information like error logging, performance tracking, and usage statistics. It includes your IP address and basic system details, but no other identifying information (unless you sign in to lbry.tv)": "This is information like error logging, performance tracking, and usage statistics. It includes your IP address and basic system details, but no other identifying information (unless you sign in to lbry.tv)",
|
||||||
|
"Allow the app to share data to LBRY.inc": "Allow the app to share data to LBRY.inc",
|
||||||
|
"Internal sharing is required to participate in rewards programs.": "Internal sharing is required to participate in rewards programs.",
|
||||||
|
"Allow the App to access third party analytics platforms": "Allow the App to access third party analytics platforms",
|
||||||
|
"We use detailed analytics to improve all aspects of the LBRY experience.": "We use detailed analytics to improve all aspects of the LBRY experience.",
|
||||||
|
"Welcome": "Welcome",
|
||||||
|
"LBRY takes privacy and choice seriously. Just a few questions before you enter the land of content freedom. ": "LBRY takes privacy and choice seriously. Just a few questions before you enter the land of content freedom. ",
|
||||||
|
"Can this app send information about your usage to inform publishers and improve the software?": "Can this app send information about your usage to inform publishers and improve the software?",
|
||||||
|
"Yes, including with third-party analytics platforms": "Yes, including with third-party analytics platforms",
|
||||||
|
"Sending information to third parties (e.g. Google Analytics or Mixpanel) allows us to use detailed\n analytical reports to improve all aspects of LBRY.": "Sending information to third parties (e.g. Google Analytics or Mixpanel) allows us to use detailed\n analytical reports to improve all aspects of LBRY.",
|
||||||
|
"Yes, but only with LBRY, Inc.": "Yes, but only with LBRY, Inc.",
|
||||||
|
"Sharing information with LBRY, Inc. allows us to report to publishers how their content is doing, as\n well as track basic usage and performance. This is the minimum required to earn rewards from LBRY, Inc.": "Sharing information with LBRY, Inc. allows us to report to publishers how their content is doing, as\n well as track basic usage and performance. This is the minimum required to earn rewards from LBRY, Inc.",
|
||||||
|
"No information will be sent directly to LBRY, Inc. or third-parties about your usage. Note that as\n peer-to-peer software, your IP address and potentially other system information can be sent to other\n users, though this information is not stored permanently.": "No information will be sent directly to LBRY, Inc. or third-parties about your usage. Note that as\n peer-to-peer software, your IP address and potentially other system information can be sent to other\n users, though this information is not stored permanently.",
|
||||||
|
"Let's go": "Let's go",
|
||||||
|
"Do you agree to the %terms%?": "Do you agree to the %terms%?",
|
||||||
|
"While we respect the desire for maximally private usage, please note that choosing this option hurts the ability for creators to understand how their content is performing.": "While we respect the desire for maximally private usage, please note that choosing this option hurts the ability for creators to understand how their content is performing.",
|
||||||
|
"A copy of your wallet is synced to lbry.tv": "A copy of your wallet is synced to lbry.tv",
|
||||||
|
"Internal sharing is required while signed in.": "Internal sharing is required while signed in."
|
||||||
}
|
}
|
||||||
|
|
210
static/img/unlocklbry.svg
Normal file
210
static/img/unlocklbry.svg
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
viewBox="0 0 757.64 896.74"
|
||||||
|
version="1.1"
|
||||||
|
id="svg62"
|
||||||
|
sodipodi:docname="unlocklbry.svg"
|
||||||
|
inkscape:version="0.92.3 (2405546, 2018-03-11)">
|
||||||
|
<metadata
|
||||||
|
id="metadata66">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title>unlock</dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1051"
|
||||||
|
id="namedview64"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="0.37218637"
|
||||||
|
inkscape:cx="97.177994"
|
||||||
|
inkscape:cy="700.34675"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg62" />
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<style
|
||||||
|
id="style2">.cls-1{fill:#f1f1f1;}.cls-2{fill:#e49d75;}.cls-3{fill:#5fc5d1;}.cls-4{fill:#6bd5e1;}.cls-5{fill:#e0e0e0;}.cls-6{fill:#a4a4a4;}.cls-7{fill:none;stroke:#e0e0e0;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px;}.cls-8{fill:#ffd98e;}.cls-9{fill:#ffe4ad;}.cls-10{fill-rule:evenodd;}</style>
|
||||||
|
</defs>
|
||||||
|
<title
|
||||||
|
id="title6">unlock</title>
|
||||||
|
<g
|
||||||
|
id="Layer_2"
|
||||||
|
data-name="Layer 2">
|
||||||
|
<g
|
||||||
|
id="vector">
|
||||||
|
<path
|
||||||
|
class="cls-1"
|
||||||
|
d="M636.5,232.73c68.06,61.33,93.17,180.88,67.33,286.61C677.81,625.07,601,717,496,778.29c-105,61.14-238,91.9-326.82,43.86S36.17,647.63,13.78,523.53c-22.2-124.11-22.56-245.67,36.58-305C109.5,159.4,228,162.31,342.79,165.22,457.62,168.31,568.62,171.41,636.5,232.73Z"
|
||||||
|
id="path8" />
|
||||||
|
<rect
|
||||||
|
class="cls-2"
|
||||||
|
x="558.8"
|
||||||
|
y="858.32"
|
||||||
|
width="22.08"
|
||||||
|
height="14.74"
|
||||||
|
id="rect10" />
|
||||||
|
<rect
|
||||||
|
class="cls-2"
|
||||||
|
x="677.14"
|
||||||
|
y="835.57"
|
||||||
|
width="20.72"
|
||||||
|
height="18.36"
|
||||||
|
transform="translate(-378.13 619.59) rotate(-38.93)"
|
||||||
|
id="rect12" />
|
||||||
|
<rect
|
||||||
|
class="cls-2"
|
||||||
|
x="586.33"
|
||||||
|
y="256.37"
|
||||||
|
width="17.47"
|
||||||
|
height="20.69"
|
||||||
|
rx="8.23"
|
||||||
|
id="rect14" />
|
||||||
|
<path
|
||||||
|
class="cls-3"
|
||||||
|
d="M602.4,567.42c3,6.88,26,144.94,29.38,158s57.45,98.2,61.13,103.29c1.13,7.36-15.57,19.81-23.49,19.81C661.5,842.26,569,708.23,566.78,702.28S557.11,553.94,602.4,567.42Z"
|
||||||
|
id="path16"
|
||||||
|
style="fill:#4b8576;fill-opacity:1" />
|
||||||
|
<path
|
||||||
|
class="cls-4"
|
||||||
|
d="M505.83,544.55c-1.05,5.7,14.58,136,16.52,153.5s31.89,158.48,34.54,162,22.81,2.76,26.29,1-6.8-147-6.8-157.53,27-107.65,23.53-135.78S505.83,544.55,505.83,544.55Z"
|
||||||
|
id="path18"
|
||||||
|
style="fill:#257761;fill-opacity:1" />
|
||||||
|
<rect
|
||||||
|
class="cls-2"
|
||||||
|
x="561.36"
|
||||||
|
y="386.6"
|
||||||
|
width="21.11"
|
||||||
|
height="36.74"
|
||||||
|
id="rect20" />
|
||||||
|
<rect
|
||||||
|
class="cls-5"
|
||||||
|
x="94.97"
|
||||||
|
y="137.85"
|
||||||
|
width="379.57"
|
||||||
|
height="379.57"
|
||||||
|
rx="22.42"
|
||||||
|
id="rect22" />
|
||||||
|
<path
|
||||||
|
class="cls-6"
|
||||||
|
d="M308.48,310.8a35.09,35.09,0,1,0-47.45,0L234,420.41H335.48Z"
|
||||||
|
id="path24" />
|
||||||
|
<path
|
||||||
|
class="cls-7"
|
||||||
|
d="M162.9,137.85a121.86,121.86,0,0,1,243.71,0"
|
||||||
|
id="path26" />
|
||||||
|
<ellipse
|
||||||
|
class="cls-2"
|
||||||
|
cx="569.19"
|
||||||
|
cy="353.64"
|
||||||
|
rx="29"
|
||||||
|
ry="39"
|
||||||
|
id="ellipse28" />
|
||||||
|
<path
|
||||||
|
class="cls-8"
|
||||||
|
d="M565.24,415.77c-35.16,0-66.5,97.54-60.48,129.91,1.78,9.56,85.92,28.85,98.78,26.15C608.11,565.61,626.76,415.77,565.24,415.77Z"
|
||||||
|
id="path30"
|
||||||
|
style="fill:#fff58c;fill-opacity:1" />
|
||||||
|
<path
|
||||||
|
class="cls-9"
|
||||||
|
d="M556.22,470.1c15.74-11.42-9.42-66.76-15.3-67.71-10.83-1.75-37.76,19-36.91,27.72C504.46,434.71,540.19,481.73,556.22,470.1Z"
|
||||||
|
id="path32"
|
||||||
|
style="fill:#fff58c;fill-opacity:1" />
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M509,426c-4.24-5.09-14.84-30-16-35.91s-4-94.74-4-100S482,271.56,482,263.64s8.06-18.66,12.16-18.8c4.38,3.11,10.46,21.35,10.74,26,1.53-10,8.77-12.3,10.75-12.3s1.72,15.45-6.48,25.85c.29,7.64,10,83.31,11.57,87.69s19.45,33.09,19.41,35.63S509,426,509,426Z"
|
||||||
|
id="path34" />
|
||||||
|
<rect
|
||||||
|
class="cls-6"
|
||||||
|
x="368.05"
|
||||||
|
y="260.35"
|
||||||
|
width="358.11"
|
||||||
|
height="10.23"
|
||||||
|
transform="translate(40.99 -71.64) rotate(7.78)"
|
||||||
|
id="rect36" />
|
||||||
|
<rect
|
||||||
|
class="cls-6"
|
||||||
|
x="366.9"
|
||||||
|
y="247.63"
|
||||||
|
width="21.9"
|
||||||
|
height="29.63"
|
||||||
|
transform="translate(39.02 -48.75) rotate(7.78)"
|
||||||
|
id="rect38" />
|
||||||
|
<rect
|
||||||
|
class="cls-6"
|
||||||
|
x="397.87"
|
||||||
|
y="251.17"
|
||||||
|
width="11.78"
|
||||||
|
height="29.63"
|
||||||
|
transform="translate(39.74 -52.22) rotate(7.78)"
|
||||||
|
id="rect40" />
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M604.74,334c-.83-4.74-1.58-39.09-.3-43.94s4.74-8.39,6.29-15.63c.53-2.49-.31-11.11-2-11.47-3.64-.78-3.85,3.3-4.33,6.3-1.86,10.23-5.65,8.36-7.4,8.12s-7.76-1.28-9.73-1.33,3.05,4,1.52,10.47c-1.2,5.09-6.84,39-8,44.55C585,331.24,604.74,334,604.74,334Z"
|
||||||
|
id="path42" />
|
||||||
|
<rect
|
||||||
|
class="cls-6"
|
||||||
|
x="417.79"
|
||||||
|
y="253.89"
|
||||||
|
width="11.78"
|
||||||
|
height="29.63"
|
||||||
|
transform="translate(40.29 -54.9) rotate(7.78)"
|
||||||
|
id="rect44" />
|
||||||
|
<rect
|
||||||
|
class="cls-6"
|
||||||
|
x="368.01"
|
||||||
|
y="250.51"
|
||||||
|
width="63.09"
|
||||||
|
height="10.5"
|
||||||
|
transform="translate(38.31 -51.75) rotate(7.78)"
|
||||||
|
id="rect46" />
|
||||||
|
<path
|
||||||
|
class="cls-6"
|
||||||
|
d="M734.69,264.08A26.54,26.54,0,1,0,757.4,294,26.54,26.54,0,0,0,734.69,264.08ZM749,292.82a18.07,18.07,0,1,1-15.45-20.35A18.07,18.07,0,0,1,749,292.82Z"
|
||||||
|
id="path48" />
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M509.28,284.31c-1.32-5.17-3.89-9.69-4.31-13.58l0,.12c-.28-4.66-6.36-22.9-10.74-26-4.1.14-12.16,10.88-12.16,18.8,0,5.81,3.8,14.5,5.82,20.79h21.35v0Z"
|
||||||
|
id="path50" />
|
||||||
|
<path
|
||||||
|
d="M543.06,329.21c0,13.49,9.52,21.81,24.61,26.45,0,18.46,2.85,19.27,2.85,30.51,0,24.22-4.13,12.11-4.13,53.93,0,25.22,10.56,38.94,30,38.94,23.51,0,37-24.87,37-38.27,0-17-16.82-46.54-18-71.07-1.63-33-11.89-60.61-37.62-60.61C555.79,309.09,543.06,317.27,543.06,329.21Z"
|
||||||
|
id="path52" />
|
||||||
|
<circle
|
||||||
|
class="cls-2"
|
||||||
|
cx="569.16"
|
||||||
|
cy="358.82"
|
||||||
|
r="7.8"
|
||||||
|
id="circle54" />
|
||||||
|
<path
|
||||||
|
class="cls-10"
|
||||||
|
d="M701.29,842.49l12.5,17.06-26.15,37-24.68.16.32-12.51,9.91-4.38L682,858.08Z"
|
||||||
|
id="path56" />
|
||||||
|
<polyline
|
||||||
|
points="582.36 871.83 582.36 896.74 509.14 896.74 509.14 885.71 557.45 871.83 582.36 871.83"
|
||||||
|
id="polyline58" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.2 KiB |
|
@ -16,6 +16,9 @@ const LBRY_TV_UA_ID = 'UA-60403362-12';
|
||||||
const DESKTOP_UA_ID = 'UA-60403362-13';
|
const DESKTOP_UA_ID = 'UA-60403362-13';
|
||||||
const SECOND_TRACKER_NAME = 'tracker2';
|
const SECOND_TRACKER_NAME = 'tracker2';
|
||||||
|
|
||||||
|
const SHARE_INTERNAL = 'shareInternal';
|
||||||
|
const SHARE_THIRD_PARTY = 'shareThirdParty';
|
||||||
|
|
||||||
// @if TARGET='app'
|
// @if TARGET='app'
|
||||||
ElectronCookies.enable({
|
ElectronCookies.enable({
|
||||||
origin: 'https://lbry.tv',
|
origin: 'https://lbry.tv',
|
||||||
|
@ -27,7 +30,8 @@ type Analytics = {
|
||||||
sentryError: ({}, {}) => Promise<any>,
|
sentryError: ({}, {}) => Promise<any>,
|
||||||
pageView: string => void,
|
pageView: string => void,
|
||||||
setUser: Object => void,
|
setUser: Object => void,
|
||||||
toggle: (boolean, ?boolean) => void,
|
toggleInternal: (boolean, ?boolean) => void,
|
||||||
|
toggleThirdParty: (boolean, ?boolean) => void,
|
||||||
apiLogView: (string, string, string, ?number, ?() => void) => Promise<any>,
|
apiLogView: (string, string, string, ?number, ?() => void) => Promise<any>,
|
||||||
apiLogPublish: (ChannelClaim | StreamClaim) => void,
|
apiLogPublish: (ChannelClaim | StreamClaim) => void,
|
||||||
tagFollowEvent: (string, boolean, string) => void,
|
tagFollowEvent: (string, boolean, string) => void,
|
||||||
|
@ -48,12 +52,17 @@ type LogPublishParams = {
|
||||||
channel_claim_id?: string,
|
channel_claim_id?: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
let analyticsEnabled: boolean = isProduction;
|
let internalAnalyticsEnabled: boolean = IS_WEB || false;
|
||||||
|
let thirdPartyAnalyticsEnabled: boolean = IS_WEB || false;
|
||||||
|
// @if TARGET='app'
|
||||||
|
if (window.localStorage.getItem(SHARE_INTERNAL) === 'true') internalAnalyticsEnabled = true;
|
||||||
|
if (window.localStorage.getItem(SHARE_THIRD_PARTY) === 'true') thirdPartyAnalyticsEnabled = true;
|
||||||
|
// @endif
|
||||||
|
|
||||||
const analytics: Analytics = {
|
const analytics: Analytics = {
|
||||||
error: message => {
|
error: message => {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (analyticsEnabled && isProduction) {
|
if (internalAnalyticsEnabled && isProduction) {
|
||||||
return Lbryio.call('event', 'desktop_error', { error_message: message }).then(() => {
|
return Lbryio.call('event', 'desktop_error', { error_message: message }).then(() => {
|
||||||
resolve(true);
|
resolve(true);
|
||||||
});
|
});
|
||||||
|
@ -64,7 +73,7 @@ const analytics: Analytics = {
|
||||||
},
|
},
|
||||||
sentryError: (error, errorInfo) => {
|
sentryError: (error, errorInfo) => {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (analyticsEnabled && isProduction) {
|
if (internalAnalyticsEnabled && isProduction) {
|
||||||
Sentry.withScope(scope => {
|
Sentry.withScope(scope => {
|
||||||
scope.setExtras(errorInfo);
|
scope.setExtras(errorInfo);
|
||||||
const eventId = Sentry.captureException(error);
|
const eventId = Sentry.captureException(error);
|
||||||
|
@ -76,12 +85,12 @@ const analytics: Analytics = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
pageView: path => {
|
pageView: path => {
|
||||||
if (analyticsEnabled) {
|
if (thirdPartyAnalyticsEnabled) {
|
||||||
ReactGA.pageview(path, [SECOND_TRACKER_NAME]);
|
ReactGA.pageview(path, [SECOND_TRACKER_NAME]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setUser: userId => {
|
setUser: userId => {
|
||||||
if (analyticsEnabled && userId) {
|
if (thirdPartyAnalyticsEnabled && userId) {
|
||||||
ReactGA.set({
|
ReactGA.set({
|
||||||
userId,
|
userId,
|
||||||
});
|
});
|
||||||
|
@ -93,15 +102,25 @@ const analytics: Analytics = {
|
||||||
// @endif
|
// @endif
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggle: (enabled: boolean): void => {
|
toggleInternal: (enabled: boolean): void => {
|
||||||
// Always collect analytics on lbry.tv
|
// Always collect analytics on lbry.tv
|
||||||
// @if TARGET='app'
|
// @if TARGET='app'
|
||||||
analyticsEnabled = enabled;
|
internalAnalyticsEnabled = enabled;
|
||||||
|
window.localStorage.setItem(SHARE_INTERNAL, enabled);
|
||||||
// @endif
|
// @endif
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toggleThirdParty: (enabled: boolean): void => {
|
||||||
|
// Always collect analytics on lbry.tv
|
||||||
|
// @if TARGET='app'
|
||||||
|
thirdPartyAnalyticsEnabled = enabled;
|
||||||
|
window.localStorage.setItem(SHARE_THIRD_PARTY, enabled);
|
||||||
|
// @endif
|
||||||
|
},
|
||||||
|
|
||||||
apiLogView: (uri, outpoint, claimId, timeToStart) => {
|
apiLogView: (uri, outpoint, claimId, timeToStart) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (analyticsEnabled && (isProduction || devInternalApis)) {
|
if (internalAnalyticsEnabled && (isProduction || devInternalApis)) {
|
||||||
const params: {
|
const params: {
|
||||||
uri: string,
|
uri: string,
|
||||||
outpoint: string,
|
outpoint: string,
|
||||||
|
@ -125,12 +144,12 @@ const analytics: Analytics = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
apiLogSearch: () => {
|
apiLogSearch: () => {
|
||||||
if (analyticsEnabled && isProduction) {
|
if (internalAnalyticsEnabled && isProduction) {
|
||||||
Lbryio.call('event', 'search');
|
Lbryio.call('event', 'search');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
apiLogPublish: (claimResult: ChannelClaim | StreamClaim) => {
|
apiLogPublish: (claimResult: ChannelClaim | StreamClaim) => {
|
||||||
if (analyticsEnabled && isProduction) {
|
if (internalAnalyticsEnabled && isProduction) {
|
||||||
const { permanent_url: uri, claim_id: claimId, txid, nout, signing_channel: signingChannel } = claimResult;
|
const { permanent_url: uri, claim_id: claimId, txid, nout, signing_channel: signingChannel } = claimResult;
|
||||||
let channelClaimId;
|
let channelClaimId;
|
||||||
if (signingChannel) {
|
if (signingChannel) {
|
||||||
|
@ -185,7 +204,7 @@ const analytics: Analytics = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function sendGaEvent(category, action, label, value) {
|
function sendGaEvent(category, action, label, value) {
|
||||||
if (analyticsEnabled && isProduction) {
|
if (thirdPartyAnalyticsEnabled && isProduction) {
|
||||||
ReactGA.event(
|
ReactGA.event(
|
||||||
{
|
{
|
||||||
category,
|
category,
|
||||||
|
@ -199,7 +218,7 @@ function sendGaEvent(category, action, label, value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendGaTimingEvent(category: string, action: string, timeInMs: number, label?: string) {
|
function sendGaTimingEvent(category: string, action: string, timeInMs: number, label?: string) {
|
||||||
if (analyticsEnabled && isProduction) {
|
if (thirdPartyAnalyticsEnabled && isProduction) {
|
||||||
ReactGA.timing(
|
ReactGA.timing(
|
||||||
{
|
{
|
||||||
category,
|
category,
|
||||||
|
|
|
@ -13,18 +13,19 @@ type Props = {
|
||||||
isUpgradeAvailable: boolean,
|
isUpgradeAvailable: boolean,
|
||||||
authPage: boolean,
|
authPage: boolean,
|
||||||
authenticated: boolean,
|
authenticated: boolean,
|
||||||
|
noHeader: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function Page(props: Props) {
|
function Page(props: Props) {
|
||||||
const { children, className, authPage = false, authenticated } = props;
|
const { children, className, authPage = false, authenticated, noHeader } = props;
|
||||||
const obscureSideNavigation = IS_WEB ? !authenticated : false;
|
const obscureSideNavigation = IS_WEB ? !authenticated : false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Header authHeader={authPage} />
|
{!noHeader && <Header authHeader={authPage} />}
|
||||||
<div className={classnames('main-wrapper__inner')}>
|
<div className={classnames('main-wrapper__inner')}>
|
||||||
<main className={classnames(MAIN_CLASS, className, { 'main--full-width': authPage })}>{children}</main>
|
<main className={classnames(MAIN_CLASS, className, { 'main--full-width': authPage })}>{children}</main>
|
||||||
{!authPage && <SideNavigation obscureSideNavigation={obscureSideNavigation} />}
|
{!authPage && !noHeader && <SideNavigation obscureSideNavigation={obscureSideNavigation} />}
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|
17
ui/component/privacyAgreement/index.js
Normal file
17
ui/component/privacyAgreement/index.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doSetDaemonSetting } from 'redux/actions/settings';
|
||||||
|
import { doSetWelcomeVersion, doToggle3PAnalytics } from 'redux/actions/app';
|
||||||
|
import PrivacyAgreement from './view';
|
||||||
|
import { DAEMON_SETTINGS } from 'lbry-redux';
|
||||||
|
import { WELCOME_VERSION } from 'config.js';
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
setWelcomeVersion: version => dispatch(doSetWelcomeVersion(version || WELCOME_VERSION)),
|
||||||
|
setShareDataInternal: share => dispatch(doSetDaemonSetting(DAEMON_SETTINGS.SHARE_USAGE_DATA, share)),
|
||||||
|
setShareDataThirdParty: share => dispatch(doToggle3PAnalytics(share)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
null,
|
||||||
|
perform
|
||||||
|
)(PrivacyAgreement);
|
148
ui/component/privacyAgreement/view.jsx
Normal file
148
ui/component/privacyAgreement/view.jsx
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
// @flow
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import I18nMessage from 'component/i18nMessage';
|
||||||
|
import { FormField } from 'component/common/form-components/form-field';
|
||||||
|
import { Form } from 'component/common/form-components/form';
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
// $FlowFixMe cannot resolve ...
|
||||||
|
import image from 'static/img/unlocklbry.svg';
|
||||||
|
|
||||||
|
const FREE = 'free';
|
||||||
|
const LIMITED = 'limited';
|
||||||
|
const NONE = 'none';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
setWelcomeVersion: () => void,
|
||||||
|
setShareDataInternal: boolean => void,
|
||||||
|
setShareDataThirdParty: boolean => void,
|
||||||
|
history: { replace: string => void },
|
||||||
|
};
|
||||||
|
|
||||||
|
function PrivacyAgreement(props: Props) {
|
||||||
|
const { setWelcomeVersion, setShareDataInternal, setShareDataThirdParty, history } = props;
|
||||||
|
const [share, setShare] = useState(undefined); // preload
|
||||||
|
const [agree, setAgree] = useState(false); // preload
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
if (share === FREE) {
|
||||||
|
setShareDataInternal(true);
|
||||||
|
setShareDataThirdParty(true);
|
||||||
|
} else if (share === LIMITED) {
|
||||||
|
setShareDataInternal(true);
|
||||||
|
setShareDataThirdParty(false);
|
||||||
|
} else {
|
||||||
|
setShareDataInternal(false);
|
||||||
|
setShareDataThirdParty(false);
|
||||||
|
}
|
||||||
|
setWelcomeVersion();
|
||||||
|
history.replace(`/`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="main--contained">
|
||||||
|
<div className={'columns'}>
|
||||||
|
<div>
|
||||||
|
<h1 className="section__title--large">{__('Welcome')}</h1>
|
||||||
|
<h3 className="section__subtitle">
|
||||||
|
{__(
|
||||||
|
`LBRY takes privacy and choice seriously. Just a few questions before you enter the land of content freedom. `
|
||||||
|
)}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<img src={image} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Form onSubmit={handleSubmit} className="section__body">
|
||||||
|
<p className="section__subtitle">
|
||||||
|
{__('Can this app send information about your usage to inform publishers and improve the software?')}
|
||||||
|
</p>
|
||||||
|
<fieldset>
|
||||||
|
<FormField
|
||||||
|
name={'shareFreely'}
|
||||||
|
type="radio"
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
<span className="emoji">😄</span> {__('Yes, including with third-party analytics platforms')}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
helper={__(`Sending information to third parties (e.g. Google Analytics or Mixpanel) allows us to use detailed
|
||||||
|
analytical reports to improve all aspects of LBRY.`)}
|
||||||
|
checked={share === FREE}
|
||||||
|
onChange={e => setShare(FREE)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
name={'shareWithLBRY'}
|
||||||
|
type="radio"
|
||||||
|
checked={share === LIMITED}
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
<span className="emoji">🙂</span> {__('Yes, but only with LBRY, Inc.')}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
helper={__(
|
||||||
|
`Sharing information with LBRY, Inc. allows us to report to publishers how their content is doing, as
|
||||||
|
well as track basic usage and performance. This is the minimum required to earn rewards from LBRY, Inc.`
|
||||||
|
)}
|
||||||
|
onChange={e => setShare(LIMITED)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
name={'shareNot'}
|
||||||
|
type="radio"
|
||||||
|
checked={share === NONE}
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
<span className="emoji">😢</span> {__('No')}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
helper={__(`No information will be sent directly to LBRY, Inc. or third-parties about your usage. Note that as
|
||||||
|
peer-to-peer software, your IP address and potentially other system information can be sent to other
|
||||||
|
users, though this information is not stored permanently.`)}
|
||||||
|
onChange={e => setShare(NONE)}
|
||||||
|
/>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<p className="section__subtitle">
|
||||||
|
<I18nMessage
|
||||||
|
tokens={{
|
||||||
|
terms: <Button button="link" href="https://www.lbry.com/termsofservice" label={__('Terms of Service')} />,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Do you agree to the %terms%?
|
||||||
|
</I18nMessage>
|
||||||
|
</p>
|
||||||
|
<fieldset>
|
||||||
|
<FormField
|
||||||
|
name={'agreeButton'}
|
||||||
|
type="radio"
|
||||||
|
label={'Yes'}
|
||||||
|
checked={agree === true}
|
||||||
|
onChange={e => setAgree(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
name={'disagreeButton'}
|
||||||
|
type="radio"
|
||||||
|
checked={agree === false}
|
||||||
|
label={__('No')}
|
||||||
|
onChange={e => setAgree(!e.target.checked)}
|
||||||
|
/>
|
||||||
|
</fieldset>
|
||||||
|
{share === NONE && (
|
||||||
|
<>
|
||||||
|
<p className="help">
|
||||||
|
{__(
|
||||||
|
'While we respect the desire for maximally private usage, please note that choosing this option hurts the ability for creators to understand how their content is performing.'
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<div className={'card__actions'}>
|
||||||
|
<Button button="primary" label={__(`Let's go`)} disabled={!share || !agree} type="submit" />
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter(PrivacyAgreement);
|
|
@ -1,6 +1,6 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectUserVerifiedEmail } from 'lbryinc';
|
import { selectUserVerifiedEmail } from 'lbryinc';
|
||||||
import { selectScrollStartingPosition } from 'redux/selectors/app';
|
import { selectScrollStartingPosition, selectWelcomeVersion } from 'redux/selectors/app';
|
||||||
import Router from './view';
|
import Router from './view';
|
||||||
import { normalizeURI, makeSelectTitleForUri } from 'lbry-redux';
|
import { normalizeURI, makeSelectTitleForUri } from 'lbry-redux';
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ const select = state => {
|
||||||
title: makeSelectTitleForUri(uri)(state),
|
title: makeSelectTitleForUri(uri)(state),
|
||||||
currentScroll: selectScrollStartingPosition(state),
|
currentScroll: selectScrollStartingPosition(state),
|
||||||
isAuthenticated: selectUserVerifiedEmail(state),
|
isAuthenticated: selectUserVerifiedEmail(state),
|
||||||
|
welcomeVersion: selectWelcomeVersion(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,8 @@ import ChannelsPage from 'page/channels';
|
||||||
import EmbedWrapperPage from 'page/embedWrapper';
|
import EmbedWrapperPage from 'page/embedWrapper';
|
||||||
import TopPage from 'page/top';
|
import TopPage from 'page/top';
|
||||||
import { parseURI } from 'lbry-redux';
|
import { parseURI } from 'lbry-redux';
|
||||||
import { SITE_TITLE } from 'config';
|
import { SITE_TITLE, WELCOME_VERSION } from 'config';
|
||||||
|
import Welcome from 'page/welcome';
|
||||||
|
|
||||||
// Tell the browser we are handling scroll restoration
|
// Tell the browser we are handling scroll restoration
|
||||||
if ('scrollRestoration' in history) {
|
if ('scrollRestoration' in history) {
|
||||||
|
@ -80,6 +81,7 @@ type Props = {
|
||||||
},
|
},
|
||||||
uri: string,
|
uri: string,
|
||||||
title: string,
|
title: string,
|
||||||
|
welcomeVersion: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
function AppRouter(props: Props) {
|
function AppRouter(props: Props) {
|
||||||
|
@ -90,6 +92,7 @@ function AppRouter(props: Props) {
|
||||||
history,
|
history,
|
||||||
uri,
|
uri,
|
||||||
title,
|
title,
|
||||||
|
welcomeVersion,
|
||||||
} = props;
|
} = props;
|
||||||
const { entries } = history;
|
const { entries } = history;
|
||||||
const entryIndex = history.index;
|
const entryIndex = history.index;
|
||||||
|
@ -133,11 +136,14 @@ function AppRouter(props: Props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
|
{/* @if TARGET='app' */}
|
||||||
|
{welcomeVersion < WELCOME_VERSION && <Route path="/*" component={Welcome} />}
|
||||||
|
{/* @endif */}
|
||||||
<Redirect from={`/$/${PAGES.CHANNELS_FOLLOWING_MANAGE}`} to={`/$/${PAGES.CHANNELS_FOLLOWING_DISCOVER}`} />
|
<Redirect from={`/$/${PAGES.CHANNELS_FOLLOWING_MANAGE}`} to={`/$/${PAGES.CHANNELS_FOLLOWING_DISCOVER}`} />
|
||||||
|
|
||||||
<Route path={`/`} exact component={HomePage} />
|
<Route path={`/`} exact component={HomePage} />
|
||||||
<Route path={`/$/${PAGES.DISCOVER}`} exact component={DiscoverPage} />
|
<Route path={`/$/${PAGES.DISCOVER}`} exact component={DiscoverPage} />
|
||||||
<Route path={`/$/${PAGES.AUTH}`} exact component={SignInPage} />
|
<Route path={`/$/${PAGES.AUTH}`} exact component={SignInPage} />
|
||||||
|
<Route path={`/$/${PAGES.WELCOME}`} exact component={Welcome} />
|
||||||
<Route path={`/$/${PAGES.TAGS}`} exact component={TagsPage} />
|
<Route path={`/$/${PAGES.TAGS}`} exact component={TagsPage} />
|
||||||
<Route path={`/$/${PAGES.TAGS_FOLLOWING}`} exact component={TagsFollowingPage} />
|
<Route path={`/$/${PAGES.TAGS_FOLLOWING}`} exact component={TagsFollowingPage} />
|
||||||
<Route
|
<Route
|
||||||
|
|
|
@ -20,6 +20,8 @@ export const HIDE_MODAL = 'HIDE_MODAL';
|
||||||
export const CHANGE_MODALS_ALLOWED = 'CHANGE_MODALS_ALLOWED';
|
export const CHANGE_MODALS_ALLOWED = 'CHANGE_MODALS_ALLOWED';
|
||||||
export const TOGGLE_SEARCH_EXPANDED = 'TOGGLE_SEARCH_EXPANDED';
|
export const TOGGLE_SEARCH_EXPANDED = 'TOGGLE_SEARCH_EXPANDED';
|
||||||
export const PASSWORD_SAVED = 'PASSWORD_SAVED';
|
export const PASSWORD_SAVED = 'PASSWORD_SAVED';
|
||||||
|
export const SET_WELCOME_VERSION = 'SET_WELCOME_VERSION';
|
||||||
|
export const SET_ALLOW_ANALYTICS = 'SET_ALLOW_ANALYTICS';
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
export const CHANGE_AFTER_AUTH_PATH = 'CHANGE_AFTER_AUTH_PATH';
|
export const CHANGE_AFTER_AUTH_PATH = 'CHANGE_AFTER_AUTH_PATH';
|
||||||
|
|
|
@ -30,3 +30,4 @@ exports.BLOCKED = 'blocked';
|
||||||
exports.CHANNELS = 'channels';
|
exports.CHANNELS = 'channels';
|
||||||
exports.EMBED = 'embed';
|
exports.EMBED = 'embed';
|
||||||
exports.TOP = 'top';
|
exports.TOP = 'top';
|
||||||
|
exports.WELCOME = 'welcome';
|
||||||
|
|
|
@ -13,7 +13,7 @@ import * as MODALS from 'constants/modal_types';
|
||||||
import React, { Fragment, useState, useEffect } from 'react';
|
import React, { Fragment, useState, useEffect } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { doDaemonReady, doAutoUpdate, doOpenModal, doHideModal } from 'redux/actions/app';
|
import { doDaemonReady, doAutoUpdate, doOpenModal, doHideModal, doToggle3PAnalytics } from 'redux/actions/app';
|
||||||
import { Lbry, doToast, isURIValid, setSearchApi, apiCall } from 'lbry-redux';
|
import { Lbry, doToast, isURIValid, setSearchApi, apiCall } from 'lbry-redux';
|
||||||
import { doSetLanguage, doUpdateIsNightAsync } from 'redux/actions/settings';
|
import { doSetLanguage, doUpdateIsNightAsync } from 'redux/actions/settings';
|
||||||
import {
|
import {
|
||||||
|
@ -277,6 +277,12 @@ function AppWrapper() {
|
||||||
// @endif
|
// @endif
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (persistDone) {
|
||||||
|
app.store.dispatch(doToggle3PAnalytics());
|
||||||
|
}
|
||||||
|
}, [persistDone]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (readyToLaunch && persistDone) {
|
if (readyToLaunch && persistDone) {
|
||||||
app.store.dispatch(doUpdateIsNightAsync());
|
app.store.dispatch(doUpdateIsNightAsync());
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as SETTINGS from 'constants/settings';
|
import {
|
||||||
import { doClearCache, doNotifyEncryptWallet, doNotifyDecryptWallet, doNotifyForgetPassword } from 'redux/actions/app';
|
doClearCache,
|
||||||
|
doNotifyEncryptWallet,
|
||||||
|
doNotifyDecryptWallet,
|
||||||
|
doNotifyForgetPassword,
|
||||||
|
doToggle3PAnalytics,
|
||||||
|
} from 'redux/actions/app';
|
||||||
|
import { selectAllowAnalytics } from 'redux/selectors/app';
|
||||||
import { doSetDaemonSetting, doSetClientSetting, doSetDarkTime } from 'redux/actions/settings';
|
import { doSetDaemonSetting, doSetClientSetting, doSetDarkTime } from 'redux/actions/settings';
|
||||||
import { doSetPlayingUri } from 'redux/actions/content';
|
import { doSetPlayingUri } from 'redux/actions/content';
|
||||||
import { makeSelectClientSetting, selectDaemonSettings, selectosNotificationsEnabled } from 'redux/selectors/settings';
|
import { makeSelectClientSetting, selectDaemonSettings, selectosNotificationsEnabled } from 'redux/selectors/settings';
|
||||||
import { doWalletStatus, selectWalletIsEncrypted, selectBlockedChannelsCount } from 'lbry-redux';
|
import { doWalletStatus, selectWalletIsEncrypted, selectBlockedChannelsCount, SETTINGS } from 'lbry-redux';
|
||||||
import SettingsPage from './view';
|
import SettingsPage from './view';
|
||||||
import { selectUserVerifiedEmail } from 'lbryinc';
|
import { selectUserVerifiedEmail } from 'lbryinc';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
daemonSettings: selectDaemonSettings(state),
|
daemonSettings: selectDaemonSettings(state),
|
||||||
|
allowAnalytics: selectAllowAnalytics(state),
|
||||||
isAuthenticated: selectUserVerifiedEmail(state),
|
isAuthenticated: selectUserVerifiedEmail(state),
|
||||||
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_MATURE)(state),
|
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_MATURE)(state),
|
||||||
instantPurchaseEnabled: makeSelectClientSetting(SETTINGS.INSTANT_PURCHASE_ENABLED)(state),
|
instantPurchaseEnabled: makeSelectClientSetting(SETTINGS.INSTANT_PURCHASE_ENABLED)(state),
|
||||||
|
@ -30,6 +37,7 @@ const select = state => ({
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
setDaemonSetting: (key, value) => dispatch(doSetDaemonSetting(key, value)),
|
setDaemonSetting: (key, value) => dispatch(doSetDaemonSetting(key, value)),
|
||||||
|
toggle3PAnalytics: allow => dispatch(doToggle3PAnalytics(allow)),
|
||||||
clearCache: () => dispatch(doClearCache()),
|
clearCache: () => dispatch(doClearCache()),
|
||||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||||
encryptWallet: () => dispatch(doNotifyEncryptWallet()),
|
encryptWallet: () => dispatch(doNotifyEncryptWallet()),
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
/* eslint react/no-unescaped-entities:0 */
|
/* eslint react/no-unescaped-entities:0 */
|
||||||
/* eslint react/jsx-no-comment-textnodes:0 */
|
/* eslint react/jsx-no-comment-textnodes:0 */
|
||||||
|
|
||||||
import * as SETTINGS from 'constants/settings';
|
|
||||||
import * as PAGES from 'constants/pages';
|
import * as PAGES from 'constants/pages';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
@ -15,6 +14,7 @@ import SettingWalletServer from 'component/settingWalletServer';
|
||||||
import SettingAutoLaunch from 'component/settingAutoLaunch';
|
import SettingAutoLaunch from 'component/settingAutoLaunch';
|
||||||
import FileSelector from 'component/common/file-selector';
|
import FileSelector from 'component/common/file-selector';
|
||||||
import SyncToggle from 'component/syncToggle';
|
import SyncToggle from 'component/syncToggle';
|
||||||
|
import { SETTINGS } from 'lbry-redux';
|
||||||
import Card from 'component/common/card';
|
import Card from 'component/common/card';
|
||||||
import { getKeychainPassword } from 'util/saved-passwords';
|
import { getKeychainPassword } from 'util/saved-passwords';
|
||||||
|
|
||||||
|
@ -51,8 +51,10 @@ type DaemonSettings = {
|
||||||
type Props = {
|
type Props = {
|
||||||
setDaemonSetting: (string, ?SetDaemonSettingArg) => void,
|
setDaemonSetting: (string, ?SetDaemonSettingArg) => void,
|
||||||
setClientSetting: (string, SetDaemonSettingArg) => void,
|
setClientSetting: (string, SetDaemonSettingArg) => void,
|
||||||
|
toggle3PAnalytics: boolean => void,
|
||||||
clearCache: () => Promise<any>,
|
clearCache: () => Promise<any>,
|
||||||
daemonSettings: DaemonSettings,
|
daemonSettings: DaemonSettings,
|
||||||
|
allowAnalytics: boolean,
|
||||||
showNsfw: boolean,
|
showNsfw: boolean,
|
||||||
isAuthenticated: boolean,
|
isAuthenticated: boolean,
|
||||||
instantPurchaseEnabled: boolean,
|
instantPurchaseEnabled: boolean,
|
||||||
|
@ -187,6 +189,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
daemonSettings,
|
daemonSettings,
|
||||||
|
allowAnalytics,
|
||||||
showNsfw,
|
showNsfw,
|
||||||
instantPurchaseEnabled,
|
instantPurchaseEnabled,
|
||||||
instantPurchaseMax,
|
instantPurchaseMax,
|
||||||
|
@ -200,6 +203,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
// autoDownload,
|
// autoDownload,
|
||||||
setDaemonSetting,
|
setDaemonSetting,
|
||||||
setClientSetting,
|
setClientSetting,
|
||||||
|
toggle3PAnalytics,
|
||||||
supportOption,
|
supportOption,
|
||||||
hideBalance,
|
hideBalance,
|
||||||
userBlockedChannelsCount,
|
userBlockedChannelsCount,
|
||||||
|
@ -445,21 +449,39 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Card
|
<Card
|
||||||
title={__('Share Diagnostic Data')}
|
title={__('Share Usage and Diagnostic Data')}
|
||||||
actions={
|
subtitle={
|
||||||
<FormField
|
|
||||||
type="checkbox"
|
|
||||||
name="share_usage_data"
|
|
||||||
onChange={() => setDaemonSetting('share_usage_data', !daemonSettings.share_usage_data)}
|
|
||||||
checked={daemonSettings.share_usage_data}
|
|
||||||
label={
|
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{__('Help make LBRY better by contributing analytics and diagnostic data about my usage.')}{' '}
|
{__(
|
||||||
<Button button="link" label={__('Learn more')} href="https://lbry.com/privacypolicy" />.
|
`This is information like error logging, performance tracking, and usage statistics. It includes your IP address and basic system details, but no other identifying information (unless you sign in to lbry.tv)`
|
||||||
|
)}{' '}
|
||||||
|
<Button button="link" label={__('Learn more')} href="https://lbry.com/privacypolicy" />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
helper={__('You will be ineligible to earn rewards while diagnostics are not being shared.')}
|
actions={
|
||||||
|
<>
|
||||||
|
<FormField
|
||||||
|
type="checkbox"
|
||||||
|
name="share_internal"
|
||||||
|
onChange={() => setDaemonSetting('share_usage_data', !daemonSettings.share_usage_data)}
|
||||||
|
checked={daemonSettings.share_usage_data}
|
||||||
|
label={<React.Fragment>{__('Allow the app to share data to LBRY.inc')}</React.Fragment>}
|
||||||
|
helper={
|
||||||
|
isAuthenticated
|
||||||
|
? __('Internal sharing is required while signed in.')
|
||||||
|
: __('Internal sharing is required to participate in rewards programs.')
|
||||||
|
}
|
||||||
|
disabled={isAuthenticated}
|
||||||
/>
|
/>
|
||||||
|
<FormField
|
||||||
|
type="checkbox"
|
||||||
|
name="share_third_party"
|
||||||
|
onChange={e => toggle3PAnalytics(e.target.checked)}
|
||||||
|
checked={allowAnalytics}
|
||||||
|
label={__('Allow the App to access third party analytics platforms')}
|
||||||
|
helper={__('We use detailed analytics to improve all aspects of the LBRY experience.')}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{/* @endif */}
|
{/* @endif */}
|
||||||
|
|
10
ui/page/welcome/index.js
Normal file
10
ui/page/welcome/index.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import Welcome from './view';
|
||||||
|
|
||||||
|
const select = () => ({});
|
||||||
|
const perform = () => ({});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(Welcome);
|
12
ui/page/welcome/view.jsx
Normal file
12
ui/page/welcome/view.jsx
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import PrivacyAgreement from 'component/privacyAgreement';
|
||||||
|
import Page from 'component/page';
|
||||||
|
|
||||||
|
export default function Welcome() {
|
||||||
|
return (
|
||||||
|
<Page noHeader className="main--auth-page">
|
||||||
|
<PrivacyAgreement />
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ import {
|
||||||
doClearSupport,
|
doClearSupport,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import Native from 'native';
|
import Native from 'native';
|
||||||
import { doFetchDaemonSettings, doSetAutoLaunch } from 'redux/actions/settings';
|
import { doFetchDaemonSettings, doSetAutoLaunch, doSetDaemonSetting } from 'redux/actions/settings';
|
||||||
import {
|
import {
|
||||||
selectIsUpgradeSkipped,
|
selectIsUpgradeSkipped,
|
||||||
selectUpdateUrl,
|
selectUpdateUrl,
|
||||||
|
@ -32,6 +32,7 @@ import {
|
||||||
selectRemoteVersion,
|
selectRemoteVersion,
|
||||||
selectUpgradeTimer,
|
selectUpgradeTimer,
|
||||||
selectModal,
|
selectModal,
|
||||||
|
selectAllowAnalytics,
|
||||||
} from 'redux/selectors/app';
|
} from 'redux/selectors/app';
|
||||||
import { doAuthenticate, doGetSync } from 'lbryinc';
|
import { doAuthenticate, doGetSync } from 'lbryinc';
|
||||||
import { lbrySettings as config, version as appVersion } from 'package.json';
|
import { lbrySettings as config, version as appVersion } from 'package.json';
|
||||||
|
@ -450,11 +451,47 @@ export function doSignOut() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doSetWelcomeVersion(version) {
|
||||||
|
return {
|
||||||
|
type: ACTIONS.SET_WELCOME_VERSION,
|
||||||
|
data: version,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doToggle3PAnalytics(allowParam, doNotDispatch) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const state = getState();
|
||||||
|
const allowState = selectAllowAnalytics(state);
|
||||||
|
const allow = allowParam !== undefined ? allowParam : allowState;
|
||||||
|
analytics.toggleThirdParty(allow);
|
||||||
|
if (!doNotDispatch) {
|
||||||
|
return dispatch({
|
||||||
|
type: ACTIONS.SET_ALLOW_ANALYTICS,
|
||||||
|
data: allow,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function doGetAndPopulatePreferences() {
|
export function doGetAndPopulatePreferences() {
|
||||||
return dispatch => {
|
return (dispatch, getState) => {
|
||||||
function successCb(savedPreferences) {
|
function successCb(savedPreferences) {
|
||||||
|
const state = getState();
|
||||||
|
const { daemonSettings } = state;
|
||||||
|
|
||||||
if (savedPreferences !== null) {
|
if (savedPreferences !== null) {
|
||||||
dispatch(doPopulateSharedUserState(savedPreferences));
|
dispatch(doPopulateSharedUserState(savedPreferences));
|
||||||
|
// @if TARGET='app'
|
||||||
|
const { settings, sharing_3P: sharing3P } = savedPreferences.value;
|
||||||
|
Object.entries(settings).forEach(([key, val]) => {
|
||||||
|
if (daemonSettings[key] !== val) {
|
||||||
|
dispatch(doSetDaemonSetting(key, val, false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (sharing3P !== undefined) {
|
||||||
|
doToggle3PAnalytics(sharing3P, true);
|
||||||
|
}
|
||||||
|
// @endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { Lbry, ACTIONS, doToast, SHARED_PREFERENCES, doWalletReconnect } from 'lbry-redux';
|
import { Lbry, ACTIONS, doToast, SHARED_PREFERENCES, doWalletReconnect, SETTINGS } from 'lbry-redux';
|
||||||
import * as SETTINGS from 'constants/settings';
|
|
||||||
import * as LOCAL_ACTIONS from 'constants/action_types';
|
import * as LOCAL_ACTIONS from 'constants/action_types';
|
||||||
import analytics from 'analytics';
|
import analytics from 'analytics';
|
||||||
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
||||||
|
@ -12,7 +11,7 @@ const UPDATE_IS_NIGHT_INTERVAL = 5 * 60 * 1000;
|
||||||
export function doFetchDaemonSettings() {
|
export function doFetchDaemonSettings() {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
Lbry.settings_get().then(settings => {
|
Lbry.settings_get().then(settings => {
|
||||||
analytics.toggle(settings.share_usage_data);
|
analytics.toggleInternal(settings.share_usage_data);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.DAEMON_SETTINGS_RECEIVED,
|
type: ACTIONS.DAEMON_SETTINGS_RECEIVED,
|
||||||
data: {
|
data: {
|
||||||
|
@ -33,10 +32,9 @@ export function doGetDaemonStatus() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return status;
|
return status;
|
||||||
},
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
export function doClearDaemonSetting(key) {
|
export function doClearDaemonSetting(key) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
|
@ -55,7 +53,7 @@ export function doClearDaemonSetting(key) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Lbry.settings_get().then(settings => {
|
Lbry.settings_get().then(settings => {
|
||||||
analytics.toggle(settings.share_usage_data);
|
analytics.toggleInternal(settings.share_usage_data);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.DAEMON_SETTINGS_RECEIVED,
|
type: ACTIONS.DAEMON_SETTINGS_RECEIVED,
|
||||||
data: {
|
data: {
|
||||||
|
@ -65,27 +63,28 @@ export function doClearDaemonSetting(key) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// if doPopulate is applying settings, we don't want to cause a loop; doNotDispatch = true.
|
||||||
export function doSetDaemonSetting(key, value) {
|
export function doSetDaemonSetting(key, value, doNotDispatch = false) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
const newSettings = {
|
const newSettings = {
|
||||||
key,
|
key,
|
||||||
value: !value && value !== false ? null : value,
|
value: !value && value !== false ? null : value,
|
||||||
};
|
};
|
||||||
Lbry.settings_set(newSettings).then(newSetting => {
|
Lbry.settings_set(newSettings).then(newSetting => {
|
||||||
if (Object.values(SHARED_PREFERENCES).includes(key)) {
|
if (Object.values(SHARED_PREFERENCES).includes(key) && !doNotDispatch) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.SHARED_PREFERENCE_SET,
|
type: ACTIONS.SHARED_PREFERENCE_SET,
|
||||||
data: {key: key, value: newSetting[key]},
|
data: { key: key, value: newSetting[key] },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// hardcoding this in lieu of a better solution
|
// hardcoding this in lieu of a better solution
|
||||||
if (key === SHARED_PREFERENCES.WALLET_SERVERS) {
|
if (key === SHARED_PREFERENCES.WALLET_SERVERS) {
|
||||||
dispatch(doWalletReconnect());
|
dispatch(doWalletReconnect());
|
||||||
|
// todo: add sdk reloadsettings() (or it happens automagically?)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Lbry.settings_get().then(settings => {
|
Lbry.settings_get().then(settings => {
|
||||||
analytics.toggle(settings.share_usage_data);
|
analytics.toggleInternal(settings.share_usage_data);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.DAEMON_SETTINGS_RECEIVED,
|
type: ACTIONS.DAEMON_SETTINGS_RECEIVED,
|
||||||
data: {
|
data: {
|
||||||
|
@ -104,12 +103,14 @@ export function doSaveCustomWalletServers(servers) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doSetClientSetting(key, value) {
|
export function doSetClientSetting(key, value) {
|
||||||
return {
|
return dispatch => {
|
||||||
|
dispatch({
|
||||||
type: ACTIONS.CLIENT_SETTING_CHANGED,
|
type: ACTIONS.CLIENT_SETTING_CHANGED,
|
||||||
data: {
|
data: {
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
|
import { ACTIONS as LBRY_REDUX_ACTIONS } from 'lbry-redux';
|
||||||
import { remote } from 'electron';
|
import { remote } from 'electron';
|
||||||
|
|
||||||
// @if TARGET='app'
|
// @if TARGET='app'
|
||||||
|
@ -38,6 +39,8 @@ export type AppState = {
|
||||||
enhancedLayout: boolean,
|
enhancedLayout: boolean,
|
||||||
searchOptionsExpanded: boolean,
|
searchOptionsExpanded: boolean,
|
||||||
isPasswordSaved: boolean,
|
isPasswordSaved: boolean,
|
||||||
|
welcomeVersion: number,
|
||||||
|
allowAnalytics: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultState: AppState = {
|
const defaultState: AppState = {
|
||||||
|
@ -69,6 +72,8 @@ const defaultState: AppState = {
|
||||||
currentScroll: 0,
|
currentScroll: 0,
|
||||||
scrollHistory: [0],
|
scrollHistory: [0],
|
||||||
isPasswordSaved: false,
|
isPasswordSaved: false,
|
||||||
|
welcomeVersion: 0.0,
|
||||||
|
allowAnalytics: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// @@router comes from react-router
|
// @@router comes from react-router
|
||||||
|
@ -250,6 +255,16 @@ reducers[ACTIONS.SHOW_MODAL] = (state, action) =>
|
||||||
modalProps: action.data.modalProps,
|
modalProps: action.data.modalProps,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
reducers[ACTIONS.SET_WELCOME_VERSION] = (state, action) =>
|
||||||
|
Object.assign({}, state, {
|
||||||
|
welcomeVersion: action.data,
|
||||||
|
});
|
||||||
|
|
||||||
|
reducers[ACTIONS.SET_ALLOW_ANALYTICS] = (state, action) =>
|
||||||
|
Object.assign({}, state, {
|
||||||
|
allowAnalytics: action.data,
|
||||||
|
});
|
||||||
|
|
||||||
reducers[ACTIONS.HIDE_MODAL] = state =>
|
reducers[ACTIONS.HIDE_MODAL] = state =>
|
||||||
Object.assign({}, state, {
|
Object.assign({}, state, {
|
||||||
modal: null,
|
modal: null,
|
||||||
|
@ -261,6 +276,15 @@ reducers[ACTIONS.TOGGLE_SEARCH_EXPANDED] = state =>
|
||||||
searchOptionsExpanded: !state.searchOptionsExpanded,
|
searchOptionsExpanded: !state.searchOptionsExpanded,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
reducers[LBRY_REDUX_ACTIONS.USER_STATE_POPULATE] = (state, action) => {
|
||||||
|
const { welcomeVersion, allowAnalytics } = action.data;
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...(welcomeVersion !== undefined ? { welcomeVersion } : {}),
|
||||||
|
...(allowAnalytics !== undefined ? { allowAnalytics } : {}),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export default function reducer(state: AppState = defaultState, action: any) {
|
export default function reducer(state: AppState = defaultState, action: any) {
|
||||||
const handler = reducers[action.type];
|
const handler = reducers[action.type];
|
||||||
if (handler) return handler(state, action);
|
if (handler) return handler(state, action);
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import * as SETTINGS from 'constants/settings';
|
import * as APP_SETTINGS from 'constants/settings';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
||||||
import { ACTIONS as LBRY_REDUX_ACTIONS, SHARED_PREFERENCES } from 'lbry-redux';
|
import { ACTIONS as LBRY_REDUX_ACTIONS, SHARED_PREFERENCES, SETTINGS } from 'lbry-redux';
|
||||||
|
|
||||||
const reducers = {};
|
const reducers = {};
|
||||||
let settingLanguage = [];
|
let settingLanguage = [];
|
||||||
try {
|
try {
|
||||||
|
@ -38,7 +37,7 @@ const defaultState = {
|
||||||
[SETTINGS.OS_NOTIFICATIONS_ENABLED]: true,
|
[SETTINGS.OS_NOTIFICATIONS_ENABLED]: true,
|
||||||
[SETTINGS.AUTOMATIC_DARK_MODE_ENABLED]: false,
|
[SETTINGS.AUTOMATIC_DARK_MODE_ENABLED]: false,
|
||||||
|
|
||||||
[SETTINGS.DARK_MODE_TIMES]: {
|
[APP_SETTINGS.DARK_MODE_TIMES]: {
|
||||||
from: { hour: '21', min: '00', formattedTime: '21:00' },
|
from: { hour: '21', min: '00', formattedTime: '21:00' },
|
||||||
to: { hour: '8', min: '00', formattedTime: '8:00' },
|
to: { hour: '8', min: '00', formattedTime: '8:00' },
|
||||||
},
|
},
|
||||||
|
@ -83,7 +82,7 @@ reducers[ACTIONS.CLIENT_SETTING_CHANGED] = (state, action) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
reducers[ACTIONS.UPDATE_IS_NIGHT] = state => {
|
reducers[ACTIONS.UPDATE_IS_NIGHT] = state => {
|
||||||
const { from, to } = state.clientSettings[SETTINGS.DARK_MODE_TIMES];
|
const { from, to } = state.clientSettings[APP_SETTINGS.DARK_MODE_TIMES];
|
||||||
const momentNow = moment();
|
const momentNow = moment();
|
||||||
const startNightMoment = moment(from.formattedTime, 'HH:mm');
|
const startNightMoment = moment(from.formattedTime, 'HH:mm');
|
||||||
const endNightMoment = moment(to.formattedTime, 'HH:mm');
|
const endNightMoment = moment(to.formattedTime, 'HH:mm');
|
||||||
|
@ -130,8 +129,8 @@ reducers[ACTIONS.CLIENT_SETTING_CHANGED] = (state, action) => {
|
||||||
|
|
||||||
reducers[LBRY_REDUX_ACTIONS.USER_STATE_POPULATE] = (state, action) => {
|
reducers[LBRY_REDUX_ACTIONS.USER_STATE_POPULATE] = (state, action) => {
|
||||||
const { settings: sharedPreferences } = action.data;
|
const { settings: sharedPreferences } = action.data;
|
||||||
|
// todo: populate sharedPreferences that match client settings constants
|
||||||
|
|
||||||
// process clientSettings and daemonSettings
|
|
||||||
return Object.assign({}, state, { sharedPreferences });
|
return Object.assign({}, state, { sharedPreferences });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,16 @@ export const selectSearchOptionsExpanded = createSelector(
|
||||||
state => state.searchOptionsExpanded
|
state => state.searchOptionsExpanded
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectWelcomeVersion = createSelector(
|
||||||
|
selectState,
|
||||||
|
state => state.welcomeVersion
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectAllowAnalytics = createSelector(
|
||||||
|
selectState,
|
||||||
|
state => state.allowAnalytics
|
||||||
|
);
|
||||||
|
|
||||||
export const selectScrollStartingPosition = createSelector(
|
export const selectScrollStartingPosition = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
state => state.currentScroll
|
state => state.currentScroll
|
||||||
|
|
16
ui/store.js
16
ui/store.js
|
@ -1,5 +1,4 @@
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import * as SETTINGS from 'constants/settings';
|
|
||||||
import { persistStore, persistReducer } from 'redux-persist';
|
import { persistStore, persistReducer } from 'redux-persist';
|
||||||
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
|
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
|
||||||
import createCompressor from 'redux-persist-transform-compress';
|
import createCompressor from 'redux-persist-transform-compress';
|
||||||
|
@ -10,7 +9,7 @@ import thunk from 'redux-thunk';
|
||||||
import { createMemoryHistory, createBrowserHistory } from 'history';
|
import { createMemoryHistory, createBrowserHistory } from 'history';
|
||||||
import { routerMiddleware } from 'connected-react-router';
|
import { routerMiddleware } from 'connected-react-router';
|
||||||
import createRootReducer from './reducers';
|
import createRootReducer from './reducers';
|
||||||
import { buildSharedStateMiddleware, ACTIONS as LBRY_REDUX_ACTIONS } from 'lbry-redux';
|
import { buildSharedStateMiddleware, ACTIONS as LBRY_REDUX_ACTIONS, SETTINGS } from 'lbry-redux';
|
||||||
import { doGetSync, selectUserVerifiedEmail } from 'lbryinc';
|
import { doGetSync, selectUserVerifiedEmail } from 'lbryinc';
|
||||||
import { getSavedPassword } from 'util/saved-passwords';
|
import { getSavedPassword } from 'util/saved-passwords';
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
|
@ -50,7 +49,14 @@ const fileInfoFilter = createFilter('fileInfo', [
|
||||||
'fileListDownloadedSort',
|
'fileListDownloadedSort',
|
||||||
'fileListSubscriptionSort',
|
'fileListSubscriptionSort',
|
||||||
]);
|
]);
|
||||||
const appFilter = createFilter('app', ['hasClickedComment', 'searchOptionsExpanded', 'volume', 'muted']);
|
const appFilter = createFilter('app', [
|
||||||
|
'hasClickedComment',
|
||||||
|
'searchOptionsExpanded',
|
||||||
|
'volume',
|
||||||
|
'muted',
|
||||||
|
'allowAnalytics',
|
||||||
|
'welcomeVersion',
|
||||||
|
]);
|
||||||
// We only need to persist the receiveAddress for the wallet
|
// We only need to persist the receiveAddress for the wallet
|
||||||
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
||||||
const searchFilter = createFilter('search', ['options']);
|
const searchFilter = createFilter('search', ['options']);
|
||||||
|
@ -113,6 +119,8 @@ const triggerSharedStateActions = [
|
||||||
LBRY_REDUX_ACTIONS.TOGGLE_BLOCK_CHANNEL,
|
LBRY_REDUX_ACTIONS.TOGGLE_BLOCK_CHANNEL,
|
||||||
LBRY_REDUX_ACTIONS.CREATE_CHANNEL_COMPLETED,
|
LBRY_REDUX_ACTIONS.CREATE_CHANNEL_COMPLETED,
|
||||||
LBRY_REDUX_ACTIONS.SHARED_PREFERENCE_SET,
|
LBRY_REDUX_ACTIONS.SHARED_PREFERENCE_SET,
|
||||||
|
ACTIONS.SET_WELCOME_VERSION,
|
||||||
|
ACTIONS.SET_ALLOW_ANALYTICS,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,6 +143,8 @@ const sharedStateFilters = {
|
||||||
},
|
},
|
||||||
blocked: { source: 'blocked', property: 'blockedChannels' },
|
blocked: { source: 'blocked', property: 'blockedChannels' },
|
||||||
settings: { source: 'settings', property: 'sharedPreferences' },
|
settings: { source: 'settings', property: 'sharedPreferences' },
|
||||||
|
app_welcome_version: { source: 'app', property: 'welcomeVersion' },
|
||||||
|
sharing_3P: { source: 'app', property: 'allowAnalytics' },
|
||||||
};
|
};
|
||||||
|
|
||||||
const sharedStateCb = ({ dispatch, getState }) => {
|
const sharedStateCb = ({ dispatch, getState }) => {
|
||||||
|
|
|
@ -7174,9 +7174,9 @@ lazy-val@^1.0.4:
|
||||||
yargs "^13.2.2"
|
yargs "^13.2.2"
|
||||||
zstd-codec "^0.1.1"
|
zstd-codec "^0.1.1"
|
||||||
|
|
||||||
lbry-redux@lbryio/lbry-redux#3d64f8acc6c2ce37252f59feff89e1fc58cb74c1:
|
lbry-redux@lbryio/lbry-redux#f22bdbfe2f403d13fa8ce99e8849dca0e3d19bef:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/3d64f8acc6c2ce37252f59feff89e1fc58cb74c1"
|
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/f22bdbfe2f403d13fa8ce99e8849dca0e3d19bef"
|
||||||
dependencies:
|
dependencies:
|
||||||
proxy-polyfill "0.1.6"
|
proxy-polyfill "0.1.6"
|
||||||
reselect "^3.0.0"
|
reselect "^3.0.0"
|
||||||
|
|
Loading…
Reference in a new issue