From fa09f8a8608619bea6e186796c8aaefe3f9524aa Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Tue, 13 Aug 2019 21:24:20 -0400
Subject: [PATCH 01/12] fix: prefil publish links and required lbry-redux
publish changes
---
package.json | 2 +-
src/ui/component/claimPreview/index.js | 10 ++++++++++
src/ui/component/claimPreview/view.jsx | 11 +++++++++--
src/ui/component/fileViewer/view.jsx | 2 +-
src/ui/modal/modalAutoGenerateThumbnail/index.js | 3 ++-
src/ui/modal/modalConfirmThumbnailUpload/index.js | 3 ++-
src/ui/page/file/index.js | 3 ++-
yarn.lock | 4 ++--
8 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/package.json b/package.json
index 2e7c64549..55e83e3d3 100644
--- a/package.json
+++ b/package.json
@@ -125,7 +125,7 @@
"jsmediatags": "^3.8.1",
"json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git",
- "lbry-redux": "lbryio/lbry-redux#05e70648e05c51c51710f6dd698a8e2219b54df2",
+ "lbry-redux": "lbryio/lbry-redux#58bbdb9a2e537b3994d545ede120d070a7b41ee5",
"lbryinc": "lbryio/lbryinc#a93596c51c8fb0a226cb84df04c26a6bb60a45fb",
"lint-staged": "^7.0.2",
"localforage": "^1.7.1",
diff --git a/src/ui/component/claimPreview/index.js b/src/ui/component/claimPreview/index.js
index 7b49dc36d..203d81718 100644
--- a/src/ui/component/claimPreview/index.js
+++ b/src/ui/component/claimPreview/index.js
@@ -1,3 +1,4 @@
+import * as PAGES from 'constants/pages';
import { connect } from 'react-redux';
import {
doResolveUri,
@@ -10,11 +11,15 @@ import {
makeSelectClaimIsNsfw,
selectBlockedChannels,
selectChannelIsBlocked,
+ doClearPublish,
+ doPrepareEdit,
} from 'lbry-redux';
import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc';
import { selectShowMatureContent } from 'redux/selectors/settings';
import { makeSelectHasVisitedUri } from 'redux/selectors/content';
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
+import { push } from 'connected-react-router';
+
import ClaimPreview from './view';
const select = (state, props) => ({
@@ -36,6 +41,11 @@ const select = (state, props) => ({
const perform = dispatch => ({
resolveUri: uri => dispatch(doResolveUri(uri)),
+ beginPublish: name => {
+ dispatch(doClearPublish());
+ dispatch(doPrepareEdit({ name }));
+ dispatch(push(`/$/${PAGES.PUBLISH}`));
+ },
});
export default connect(
diff --git a/src/ui/component/claimPreview/view.jsx b/src/ui/component/claimPreview/view.jsx
index d15ed42ad..93f142916 100644
--- a/src/ui/component/claimPreview/view.jsx
+++ b/src/ui/component/claimPreview/view.jsx
@@ -44,6 +44,7 @@ type Props = {
blockedChannelUris: Array,
channelIsBlocked: boolean,
isSubscribed: boolean,
+ beginPublish: string => void,
};
const ClaimPreview = forwardRef((props: Props, ref: any) => {
@@ -68,6 +69,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => {
showUserBlocked,
channelIsBlocked,
isSubscribed,
+ beginPublish,
} = props;
const haventFetched = claim === undefined;
const abandoned = !isResolvingUri && !claim;
@@ -77,8 +79,9 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => {
const hideActions = type === 'small' || type === 'tooltip';
let isValid;
+ let name;
try {
- parseURI(uri);
+ ({ claimName: name } = parseURI(uri));
isValid = true;
} catch (e) {
isValid = false;
@@ -191,7 +194,11 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => {
{__('Publish something and claim this spot!')}
-
+
)}
diff --git a/src/ui/component/fileViewer/view.jsx b/src/ui/component/fileViewer/view.jsx
index 1f96390e8..c67f6ff3c 100644
--- a/src/ui/component/fileViewer/view.jsx
+++ b/src/ui/component/fileViewer/view.jsx
@@ -87,7 +87,7 @@ export default function FileViewer(props: Props) {
const hidePlayer = !isPlaying || !uri || (!inline && (!floatingPlayerEnabled || !isStreamable));
if (hidePlayer) {
- clearPlayingUri();
+ // clearPlayingUri();
return null;
}
diff --git a/src/ui/modal/modalAutoGenerateThumbnail/index.js b/src/ui/modal/modalAutoGenerateThumbnail/index.js
index d17116afe..da06408b6 100644
--- a/src/ui/modal/modalAutoGenerateThumbnail/index.js
+++ b/src/ui/modal/modalAutoGenerateThumbnail/index.js
@@ -1,11 +1,12 @@
import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app';
import { doToast, doUploadThumbnail } from 'lbry-redux';
+import fs from 'fs';
import ModalAutoGenerateThumbnail from './view';
const perform = dispatch => ({
closeModal: () => dispatch(doHideModal()),
- upload: buffer => dispatch(doUploadThumbnail(null, buffer)),
+ upload: buffer => dispatch(doUploadThumbnail(null, buffer, null, fs)),
showToast: options => dispatch(doToast(options)),
});
diff --git a/src/ui/modal/modalConfirmThumbnailUpload/index.js b/src/ui/modal/modalConfirmThumbnailUpload/index.js
index f30c9a74f..6c5c6858e 100644
--- a/src/ui/modal/modalConfirmThumbnailUpload/index.js
+++ b/src/ui/modal/modalConfirmThumbnailUpload/index.js
@@ -1,11 +1,12 @@
import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app';
import { doUploadThumbnail, doUpdatePublishForm } from 'lbry-redux';
+import fs from 'fs';
import ModalConfirmThumbnailUpload from './view';
const perform = dispatch => ({
closeModal: () => dispatch(doHideModal()),
- upload: path => dispatch(doUploadThumbnail(path)),
+ upload: path => dispatch(doUploadThumbnail(path, null, null, fs)),
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
});
diff --git a/src/ui/page/file/index.js b/src/ui/page/file/index.js
index d56504d5f..b0f1c6c8e 100644
--- a/src/ui/page/file/index.js
+++ b/src/ui/page/file/index.js
@@ -22,6 +22,7 @@ import { doFetchViewCount, makeSelectViewCountForUri, makeSelectCostInfoForUri,
import { selectShowMatureContent, makeSelectClientSetting } from 'redux/selectors/settings';
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
import { doOpenModal } from 'redux/actions/app';
+import fs from 'fs';
import FilePage from './view';
const select = (state, props) => ({
@@ -47,7 +48,7 @@ const perform = dispatch => ({
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
- prepareEdit: (publishData, uri, fileInfo) => dispatch(doPrepareEdit(publishData, uri, fileInfo)),
+ prepareEdit: (publishData, uri, fileInfo) => dispatch(doPrepareEdit(publishData, uri, fileInfo, fs)),
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
setViewed: uri => dispatch(doSetContentHistoryItem(uri)),
markSubscriptionRead: (channel, uri) => dispatch(doRemoveUnreadSubscription(channel, uri)),
diff --git a/yarn.lock b/yarn.lock
index 444ae1a62..d1ad5cbbf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6762,9 +6762,9 @@ lazy-val@^1.0.3, lazy-val@^1.0.4:
yargs "^13.2.2"
zstd-codec "^0.1.1"
-lbry-redux@lbryio/lbry-redux#05e70648e05c51c51710f6dd698a8e2219b54df2:
+lbry-redux@lbryio/lbry-redux#58bbdb9a2e537b3994d545ede120d070a7b41ee5:
version "0.0.1"
- resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/05e70648e05c51c51710f6dd698a8e2219b54df2"
+ resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/58bbdb9a2e537b3994d545ede120d070a7b41ee5"
dependencies:
mime "^2.4.4"
proxy-polyfill "0.1.6"
--
2.45.2
From f51cabc5613cacb078cf0ea976c8a12d9cb83925 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Tue, 13 Aug 2019 23:04:08 -0400
Subject: [PATCH 02/12] add back file view analytics
---
src/ui/analytics.js | 13 +++-----
src/ui/component/fileViewer/index.js | 2 ++
src/ui/component/fileViewer/view.jsx | 44 +++++++++++++++++++++-------
src/ui/page/settings/index.js | 2 ++
src/ui/page/settings/view.jsx | 2 ++
src/ui/redux/actions/app.js | 25 +++++++++++++++-
src/ui/util/use-previous.js | 11 +++++++
7 files changed, 78 insertions(+), 21 deletions(-)
create mode 100644 src/ui/util/use-previous.js
diff --git a/src/ui/analytics.js b/src/ui/analytics.js
index 2c887eeaa..47e6eeb2f 100644
--- a/src/ui/analytics.js
+++ b/src/ui/analytics.js
@@ -39,7 +39,7 @@ const analytics: Analytics = {
analyticsEnabled = enabled;
// @endif
},
- apiLogView: (uri, outpoint, claimId, timeToStart, onSuccessCb) => {
+ apiLogView: (uri, outpoint, claimId, timeToStart) => {
if (analyticsEnabled) {
const params: {
uri: string,
@@ -52,17 +52,12 @@ const analytics: Analytics = {
claim_id: claimId,
};
- if (timeToStart) {
+ // lbry.tv streams from AWS so we don't care about the time to start
+ if (timeToStart && !IS_WEB) {
params.time_to_start = timeToStart;
}
- Lbryio.call('file', 'view', params)
- .then(() => {
- if (onSuccessCb) {
- onSuccessCb();
- }
- })
- .catch(() => {});
+ Lbryio.call('file', 'view', params);
}
},
apiLogSearch: () => {
diff --git a/src/ui/component/fileViewer/index.js b/src/ui/component/fileViewer/index.js
index 82249b4bb..5551fec66 100644
--- a/src/ui/component/fileViewer/index.js
+++ b/src/ui/component/fileViewer/index.js
@@ -12,6 +12,7 @@ import { makeSelectIsPlaying, makeSelectShouldObscurePreview, selectPlayingUri }
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSetPlayingUri } from 'redux/actions/content';
import { withRouter } from 'react-router';
+import { doAnalyticsView } from 'redux/actions/app';
import FileViewer from './view';
const select = (state, props) => {
@@ -32,6 +33,7 @@ const select = (state, props) => {
const perform = dispatch => ({
clearPlayingUri: () => dispatch(doSetPlayingUri(null)),
+ triggerAnalyticsView: (uri, timeToStart) => dispatch(doAnalyticsView(uri, timeToStart)),
});
export default withRouter(
diff --git a/src/ui/component/fileViewer/view.jsx b/src/ui/component/fileViewer/view.jsx
index c67f6ff3c..8797e2baf 100644
--- a/src/ui/component/fileViewer/view.jsx
+++ b/src/ui/component/fileViewer/view.jsx
@@ -1,12 +1,13 @@
// @flow
import * as ICONS from 'constants/icons';
-import React, { useEffect } from 'react';
+import React, { useState, useEffect } from 'react';
import Button from 'component/button';
import classnames from 'classnames';
import LoadingScreen from 'component/common/loading-screen';
import FileRender from 'component/fileRender';
import UriIndicator from 'component/uriIndicator';
import usePersistedState from 'util/use-persisted-state';
+import usePrevious from 'util/use-previous';
import { FILE_WRAPPER_CLASS } from 'page/file/view';
import Draggable from 'react-draggable';
import Tooltip from 'component/common/tooltip';
@@ -27,6 +28,7 @@ type Props = {
title: ?string,
floatingPlayerEnabled: boolean,
clearPlayingUri: () => void,
+ triggerAnalyticsView: (string, number) => void,
};
export default function FileViewer(props: Props) {
@@ -40,7 +42,9 @@ export default function FileViewer(props: Props) {
title,
clearPlayingUri,
floatingPlayerEnabled,
+ triggerAnalyticsView,
} = props;
+ const [playTime, setPlayTime] = useState();
const [fileViewerRect, setFileViewerRect] = usePersistedState('inline-file-viewer:rect');
const [position, setPosition] = usePersistedState('floating-file-viewer:position', {
x: -25,
@@ -54,15 +58,24 @@ export default function FileViewer(props: Props) {
? __("It looks like you deleted or moved this file. We're rebuilding it now. It will only take a few seconds.")
: __('Loading');
- function handleDrag(e, ui) {
- const { x, y } = position;
- const newX = x + ui.deltaX;
- const newY = y + ui.deltaY;
- setPosition({
- x: newX,
- y: newY,
- });
- }
+ const previousUri = usePrevious(uri);
+ const previousIsReadyToPlay = usePrevious(isReadyToPlay);
+ const isNewView = uri && previousUri !== uri && isPlaying;
+ const wasntReadyButNowItIs = isReadyToPlay && !previousIsReadyToPlay;
+
+ useEffect(() => {
+ if (isNewView) {
+ setPlayTime(Date.now());
+ }
+ }, [isNewView, uri]);
+
+ useEffect(() => {
+ if (playTime && isReadyToPlay && wasntReadyButNowItIs) {
+ const timeToStart = Date.now() - playTime;
+ triggerAnalyticsView(uri, timeToStart);
+ setPlayTime(null);
+ }
+ }, [setPlayTime, triggerAnalyticsView, isReadyToPlay, wasntReadyButNowItIs, playTime, uri]);
useEffect(() => {
function handleResize() {
@@ -85,9 +98,18 @@ export default function FileViewer(props: Props) {
}
}, [setFileViewerRect, inline]);
+ function handleDrag(e, ui) {
+ const { x, y } = position;
+ const newX = x + ui.deltaX;
+ const newY = y + ui.deltaY;
+ setPosition({
+ x: newX,
+ y: newY,
+ });
+ }
+
const hidePlayer = !isPlaying || !uri || (!inline && (!floatingPlayerEnabled || !isStreamable));
if (hidePlayer) {
- // clearPlayingUri();
return null;
}
diff --git a/src/ui/page/settings/index.js b/src/ui/page/settings/index.js
index 2fcc268c7..56a7c7a43 100644
--- a/src/ui/page/settings/index.js
+++ b/src/ui/page/settings/index.js
@@ -2,6 +2,7 @@ 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 { doSetPlayingUri } from 'redux/actions/content';
import {
makeSelectClientSetting,
selectDaemonSettings,
@@ -40,6 +41,7 @@ const perform = dispatch => ({
encryptWallet: () => dispatch(doNotifyEncryptWallet()),
decryptWallet: () => dispatch(doNotifyDecryptWallet()),
updateWalletStatus: () => dispatch(doWalletStatus()),
+ clearPlayingUri: () => dispatch(doSetPlayingUri(null)),
});
export default connect(
diff --git a/src/ui/page/settings/view.jsx b/src/ui/page/settings/view.jsx
index c31decd29..06feac772 100644
--- a/src/ui/page/settings/view.jsx
+++ b/src/ui/page/settings/view.jsx
@@ -168,6 +168,7 @@ class SettingsPage extends React.PureComponent {
hideBalance,
userBlockedChannelsCount,
floatingPlayer,
+ clearPlayingUri,
} = this.props;
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
@@ -319,6 +320,7 @@ class SettingsPage extends React.PureComponent {
name="floating_player"
onChange={() => {
setClientSetting(SETTINGS.FLOATING_PLAYER, !floatingPlayer);
+ clearPlayingUri();
}}
checked={floatingPlayer}
label={__('Floating video player')}
diff --git a/src/ui/redux/actions/app.js b/src/ui/redux/actions/app.js
index cd05bba2b..ee5114926 100644
--- a/src/ui/redux/actions/app.js
+++ b/src/ui/redux/actions/app.js
@@ -6,7 +6,14 @@ import { ipcRenderer, remote } from 'electron';
import path from 'path';
import * as ACTIONS from 'constants/action_types';
import * as MODALS from 'constants/modal_types';
-import { Lbry, doBalanceSubscribe, doFetchFileInfosAndPublishedClaims, doError } from 'lbry-redux';
+import {
+ Lbry,
+ doBalanceSubscribe,
+ doFetchFileInfosAndPublishedClaims,
+ doError,
+ makeSelectClaimForUri,
+ makeSelectClaimIsMine,
+} from 'lbry-redux';
import Native from 'native';
import { doFetchDaemonSettings } from 'redux/actions/settings';
import { doCheckSubscriptionsInit } from 'redux/actions/subscriptions';
@@ -24,6 +31,7 @@ import {
import { doAuthenticate } from 'lbryinc';
import { lbrySettings as config, version as appVersion } from 'package.json';
import { push } from 'connected-react-router';
+import analytics from 'analytics';
// @if TARGET='app'
const { autoUpdater } = remote.require('electron-updater');
@@ -410,3 +418,18 @@ export function doToggleSearchExpanded() {
type: ACTIONS.TOGGLE_SEARCH_EXPANDED,
};
}
+
+export function doAnalyticsView(uri, timeToStart) {
+ return (dispatch, getState) => {
+ const state = getState();
+ const { txid, nout, claim_id: claimId } = makeSelectClaimForUri(uri)(state);
+ const claimIsMine = makeSelectClaimIsMine(uri)(state);
+ const outpoint = `${txid}:${nout}`;
+
+ if (claimIsMine) {
+ return;
+ }
+
+ analytics.apiLogView(uri, outpoint, claimId, timeToStart);
+ };
+}
diff --git a/src/ui/util/use-previous.js b/src/ui/util/use-previous.js
new file mode 100644
index 000000000..ed46581cb
--- /dev/null
+++ b/src/ui/util/use-previous.js
@@ -0,0 +1,11 @@
+import { useEffect, useRef } from 'react';
+
+export default function usePrevious(value) {
+ const ref = useRef();
+
+ useEffect(() => {
+ ref.current = value;
+ }, [value]);
+
+ return ref.current;
+}
--
2.45.2
From 00e03ff6bef40bb128bd4006996b6ca027720a87 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Tue, 13 Aug 2019 23:09:25 -0400
Subject: [PATCH 03/12] fix: only autoplay streamable files
---
src/ui/component/fileViewerInitiator/view.jsx | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/ui/component/fileViewerInitiator/view.jsx b/src/ui/component/fileViewerInitiator/view.jsx
index 7572b6f77..a8e5142a9 100644
--- a/src/ui/component/fileViewerInitiator/view.jsx
+++ b/src/ui/component/fileViewerInitiator/view.jsx
@@ -25,7 +25,18 @@ type Props = {
};
export default function FileViewer(props: Props) {
- const { play, mediaType, isPlaying, fileInfo, uri, obscurePreview, insufficientCredits, thumbnail, autoplay } = props;
+ const {
+ play,
+ mediaType,
+ isPlaying,
+ fileInfo,
+ uri,
+ obscurePreview,
+ insufficientCredits,
+ thumbnail,
+ autoplay,
+ isStreamable,
+ } = props;
const isPlayable = ['audio', 'video'].indexOf(mediaType) !== -1;
const fileStatus = fileInfo && fileInfo.status;
@@ -64,10 +75,10 @@ export default function FileViewer(props: Props) {
useEffect(() => {
const videoOnPage = document.querySelector('video');
- if (autoplay && !videoOnPage) {
+ if (autoplay && !videoOnPage && isStreamable) {
viewFile();
}
- }, [autoplay, viewFile]);
+ }, [autoplay, viewFile, isStreamable]);
return (
Date: Tue, 13 Aug 2019 23:56:11 -0400
Subject: [PATCH 04/12] general player fixes
---
package.json | 2 +-
src/ui/analytics.js | 2 +-
src/ui/component/fileDownloadLink/view.jsx | 4 +---
src/ui/modal/modalRemoveFile/view.jsx | 2 +-
src/ui/redux/actions/file.js | 3 +++
src/ui/scss/component/_content.scss | 9 ++++-----
yarn.lock | 4 ++--
7 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/package.json b/package.json
index 55e83e3d3..609de08c9 100644
--- a/package.json
+++ b/package.json
@@ -125,7 +125,7 @@
"jsmediatags": "^3.8.1",
"json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git",
- "lbry-redux": "lbryio/lbry-redux#58bbdb9a2e537b3994d545ede120d070a7b41ee5",
+ "lbry-redux": "lbryio/lbry-redux#4e093983eaf3d9e7513119657d731b808ead74a6",
"lbryinc": "lbryio/lbryinc#a93596c51c8fb0a226cb84df04c26a6bb60a45fb",
"lint-staged": "^7.0.2",
"localforage": "^1.7.1",
diff --git a/src/ui/analytics.js b/src/ui/analytics.js
index 47e6eeb2f..7aff3a2f5 100644
--- a/src/ui/analytics.js
+++ b/src/ui/analytics.js
@@ -40,7 +40,7 @@ const analytics: Analytics = {
// @endif
},
apiLogView: (uri, outpoint, claimId, timeToStart) => {
- if (analyticsEnabled) {
+ if (analyticsEnabled && isProduction) {
const params: {
uri: string,
outpoint: string,
diff --git a/src/ui/component/fileDownloadLink/view.jsx b/src/ui/component/fileDownloadLink/view.jsx
index f41035954..488be2b3b 100644
--- a/src/ui/component/fileDownloadLink/view.jsx
+++ b/src/ui/component/fileDownloadLink/view.jsx
@@ -23,9 +23,7 @@ function FileDownloadLink(props: Props) {
if (loading || downloading) {
const progress = fileInfo && fileInfo.written_bytes > 0 ? (fileInfo.written_bytes / fileInfo.total_bytes) * 100 : 0;
const label =
- fileInfo && fileInfo.written_bytes > 0
- ? __('Downloading: ') + progress.toFixed(0) + __('% complete')
- : __('Connecting...');
+ fileInfo && fileInfo.written_bytes > 0 ? progress.toFixed(0) + __('% downloaded') : __('Connecting...');
return {label};
}
diff --git a/src/ui/modal/modalRemoveFile/view.jsx b/src/ui/modal/modalRemoveFile/view.jsx
index 9fca2e35a..ccf05e277 100644
--- a/src/ui/modal/modalRemoveFile/view.jsx
+++ b/src/ui/modal/modalRemoveFile/view.jsx
@@ -54,7 +54,7 @@ function ModalRemoveFile(props: Props) {
button="primary"
label={__('OK')}
disabled={!deleteChecked && !abandonChecked}
- onClick={() => deleteFile(outpoint || '', deleteChecked, abandonChecked)}
+ onClick={() => deleteFile(outpoint || '', deleteChecked, claimIsMine ? abandonChecked : false)}
/>
diff --git a/src/ui/redux/actions/file.js b/src/ui/redux/actions/file.js
index 99b95cd7c..5bd4abc75 100644
--- a/src/ui/redux/actions/file.js
+++ b/src/ui/redux/actions/file.js
@@ -5,6 +5,7 @@ import { shell } from 'electron';
import { Lbry, batchActions, doAbandonClaim, selectMyClaimsOutpoints } from 'lbry-redux';
import { doHideModal } from 'redux/actions/app';
import { goBack } from 'connected-react-router';
+import { doSetPlayingUri } from 'redux/actions/content';
export function doOpenFileInFolder(path) {
return () => {
@@ -52,7 +53,9 @@ export function doDeleteFileAndMaybeGoBack(fileInfo, deleteFromComputer, abandon
const actions = [];
actions.push(doHideModal());
actions.push(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim));
+ actions.push(doSetPlayingUri(null));
dispatch(batchActions(...actions));
+
if (abandonClaim) {
dispatch(goBack());
}
diff --git a/src/ui/scss/component/_content.scss b/src/ui/scss/component/_content.scss
index cc59f2bb6..99ad73011 100644
--- a/src/ui/scss/component/_content.scss
+++ b/src/ui/scss/component/_content.scss
@@ -23,6 +23,9 @@
position: relative;
width: 100%;
height: 100%;
+ // display: flex;
+ // flex-direction: column;
+ // justify-content: space-between;
}
.content__wrapper--floating {
@@ -85,11 +88,7 @@
}
.content__loading {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
+ height: 100%;
display: flex;
align-items: center;
flex-direction: column;
diff --git a/yarn.lock b/yarn.lock
index d1ad5cbbf..9d9bc61f7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6762,9 +6762,9 @@ lazy-val@^1.0.3, lazy-val@^1.0.4:
yargs "^13.2.2"
zstd-codec "^0.1.1"
-lbry-redux@lbryio/lbry-redux#58bbdb9a2e537b3994d545ede120d070a7b41ee5:
+lbry-redux@lbryio/lbry-redux#4e093983eaf3d9e7513119657d731b808ead74a6:
version "0.0.1"
- resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/58bbdb9a2e537b3994d545ede120d070a7b41ee5"
+ resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/4e093983eaf3d9e7513119657d731b808ead74a6"
dependencies:
mime "^2.4.4"
proxy-polyfill "0.1.6"
--
2.45.2
From 70fc45464782c80135b80e57890ad2a24ec938a2 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Wed, 14 Aug 2019 00:10:27 -0400
Subject: [PATCH 05/12] v0.35.0-rc.1
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 609de08c9..d9865cae5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "LBRY",
- "version": "0.34.2",
+ "version": "0.35.0-rc.1",
"description": "A browser for the LBRY network, a digital marketplace controlled by its users.",
"keywords": [
"lbry"
--
2.45.2
From e589a872986c42aa7cb1f586207017e74d09573d Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Wed, 14 Aug 2019 12:28:13 -0400
Subject: [PATCH 06/12] add analytics for version/email/reward eligibility
---
package.json | 2 +-
src/ui/analytics.js | 43 +++++++++++++++++++++++---
src/ui/component/app/view.jsx | 24 +++++++++++---
src/ui/component/userEmailNew/view.jsx | 2 ++
yarn.lock | 4 +--
5 files changed, 64 insertions(+), 11 deletions(-)
diff --git a/package.json b/package.json
index d9865cae5..0627fa89e 100644
--- a/package.json
+++ b/package.json
@@ -126,7 +126,7 @@
"json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#4e093983eaf3d9e7513119657d731b808ead74a6",
- "lbryinc": "lbryio/lbryinc#a93596c51c8fb0a226cb84df04c26a6bb60a45fb",
+ "lbryinc": "lbryio/lbryinc#1ce266b3c52654190b955e9c869b8e302aa5c585",
"lint-staged": "^7.0.2",
"localforage": "^1.7.1",
"lodash-es": "^4.17.14",
diff --git a/src/ui/analytics.js b/src/ui/analytics.js
index 7aff3a2f5..373a20ca2 100644
--- a/src/ui/analytics.js
+++ b/src/ui/analytics.js
@@ -3,6 +3,7 @@ import { Lbryio } from 'lbryinc';
import ReactGA from 'react-ga';
import { history } from './store';
// @if TARGET='app'
+import Native from 'native';
import ElectronCookies from '@exponent/electron-cookies';
// @endif
@@ -15,6 +16,9 @@ type Analytics = {
apiLogView: (string, string, string, ?number, ?() => void) => void,
apiLogPublish: () => void,
tagFollowEvent: (string, boolean, string) => void,
+ emailProvidedEvent: () => void,
+ emailVerifiedEvent: () => void,
+ rewardEligibleEvent: () => void,
};
let analyticsEnabled: boolean = true;
@@ -26,11 +30,18 @@ const analytics: Analytics = {
},
setUser: userId => {
if (analyticsEnabled && userId) {
- ReactGA.event({
- category: 'User',
- action: 'userId',
- value: userId,
+ ReactGA.set({
+ userId,
});
+
+ // @if TARGET='app'
+ Native.getAppVersionInfo().then(({ localVersion }) => {
+ ReactGA.event({
+ category: 'Desktop-Version',
+ action: localVersion,
+ });
+ });
+ // @endif
}
},
toggle: (enabled: boolean): void => {
@@ -92,6 +103,30 @@ const analytics: Analytics = {
});
}
},
+ emailProvidedEvent: () => {
+ if (analyticsEnabled && isProduction) {
+ ReactGA.event({
+ category: 'Engagement',
+ action: 'Email-Provided',
+ });
+ }
+ },
+ emailVerifiedEvent: () => {
+ if (analyticsEnabled && isProduction) {
+ ReactGA.event({
+ category: 'Engagement',
+ action: 'Email-Verified',
+ });
+ }
+ },
+ rewardEligibleEvent: () => {
+ if (analyticsEnabled && isProduction) {
+ ReactGA.event({
+ category: 'Engagement',
+ action: 'Reward-Eligible',
+ });
+ }
+ },
};
// Initialize google analytics
diff --git a/src/ui/component/app/view.jsx b/src/ui/component/app/view.jsx
index 80501bce8..b337e9c93 100644
--- a/src/ui/component/app/view.jsx
+++ b/src/ui/component/app/view.jsx
@@ -12,6 +12,7 @@ import useKonamiListener from 'util/enhanced-layout';
import Yrbl from 'component/yrbl';
import FileViewer from 'component/fileViewer';
import { withRouter } from 'react-router';
+import usePrevious from 'util/use-previous';
export const MAIN_WRAPPER_CLASS = 'main-wrapper';
@@ -21,7 +22,7 @@ type Props = {
language: string,
theme: string,
accessToken: ?string,
- user: ?{ id: string, has_verified_email: boolean },
+ user: ?{ id: string, has_verified_email: boolean, is_reward_approved: boolean },
location: { pathname: string },
fetchRewards: () => void,
fetchRewardedContent: () => void,
@@ -35,7 +36,10 @@ function App(props: Props) {
const isEnhancedLayout = useKonamiListener();
const userId = user && user.id;
const hasVerifiedEmail = user && user.has_verified_email;
-
+ const isRewardApproved = user && user.is_reward_approved;
+ const previousUserId = usePrevious(userId);
+ const previousHasVerifiedEmail = usePrevious(hasVerifiedEmail);
+ const previousRewardApproved = usePrevious(isRewardApproved);
const { pathname } = props.location;
const urlParts = pathname.split('/');
const claimName = urlParts[1];
@@ -65,10 +69,22 @@ function App(props: Props) {
}, [theme]);
useEffect(() => {
- if (userId) {
+ if (previousUserId === undefined && userId) {
analytics.setUser(userId);
}
- }, [userId]);
+ }, [previousUserId, userId]);
+
+ useEffect(() => {
+ if (previousHasVerifiedEmail !== undefined && hasVerifiedEmail) {
+ analytics.emailVerifiedEvent();
+ }
+ }, [previousHasVerifiedEmail, hasVerifiedEmail]);
+
+ useEffect(() => {
+ if (previousRewardApproved !== undefined && isRewardApproved) {
+ analytics.rewardEligibleEvent();
+ }
+ }, [previousRewardApproved, isRewardApproved]);
// @if TARGET='web'
useEffect(() => {
diff --git a/src/ui/component/userEmailNew/view.jsx b/src/ui/component/userEmailNew/view.jsx
index 4e8129c71..0fe2f8b62 100644
--- a/src/ui/component/userEmailNew/view.jsx
+++ b/src/ui/component/userEmailNew/view.jsx
@@ -3,6 +3,7 @@ import * as React from 'react';
import { FormField, Form } from 'component/common/form';
import Button from 'component/button';
import { Lbryio } from 'lbryinc';
+import analytics from 'analytics';
type Props = {
cancelButton: React.Node,
@@ -37,6 +38,7 @@ class UserEmailNew extends React.PureComponent {
const { email } = this.state;
const { addUserEmail } = this.props;
addUserEmail(email);
+ analytics.emailProvidedEvent();
// @if TARGET='web'
Lbryio.call('user_tag', 'edit', { add: 'lbrytv' });
diff --git a/yarn.lock b/yarn.lock
index 9d9bc61f7..0b78fb183 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6771,9 +6771,9 @@ lbry-redux@lbryio/lbry-redux#4e093983eaf3d9e7513119657d731b808ead74a6:
reselect "^3.0.0"
uuid "^3.3.2"
-lbryinc@lbryio/lbryinc#a93596c51c8fb0a226cb84df04c26a6bb60a45fb:
+lbryinc@lbryio/lbryinc#1ce266b3c52654190b955e9c869b8e302aa5c585:
version "0.0.1"
- resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/a93596c51c8fb0a226cb84df04c26a6bb60a45fb"
+ resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/1ce266b3c52654190b955e9c869b8e302aa5c585"
dependencies:
reselect "^3.0.0"
--
2.45.2
From 3c39dbf01e682cadc4f7d4ef1235f42f3b42dbf2 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Wed, 14 Aug 2019 12:31:34 -0400
Subject: [PATCH 07/12] disable user drag on links and images
---
src/ui/scss/init/_gui.scss | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/ui/scss/init/_gui.scss b/src/ui/scss/init/_gui.scss
index afb5685ca..018172e55 100644
--- a/src/ui/scss/init/_gui.scss
+++ b/src/ui/scss/init/_gui.scss
@@ -98,6 +98,11 @@ hr {
}
}
+img,
+a {
+ -webkit-user-drag: none;
+}
+
.columns {
display: flex;
justify-content: space-between;
--
2.45.2
From c20f491457a1358182fd68cead6fce041fffd389 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Wed, 14 Aug 2019 14:09:45 -0400
Subject: [PATCH 08/12] cleanup
---
package.json | 2 +-
src/ui/component/common/icon.jsx | 2 +-
src/ui/component/fileDetails/view.jsx | 1 +
src/ui/component/fileProperties/index.js | 4 ++--
src/ui/redux/selectors/subscriptions.js | 6 +++++-
src/ui/scss/component/_button.scss | 10 ++++++++++
src/ui/scss/component/_content.scss | 3 ---
src/ui/scss/component/_file-render.scss | 7 +++++++
yarn.lock | 4 ++--
9 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/package.json b/package.json
index 0627fa89e..6e250b5ad 100644
--- a/package.json
+++ b/package.json
@@ -125,7 +125,7 @@
"jsmediatags": "^3.8.1",
"json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git",
- "lbry-redux": "lbryio/lbry-redux#4e093983eaf3d9e7513119657d731b808ead74a6",
+ "lbry-redux": "lbryio/lbry-redux#1bd625f0c6e9e36d14eb0c520a3eb99f9600705d",
"lbryinc": "lbryio/lbryinc#1ce266b3c52654190b955e9c869b8e302aa5c585",
"lint-staged": "^7.0.2",
"localforage": "^1.7.1",
diff --git a/src/ui/component/common/icon.jsx b/src/ui/component/common/icon.jsx
index 480bc47f8..75e66b091 100644
--- a/src/ui/component/common/icon.jsx
+++ b/src/ui/component/common/icon.jsx
@@ -25,7 +25,7 @@ class IconComponent extends React.PureComponent {
case ICONS.FEATURED:
return __('Featured content. Earn rewards for watching.');
case ICONS.DOWNLOAD:
- return __('This file is downloaded.');
+ return __('This file is in your library.');
case ICONS.SUBSCRIBE:
return __('You are subscribed to this channel.');
case ICONS.SETTINGS:
diff --git a/src/ui/component/fileDetails/view.jsx b/src/ui/component/fileDetails/view.jsx
index 72cc8a869..8682359d5 100644
--- a/src/ui/component/fileDetails/view.jsx
+++ b/src/ui/component/fileDetails/view.jsx
@@ -77,6 +77,7 @@ class FileDetails extends PureComponent {
{': '}
-
diff --git a/src/ui/redux/actions/file.js b/src/ui/redux/actions/file.js
index 5bd4abc75..82f139f2f 100644
--- a/src/ui/redux/actions/file.js
+++ b/src/ui/redux/actions/file.js
@@ -2,10 +2,11 @@ import * as ACTIONS from 'constants/action_types';
// @if TARGET='app'
import { shell } from 'electron';
// @endif
-import { Lbry, batchActions, doAbandonClaim, selectMyClaimsOutpoints } from 'lbry-redux';
+import { Lbry, batchActions, doAbandonClaim, selectMyClaimsOutpoints, makeSelectFileInfoForUri } from 'lbry-redux';
import { doHideModal } from 'redux/actions/app';
import { goBack } from 'connected-react-router';
import { doSetPlayingUri } from 'redux/actions/content';
+import { selectPlayingUri } from 'redux/selectors/content';
export function doOpenFileInFolder(path) {
return () => {
@@ -48,16 +49,23 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
};
}
-export function doDeleteFileAndMaybeGoBack(fileInfo, deleteFromComputer, abandonClaim) {
- return dispatch => {
+export function doDeleteFileAndMaybeGoBack(uri, deleteFromComputer, abandonClaim) {
+ return (dispatch, getState) => {
+ const state = getState();
+ const playingUri = selectPlayingUri(state);
+ const { outpoint } = makeSelectFileInfoForUri(uri)(state);
const actions = [];
actions.push(doHideModal());
- actions.push(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim));
- actions.push(doSetPlayingUri(null));
- dispatch(batchActions(...actions));
+ actions.push(doDeleteFile(outpoint, deleteFromComputer, abandonClaim));
+
+ if (playingUri === uri) {
+ actions.push(doSetPlayingUri(null));
+ }
if (abandonClaim) {
- dispatch(goBack());
+ actions.push(goBack());
}
+
+ dispatch(batchActions(...actions));
};
}
diff --git a/src/ui/util/use-persisted-state.js b/src/ui/util/use-persisted-state.js
index ad63a6127..466572eb2 100644
--- a/src/ui/util/use-persisted-state.js
+++ b/src/ui/util/use-persisted-state.js
@@ -12,7 +12,7 @@ export default function usePersistedState(key, firstTimeDefault) {
parsedItem = JSON.parse(item);
} catch (e) {}
- if (parsedItem) {
+ if (parsedItem !== undefined) {
defaultValue = parsedItem;
} else {
defaultValue = item;
--
2.45.2
From 88cd024c8c5f614bea828e9bd1e289056072f4e7 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Wed, 14 Aug 2019 23:09:34 -0400
Subject: [PATCH 12/12] cleanup reactGA events
---
src/ui/analytics.js | 51 ++++++++++++-----------------------
src/ui/component/app/view.jsx | 2 ++
2 files changed, 19 insertions(+), 34 deletions(-)
diff --git a/src/ui/analytics.js b/src/ui/analytics.js
index 373a20ca2..1806e40b1 100644
--- a/src/ui/analytics.js
+++ b/src/ui/analytics.js
@@ -36,10 +36,7 @@ const analytics: Analytics = {
// @if TARGET='app'
Native.getAppVersionInfo().then(({ localVersion }) => {
- ReactGA.event({
- category: 'Desktop-Version',
- action: localVersion,
- });
+ sendGaEvent('Desktop-Version', localVersion);
});
// @endif
}
@@ -88,47 +85,31 @@ const analytics: Analytics = {
}
},
tagFollowEvent: (tag, following, location) => {
- if (analyticsEnabled) {
- ReactGA.event({
- category: following ? 'Tag-Follow' : 'Tag-Unfollow',
- action: tag,
- });
- }
+ sendGaEvent(following ? 'Tag-Follow' : 'Tag-Unfollow', tag);
},
channelBlockEvent: (uri, blocked, location) => {
- if (analyticsEnabled) {
- ReactGA.event({
- category: blocked ? 'Channel-Hidden' : 'Channel-Unhidden',
- action: uri,
- });
- }
+ sendGaEvent(blocked ? 'Channel-Hidden' : 'Channel-Unhidden', uri);
},
emailProvidedEvent: () => {
- if (analyticsEnabled && isProduction) {
- ReactGA.event({
- category: 'Engagement',
- action: 'Email-Provided',
- });
- }
+ sendGaEvent('Engagement', 'Email-Provided');
},
emailVerifiedEvent: () => {
- if (analyticsEnabled && isProduction) {
- ReactGA.event({
- category: 'Engagement',
- action: 'Email-Verified',
- });
- }
+ sendGaEvent('Engagement', 'Email-Verified');
},
rewardEligibleEvent: () => {
- if (analyticsEnabled && isProduction) {
- ReactGA.event({
- category: 'Engagement',
- action: 'Reward-Eligible',
- });
- }
+ sendGaEvent('Engagement', 'Reward-Eligible');
},
};
+function sendGaEvent(category, action) {
+ if (analyticsEnabled && isProduction) {
+ ReactGA.event({
+ category,
+ action,
+ });
+ }
+}
+
// Initialize google analytics
// Set `debug: true` for debug info
// Will change once we have separate ids for desktop/web
@@ -143,6 +124,8 @@ ElectronCookies.enable({
ReactGA.initialize(UA_ID, {
testMode: process.env.NODE_ENV !== 'production',
cookieDomain: 'auto',
+ // un-comment to see events as they are sent to google
+ // debug: true,
});
// Manually call the first page view
diff --git a/src/ui/component/app/view.jsx b/src/ui/component/app/view.jsx
index b337e9c93..6740470de 100644
--- a/src/ui/component/app/view.jsx
+++ b/src/ui/component/app/view.jsx
@@ -75,6 +75,8 @@ function App(props: Props) {
}, [previousUserId, userId]);
useEffect(() => {
+ // Check that previousHasVerifiedEmail was not undefined instead of just not truthy
+ // This ensures we don't fire the emailVerified event on the initial user fetch
if (previousHasVerifiedEmail !== undefined && hasVerifiedEmail) {
analytics.emailVerifiedEvent();
}
--
2.45.2