From ed2fe16f45c96bb95376e4bab0912eccded8ef53 Mon Sep 17 00:00:00 2001
From: Daniel Dominguez
Date: Wed, 16 May 2018 18:34:07 -0300
Subject: [PATCH 01/34] Add right click context menu on all text inputs.
---
src/renderer/index.js | 3 ++
src/renderer/util/contextMenu.js | 65 ++++++++++++++++++++++++++++++++
2 files changed, 68 insertions(+)
create mode 100644 src/renderer/util/contextMenu.js
diff --git a/src/renderer/index.js b/src/renderer/index.js
index c82db3287..fe0b9e695 100644
--- a/src/renderer/index.js
+++ b/src/renderer/index.js
@@ -16,6 +16,7 @@ import 'scss/all.scss';
import store from 'store';
import app from './app';
import analytics from './analytics';
+import getMenu from './util/contextMenu';
const { autoUpdater } = remote.require('electron-updater');
@@ -95,6 +96,8 @@ document.addEventListener('click', event => {
}
});
+document.addEventListener('contextmenu', getMenu);
+
const init = () => {
autoUpdater.on('update-downloaded', () => {
app.store.dispatch(doAutoUpdate());
diff --git a/src/renderer/util/contextMenu.js b/src/renderer/util/contextMenu.js
new file mode 100644
index 000000000..0348423bf
--- /dev/null
+++ b/src/renderer/util/contextMenu.js
@@ -0,0 +1,65 @@
+import { clipboard, remote } from 'electron';
+import isDev from 'electron-is-dev';
+
+function textInputTemplate(target) {
+ const somethingSelected = target.selectionStart < target.selectionEnd;
+ const hasValue = target.value.length > 0;
+
+ // Native Electron selectAll role does not work
+ function selectAll() {
+ target.selectionStart = 0;
+ target.selectionEnd = target.value.length + 1;
+ }
+
+ const template = [
+ { label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut', enabled: somethingSelected },
+ { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy', enabled: somethingSelected },
+ {
+ label: 'Paste',
+ accelerator: 'CmdOrCtrl+V',
+ role: 'paste',
+ enabled: clipboard.readText().length > 0,
+ },
+ {
+ label: 'Select All',
+ accelerator: 'CmdOrCtrl+A',
+ role: 'selectAll',
+ enabled: hasValue,
+ click: selectAll,
+ },
+ ];
+
+ return template;
+}
+
+function getTemplate(target) {
+ const { type } = target;
+ if (target.matches('input') && (type === 'text' || type === 'number')) {
+ return textInputTemplate(target);
+ }
+ return [];
+}
+
+export default event => {
+ event.preventDefault();
+ const { target } = event;
+ const template = getTemplate(target);
+ if (isDev) {
+ const { screenX, screenY } = event;
+ const separator = { type: 'separator' };
+ const developmentTemplateAddition = [
+ {
+ label: 'Inspect element',
+ accelerator: 'CmdOrCtrl+Shift+I',
+ click: () => {
+ remote.getCurrentWindow().inspectElement(screenX, screenY);
+ },
+ },
+ ];
+ if (template.length > 0) {
+ template.push(separator);
+ }
+ template.push(...developmentTemplateAddition);
+ }
+ remote.Menu.buildFromTemplate(template).popup();
+};
From 86876d6a1982e55c0856efc9f6944d0113ea7417 Mon Sep 17 00:00:00 2001
From: Daniel Dominguez
Date: Sun, 20 May 2018 22:00:59 -0300
Subject: [PATCH 02/34] Add context menu helper to be able to modify the menu
templates in react way and not be static.
---
src/main/createWindow.js | 2 -
src/main/menu/setupContextMenu.js | 27 ------
src/renderer/component/fileCard/view.jsx | 5 ++
src/renderer/index.js | 6 +-
src/renderer/util/contextMenu.js | 107 ++++++++++++-----------
5 files changed, 63 insertions(+), 84 deletions(-)
delete mode 100644 src/main/menu/setupContextMenu.js
diff --git a/src/main/createWindow.js b/src/main/createWindow.js
index 738ab792a..764003c65 100644
--- a/src/main/createWindow.js
+++ b/src/main/createWindow.js
@@ -3,7 +3,6 @@ import isDev from 'electron-is-dev';
import windowStateKeeper from 'electron-window-state';
import setupBarMenu from './menu/setupBarMenu';
-import setupContextMenu from './menu/setupContextMenu';
export default appState => {
// Get primary display dimensions from Electron.
@@ -73,7 +72,6 @@ export default appState => {
}
setupBarMenu();
- setupContextMenu(window);
window.on('close', event => {
if (!appState.isQuitting && !appState.autoUpdateAccepted) {
diff --git a/src/main/menu/setupContextMenu.js b/src/main/menu/setupContextMenu.js
deleted file mode 100644
index 658ac731a..000000000
--- a/src/main/menu/setupContextMenu.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// @flow
-import { Menu, BrowserWindow } from 'electron';
-import isDev from 'electron-is-dev';
-
-export default (rendererWindow: BrowserWindow) => {
- rendererWindow.webContents.on('context-menu', (e, params) => {
- const { x, y } = params;
-
- const template = [{ role: 'cut' }, { role: 'copy' }, { role: 'paste' }];
-
- const developmentTemplateAddition = [
- { type: 'separator' },
- {
- label: 'Inspect element',
- click: () => {
- rendererWindow.inspectElement(x, y);
- },
- },
- ];
-
- if (isDev) {
- template.push(...developmentTemplateAddition);
- }
-
- Menu.buildFromTemplate(template).popup();
- });
-};
diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx
index 88bb99946..6fc765633 100644
--- a/src/renderer/component/fileCard/view.jsx
+++ b/src/renderer/component/fileCard/view.jsx
@@ -9,6 +9,7 @@ import FilePrice from 'component/filePrice';
import UriIndicator from 'component/uriIndicator';
import * as icons from 'constants/icons';
import classnames from 'classnames';
+import { openCopyLinkMenu } from '../../util/contextMenu';
// TODO: iron these out
type Props = {
@@ -60,6 +61,9 @@ class FileCard extends React.PureComponent {
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw;
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
+ const handleContextMenu = event => {
+ openCopyLinkMenu(uri, event);
+ };
// We should be able to tab through cards
/* eslint-disable jsx-a11y/click-events-have-key-events */
@@ -72,6 +76,7 @@ class FileCard extends React.PureComponent {
'card--link': !pending,
'card--pending': pending,
})}
+ onContextMenu={handleContextMenu}
>
{showPrice && }
diff --git a/src/renderer/index.js b/src/renderer/index.js
index fe0b9e695..c19790f06 100644
--- a/src/renderer/index.js
+++ b/src/renderer/index.js
@@ -16,7 +16,7 @@ import 'scss/all.scss';
import store from 'store';
import app from './app';
import analytics from './analytics';
-import getMenu from './util/contextMenu';
+import { initContextMenu } from './util/contextMenu';
const { autoUpdater } = remote.require('electron-updater');
@@ -96,7 +96,7 @@ document.addEventListener('click', event => {
}
});
-document.addEventListener('contextmenu', getMenu);
+document.addEventListener('contextmenu', initContextMenu);
const init = () => {
autoUpdater.on('update-downloaded', () => {
@@ -132,7 +132,7 @@ const init = () => {
ReactDOM.render(
-
+
openContextMenu(e)} />
,
diff --git a/src/renderer/util/contextMenu.js b/src/renderer/util/contextMenu.js
index 0348423bf..79f47da5b 100644
--- a/src/renderer/util/contextMenu.js
+++ b/src/renderer/util/contextMenu.js
@@ -1,65 +1,68 @@
import { clipboard, remote } from 'electron';
import isDev from 'electron-is-dev';
-function textInputTemplate(target) {
- const somethingSelected = target.selectionStart < target.selectionEnd;
- const hasValue = target.value.length > 0;
-
- // Native Electron selectAll role does not work
- function selectAll() {
- target.selectionStart = 0;
- target.selectionEnd = target.value.length + 1;
- }
-
- const template = [
- { label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut', enabled: somethingSelected },
- { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy', enabled: somethingSelected },
+function injectDevelopmentTemplate(event, templates) {
+ if (!isDev) return templates;
+ const { screenX, screenY } = event;
+ const separator = { type: 'separator' };
+ const developmentTemplateAddition = [
{
- label: 'Paste',
- accelerator: 'CmdOrCtrl+V',
- role: 'paste',
- enabled: clipboard.readText().length > 0,
- },
- {
- label: 'Select All',
- accelerator: 'CmdOrCtrl+A',
- role: 'selectAll',
- enabled: hasValue,
- click: selectAll,
+ label: 'Inspect element',
+ accelerator: 'CmdOrCtrl+Shift+I',
+ click: () => {
+ remote.getCurrentWindow().inspectElement(screenX, screenY);
+ },
},
];
-
- return template;
-}
-
-function getTemplate(target) {
- const { type } = target;
- if (target.matches('input') && (type === 'text' || type === 'number')) {
- return textInputTemplate(target);
+ if (templates.length > 0) {
+ templates.push(separator);
}
- return [];
+ templates.push(...developmentTemplateAddition);
+ return templates;
}
-export default event => {
- event.preventDefault();
- const { target } = event;
- const template = getTemplate(target);
- if (isDev) {
- const { screenX, screenY } = event;
- const separator = { type: 'separator' };
- const developmentTemplateAddition = [
+export function openContextMenu(event, templates = [], addDefaultTemplates = true) {
+ if (addDefaultTemplates) {
+ const { value } = event.target;
+ const inputTemplates = [
+ { label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut' },
+ { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' },
{
- label: 'Inspect element',
- accelerator: 'CmdOrCtrl+Shift+I',
- click: () => {
- remote.getCurrentWindow().inspectElement(screenX, screenY);
- },
+ label: 'Paste',
+ accelerator: 'CmdOrCtrl+V',
+ role: 'paste',
+ enabled: clipboard.readText().length > 0,
+ },
+ {
+ label: 'Select All',
+ accelerator: 'CmdOrCtrl+A',
+ role: 'selectall',
+ enabled: !!value,
},
];
- if (template.length > 0) {
- template.push(separator);
- }
- template.push(...developmentTemplateAddition);
+ templates.push(...inputTemplates);
}
- remote.Menu.buildFromTemplate(template).popup();
-};
+
+ injectDevelopmentTemplate(event, templates);
+ remote.Menu.buildFromTemplate(templates).popup();
+}
+export function openCopyLinkMenu(text, event) {
+ const templates = [
+ {
+ label: 'Copy link',
+ click: () => {
+ clipboard.writeText(text);
+ },
+ },
+ ];
+ openContextMenu(event, templates, false);
+}
+
+export function initContextMenu(event) {
+ const { type } = event.target;
+ if (event.target.matches('input') && (type === 'text' || type === 'number')) {
+ openContextMenu(event);
+ } else {
+ event.preventDefault();
+ }
+}
From b4542517def09c07b423700fad15208b4f445cb0 Mon Sep 17 00:00:00 2001
From: Daniel Dominguez
Date: Mon, 21 May 2018 14:18:02 -0300
Subject: [PATCH 03/34] Correctly copy an URI so it can be opened with lbry-app
when shared.
---
src/renderer/component/fileCard/view.jsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx
index 6fc765633..818d8cd4a 100644
--- a/src/renderer/component/fileCard/view.jsx
+++ b/src/renderer/component/fileCard/view.jsx
@@ -1,6 +1,6 @@
// @flow
import * as React from 'react';
-import { normalizeURI } from 'lbry-redux';
+import { normalizeURI, convertToShareLink } from 'lbry-redux';
import Button from 'component/button';
import CardMedia from 'component/cardMedia';
import TruncatedText from 'component/common/truncated-text';
@@ -62,7 +62,7 @@ class FileCard extends React.PureComponent {
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw;
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
const handleContextMenu = event => {
- openCopyLinkMenu(uri, event);
+ openCopyLinkMenu(convertToShareLink(uri), event);
};
// We should be able to tab through cards
From f54a24309e7320db1af59a3969cfb940aae23b78 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Wed, 23 May 2018 00:35:34 -0400
Subject: [PATCH 04/34] fix: use short form uri when preparingEdit so users
know they are editing
---
src/renderer/page/file/view.jsx | 10 +++++++++-
src/renderer/redux/reducers/navigation.js | 2 +-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/renderer/page/file/view.jsx b/src/renderer/page/file/view.jsx
index bf7c34846..5ebe44876 100644
--- a/src/renderer/page/file/view.jsx
+++ b/src/renderer/page/file/view.jsx
@@ -129,6 +129,14 @@ class FilePage extends React.Component {
subscriptionUri = buildURI({ channelName, claimId: channelClaimId }, false);
}
+ // We want to use the short form uri for editing
+ // This is what the user is used to seeing, they don't care about the claim id
+ // We will select the claim id before they publish
+ let editUri;
+ if (claimIsMine) {
+ editUri = buildURI({ channelName, contentName: claim.name });
+ }
+
const isPlaying = playingUri === uri && !isPaused;
return (
@@ -170,7 +178,7 @@ class FilePage extends React.Component {
icon={icons.EDIT}
label={__('Edit')}
onClick={() => {
- prepareEdit(claim, uri);
+ prepareEdit(claim, editUri);
navigate('/publish');
}}
/>
diff --git a/src/renderer/redux/reducers/navigation.js b/src/renderer/redux/reducers/navigation.js
index e4544b4cc..80a5e0259 100644
--- a/src/renderer/redux/reducers/navigation.js
+++ b/src/renderer/redux/reducers/navigation.js
@@ -3,7 +3,7 @@ import * as ACTIONS from 'constants/action_types';
const getCurrentPath = () => {
const { hash } = document.location;
if (hash !== '') return hash.replace(/^#/, '');
- return '/discover';
+ return '/publish';
};
const reducers = {};
From 8ca6e21969e5c081a553371b4ab2683f82932968 Mon Sep 17 00:00:00 2001
From: Daniel Dominguez
Date: Wed, 23 May 2018 16:30:45 -0300
Subject: [PATCH 05/34] Allow https to follow redirections when requesting
latest release data from github.
---
src/main/index.js | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/src/main/index.js b/src/main/index.js
index 2591e20f6..276212b59 100644
--- a/src/main/index.js
+++ b/src/main/index.js
@@ -176,11 +176,11 @@ ipcMain.on('version-info-requested', () => {
},
};
let result = '';
-
- const req = https.get(Object.assign(opts, url.parse(latestReleaseAPIURL)), res => {
+ const onSuccess = res => {
res.on('data', data => {
result += data;
});
+
res.on('end', () => {
const tagName = JSON.parse(result).tag_name;
const [, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
@@ -199,14 +199,27 @@ ipcMain.on('version-info-requested', () => {
}
}
});
- });
+ };
- req.on('error', err => {
- console.log('Failed to get current version from GitHub. Error:', err);
- if (rendererWindow) {
- rendererWindow.webContents.send('version-info-received', null);
- }
- });
+ const requestLatestRelease = (apiUrl, alreadyRedirected = false) => {
+ const req = https.get(Object.assign(opts, url.parse(apiUrl)), res => {
+ if (res.statusCode === 301 || res.statusCode === 302) {
+ requestLatestRelease(res.headers.location, true);
+ } else {
+ onSuccess(res);
+ }
+ });
+
+ if (alreadyRedirected) return;
+ req.on('error', err => {
+ console.log('Failed to get current version from GitHub. Error:', err);
+ if (rendererWindow) {
+ rendererWindow.webContents.send('version-info-received', null);
+ }
+ });
+ };
+
+ requestLatestRelease(latestReleaseAPIURL);
});
ipcMain.on('get-auth-token', event => {
From bd3936fc2be14c89c559b6ea16e9c842acb73393 Mon Sep 17 00:00:00 2001
From: Travis Eden
Date: Tue, 15 May 2018 19:01:53 -0400
Subject: [PATCH 06/34] publish by channel_id rather than channel_name
---
src/renderer/component/publishForm/view.jsx | 17 ++++++++++-------
src/renderer/page/publish/index.js | 2 ++
src/renderer/redux/actions/publish.js | 5 ++---
src/renderer/redux/reducers/publish.js | 4 ++++
4 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/src/renderer/component/publishForm/view.jsx b/src/renderer/component/publishForm/view.jsx
index ff3850a2c..e93ebb95d 100644
--- a/src/renderer/component/publishForm/view.jsx
+++ b/src/renderer/component/publishForm/view.jsx
@@ -29,6 +29,8 @@ type Props = {
currency: string,
},
channel: string,
+ channelId: ?string,
+ myChannels: Array<{ name: string }>,
name: ?string,
tosAccepted: boolean,
updatePublishForm: UpdatePublishFormData => void,
@@ -137,13 +139,14 @@ class PublishForm extends React.PureComponent {
}
handleChannelChange(channelName: string) {
- const { name, updatePublishForm } = this.props;
+ const { name, updatePublishForm, myChannels } = this.props;
+ const form = { channel: channelName };
+ const namedChannelClaim = myChannels.find(channel => channel.name === channelName);
+ form.channelId = namedChannelClaim ? namedChannelClaim.claim_id : '';
if (name) {
- const uri = this.getNewUri(name, channelName);
- updatePublishForm({ channel: channelName, uri });
- } else {
- updatePublishForm({ channel: channelName });
+ form.uri = this.getNewUri(name, channelName);
}
+ updatePublishForm(form);
}
handleBidChange(bid: number) {
@@ -183,7 +186,7 @@ class PublishForm extends React.PureComponent {
description,
language,
nsfw,
- channel,
+ channelId,
licenseType,
licenseUrl,
otherLicenseDescription,
@@ -217,7 +220,7 @@ class PublishForm extends React.PureComponent {
description,
language,
nsfw,
- channel,
+ channelId,
license: publishingLicense,
licenseUrl: publishingLicenseUrl,
otherLicenseDescription,
diff --git a/src/renderer/page/publish/index.js b/src/renderer/page/publish/index.js
index 864ab0df5..78950abe7 100644
--- a/src/renderer/page/publish/index.js
+++ b/src/renderer/page/publish/index.js
@@ -35,6 +35,7 @@ const select = (state, props) => {
const claimsByUri = selectClaimsByUri(state);
const myClaims = selectMyClaims(state);
+ const myChannels = selectMyChannelClaims(state);
const claimForUri = claimsByUri[uri];
let winningBidForClaimUri;
@@ -50,6 +51,7 @@ const select = (state, props) => {
claimForUri,
winningBidForClaimUri,
myClaimForUri,
+ myChannels,
costInfo: makeSelectCostInfoForUri(props.uri)(state),
balance: selectBalance(state),
};
diff --git a/src/renderer/redux/actions/publish.js b/src/renderer/redux/actions/publish.js
index 2981299fc..270f156b4 100644
--- a/src/renderer/redux/actions/publish.js
+++ b/src/renderer/redux/actions/publish.js
@@ -6,7 +6,6 @@ import type {
UpdatePublishFormAction,
PublishParams,
} from 'redux/reducers/publish';
-import { CHANNEL_NEW, CHANNEL_ANONYMOUS } from 'constants/claim';
type Action = UpdatePublishFormAction | { type: ACTIONS.CLEAR_PUBLISH };
type PromiseAction = Promise;
@@ -86,6 +85,7 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat
thumbnail,
nsfw,
channel,
+ channelId,
title,
contentIsFree,
price,
@@ -104,7 +104,6 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat
}
}
- const channelName = channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW ? '' : channel;
const fee = contentIsFree || !price.amount ? undefined : { ...price };
const metadata = {
@@ -126,7 +125,7 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat
const publishPayload = {
name,
- channel_name: channelName,
+ channel_id: channelId,
bid,
metadata,
};
diff --git a/src/renderer/redux/reducers/publish.js b/src/renderer/redux/reducers/publish.js
index d20505598..048ca4ac5 100644
--- a/src/renderer/redux/reducers/publish.js
+++ b/src/renderer/redux/reducers/publish.js
@@ -18,6 +18,7 @@ type PublishState = {
language: string,
tosAccepted: boolean,
channel: string,
+ channelId: ?string,
name: string,
nameError: ?string,
bid: number,
@@ -41,6 +42,7 @@ export type UpdatePublishFormData = {
language?: string,
tosAccepted?: boolean,
channel?: string,
+ channelId?: string,
name?: string,
nameError?: string,
bid?: number,
@@ -66,6 +68,7 @@ export type PublishParams = {
thumbnail: ?string,
nsfw: boolean,
channel: string,
+ channelId: string,
title: string,
contentIsFree: boolean,
uri: string,
@@ -97,6 +100,7 @@ const defaultState: PublishState = {
language: 'en',
nsfw: false,
channel: CHANNEL_ANONYMOUS,
+ channelId: '',
tosAccepted: false,
name: '',
nameError: undefined,
From 938a8e1b7e6d1dc3f80e5d7cd1f981640717f0ca Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Wed, 23 May 2018 00:35:34 -0400
Subject: [PATCH 07/34] allow channels on Discover page
---
src/renderer/component/categoryList/index.js | 18 +++++++++++++
.../view.jsx} | 27 +++++++++++++++++--
src/renderer/page/discover/view.jsx | 8 ++++--
src/renderer/page/file/view.jsx | 10 ++++++-
src/renderer/redux/actions/content.js | 8 +++---
5 files changed, 62 insertions(+), 9 deletions(-)
create mode 100644 src/renderer/component/categoryList/index.js
rename src/renderer/component/{common/category-list.jsx => categoryList/view.jsx} (91%)
diff --git a/src/renderer/component/categoryList/index.js b/src/renderer/component/categoryList/index.js
new file mode 100644
index 000000000..7e728b9f4
--- /dev/null
+++ b/src/renderer/component/categoryList/index.js
@@ -0,0 +1,18 @@
+import { connect } from 'react-redux';
+import { doFetchClaimsByChannel } from 'redux/actions/content';
+import {
+ makeSelectClaimsInChannelForCurrentPage,
+ makeSelectFetchingChannelClaims,
+} from 'lbry-redux';
+import CategoryList from './view';
+
+const select = (state, props) => ({
+ channelClaims: makeSelectClaimsInChannelForCurrentPage(props.categoryLink)(state),
+ fetching: makeSelectFetchingChannelClaims(props.categoryLink)(state),
+});
+
+const perform = dispatch => ({
+ fetchChannel: channel => dispatch(doFetchClaimsByChannel(channel)),
+});
+
+export default connect(select, perform)(CategoryList);
diff --git a/src/renderer/component/common/category-list.jsx b/src/renderer/component/categoryList/view.jsx
similarity index 91%
rename from src/renderer/component/common/category-list.jsx
rename to src/renderer/component/categoryList/view.jsx
index 4b1589cee..0afa57940 100644
--- a/src/renderer/component/common/category-list.jsx
+++ b/src/renderer/component/categoryList/view.jsx
@@ -5,11 +5,15 @@ import ToolTip from 'component/common/tooltip';
import FileCard from 'component/fileCard';
import Button from 'component/button';
import * as icons from 'constants/icons';
+import Claim from 'types/claim';
type Props = {
category: string,
names: Array,
- categoryLink?: string,
+ categoryLink: ?string,
+ fetching: boolean,
+ channelClaims: Array,
+ fetchChannel: string => void,
};
type State = {
@@ -18,6 +22,11 @@ type State = {
};
class CategoryList extends React.PureComponent {
+ static defaultProps = {
+ names: [],
+ categoryLink: '',
+ };
+
constructor() {
super();
@@ -32,6 +41,11 @@ class CategoryList extends React.PureComponent {
}
componentDidMount() {
+ const { fetching, categoryLink, fetchChannel } = this.props;
+ if (!fetching) {
+ fetchChannel(categoryLink);
+ }
+
const cardRow = this.rowItems;
if (cardRow) {
const cards = cardRow.getElementsByTagName('section');
@@ -109,6 +123,9 @@ class CategoryList extends React.PureComponent {
// check if a card is fully visible horizontally
isCardVisible = (section: HTMLElement) => {
+ if (!section) {
+ return false;
+ }
const rect = section.getBoundingClientRect();
const isVisible = rect.left >= 0 && rect.right <= window.innerWidth;
return isVisible;
@@ -189,7 +206,7 @@ class CategoryList extends React.PureComponent {
}
render() {
- const { category, names, categoryLink } = this.props;
+ const { category, categoryLink, names, channelClaims } = this.props;
const { canScrollNext, canScrollPrevious } = this.state;
// The lint was throwing an error saying we should use instead of
@@ -235,6 +252,12 @@ class CategoryList extends React.PureComponent {
className="card-row__scrollhouse"
>
{names && names.map(name => )}
+
+ {channelClaims && channelClaims.length
+ ? channelClaims.map(claim => (
+
+ ))
+ : null}
);
diff --git a/src/renderer/page/discover/view.jsx b/src/renderer/page/discover/view.jsx
index 28adf330c..123992dc8 100644
--- a/src/renderer/page/discover/view.jsx
+++ b/src/renderer/page/discover/view.jsx
@@ -1,7 +1,7 @@
// @flow
import React from 'react';
import Page from 'component/page';
-import CategoryList from 'component/common/category-list';
+import CategoryList from 'component/categoryList';
type Props = {
fetchFeaturedUris: () => void,
@@ -27,7 +27,11 @@ class DiscoverPage extends React.PureComponent {
featuredUris[category].length ? (
) : (
- ''
+
)
)}
{failedToLoad && {__('Failed to load landing content.')}
}
diff --git a/src/renderer/page/file/view.jsx b/src/renderer/page/file/view.jsx
index bf7c34846..5ebe44876 100644
--- a/src/renderer/page/file/view.jsx
+++ b/src/renderer/page/file/view.jsx
@@ -129,6 +129,14 @@ class FilePage extends React.Component {
subscriptionUri = buildURI({ channelName, claimId: channelClaimId }, false);
}
+ // We want to use the short form uri for editing
+ // This is what the user is used to seeing, they don't care about the claim id
+ // We will select the claim id before they publish
+ let editUri;
+ if (claimIsMine) {
+ editUri = buildURI({ channelName, contentName: claim.name });
+ }
+
const isPlaying = playingUri === uri && !isPaused;
return (
@@ -170,7 +178,7 @@ class FilePage extends React.Component {
icon={icons.EDIT}
label={__('Edit')}
onClick={() => {
- prepareEdit(claim, uri);
+ prepareEdit(claim, editUri);
navigate('/publish');
}}
/>
diff --git a/src/renderer/redux/actions/content.js b/src/renderer/redux/actions/content.js
index 8dae86f8f..7278beb3d 100644
--- a/src/renderer/redux/actions/content.js
+++ b/src/renderer/redux/actions/content.js
@@ -42,10 +42,10 @@ export function doFetchFeaturedUris() {
});
const success = ({ Uris }) => {
- let urisToResolve = [];
- Object.keys(Uris).forEach(category => {
- urisToResolve = [...urisToResolve, ...Uris[category]];
- });
+ const urisToResolve = Object.keys(Uris).reduce(
+ (resolve, category) => [...resolve, ...Uris[category]],
+ []
+ );
const actions = [
doResolveUris(urisToResolve),
From c0e6de66a4266cd28b26ef9d4c00a2c081a49698 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Wed, 16 May 2018 22:49:51 -0400
Subject: [PATCH 08/34] don't use channel name in FileList
---
src/renderer/component/fileList/view.jsx | 22 ++++++----------------
1 file changed, 6 insertions(+), 16 deletions(-)
diff --git a/src/renderer/component/fileList/view.jsx b/src/renderer/component/fileList/view.jsx
index 8bc26d362..1f649f527 100644
--- a/src/renderer/component/fileList/view.jsx
+++ b/src/renderer/component/fileList/view.jsx
@@ -8,6 +8,7 @@ type FileInfo = {
name: string,
channelName: ?string,
pending?: boolean,
+ channel_claim_id: string,
value?: {
publisherSignature: {
certificateId: string,
@@ -139,6 +140,8 @@ class FileList extends React.PureComponent {
});
}
+ sortFunctions: {};
+
render() {
const { fileInfos, hideFilter, checkPending } = this.props;
const { sortBy } = this.state;
@@ -149,27 +152,14 @@ class FileList extends React.PureComponent {
}
this.sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
- const {
- channel_name: channelName,
- name: claimName,
- claim_name: claimNameDownloaded,
- claim_id: claimId,
- } = fileInfo;
+ const { name: claimName, claim_name: claimNameDownloaded, claim_id: claimId } = fileInfo;
const uriParams = {};
// This is unfortunate
// https://github.com/lbryio/lbry/issues/1159
const name = claimName || claimNameDownloaded;
-
- if (channelName) {
- uriParams.channelName = channelName;
- uriParams.contentName = name;
- uriParams.claimId = this.getChannelSignature(fileInfo);
- } else {
- uriParams.claimId = claimId;
- uriParams.claimName = name;
- }
-
+ uriParams.contentName = name;
+ uriParams.claimId = claimId;
const uri = buildURI(uriParams);
content.push( );
From 85191292118e48e7acd7399b5390d54d4219c973 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Wed, 16 May 2018 23:36:38 -0400
Subject: [PATCH 09/34] dropdown styling
---
src/renderer/scss/_gui.scss | 14 ++++++++++++++
src/renderer/scss/_vars.scss | 3 +++
src/renderer/scss/component/_form-field.scss | 2 +-
static/themes/dark.css | 6 ++++--
4 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/src/renderer/scss/_gui.scss b/src/renderer/scss/_gui.scss
index e7266b68b..d49071623 100644
--- a/src/renderer/scss/_gui.scss
+++ b/src/renderer/scss/_gui.scss
@@ -121,6 +121,20 @@ input::placeholder {
opacity: 0.5;
}
+select {
+ min-width: 100px;
+ height: 30px;
+ border-radius: 8px;
+ background-color: var(--input-select-bg-color);
+ font: normal 12px/30px 'metropolis-medium';
+ text-indent: 12px;
+ color: var(--input-select-color);
+
+ &:disabled {
+ opacity: 0.5;
+ }
+}
+
button + input {
margin-left: $spacing-vertical * 2/3;
}
diff --git a/src/renderer/scss/_vars.scss b/src/renderer/scss/_vars.scss
index cdfe3ddcf..ea591571e 100644
--- a/src/renderer/scss/_vars.scss
+++ b/src/renderer/scss/_vars.scss
@@ -35,6 +35,7 @@ $large-breakpoint: 1760px;
--color-green-light: #effbe4;
--color-green-blue: #2ec1a8;
--color-purple: #8165b0;
+ --color-blue-grey: #203049;
/* Colors */
--color-divider: #e3e3e3;
@@ -73,6 +74,8 @@ $large-breakpoint: 1760px;
--input-copyable-bg: #f6f6f6;
--input-copyable-color: var(--color-grey-dark);
--input-copyable-border: var(--color-grey);
+ --input-select-bg-color: var(--color-grey);
+ --input-select-color: var(--text-color);
/* input:disabled */
--input-disabled-border-color: rgba(0, 0, 0, 0.42);
diff --git a/src/renderer/scss/component/_form-field.scss b/src/renderer/scss/component/_form-field.scss
index 2be99b8ab..406318e8e 100644
--- a/src/renderer/scss/component/_form-field.scss
+++ b/src/renderer/scss/component/_form-field.scss
@@ -103,7 +103,7 @@
// Not sure if I like these
// Maybe this should be in gui.scss?
.input--price-amount {
- width: 60px;
+ width: 80px;
}
.input--address {
diff --git a/static/themes/dark.css b/static/themes/dark.css
index 7796724ef..dc4d666b7 100644
--- a/static/themes/dark.css
+++ b/static/themes/dark.css
@@ -7,7 +7,7 @@
--color-help: #8696AF;
--color-download: rgba(255, 255, 255, 0.75);
--color-download-overlay: var(--color-black);
- --color-bg: #203049;
+ --color-bg: var(--color-blue-grey);
--color-bg-alt: #2D3D56;
--color-placeholder: var(--color-bg-alt);
@@ -26,9 +26,11 @@
--input-border-size: 1px;
--input-border-color: rgba(255,255,255, 0.5);
--input-hover-border-color: rgba(255, 255, 255, 1);
- --input-copyable-bg: #203049;
+ --input-copyable-bg: var(--color-blue-grey);
--input-copyable-color: #8696AF;
--input-copyable-border: #53637C;
+ --input-select-bg-color: var(--color-blue-grey);
+ --input-select-color: var(--color-white);
/* input:disabled */
--input-disabled-border-color: rgba(255, 255, 255, 0.42);
From 55209a21cf0b4935c9b78da6d2fc013a87e33fa4 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Thu, 17 May 2018 00:09:25 -0400
Subject: [PATCH 10/34] don't show rewards message if no claimable rewards
---
src/renderer/modal/modalCreditIntro/view.jsx | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/src/renderer/modal/modalCreditIntro/view.jsx b/src/renderer/modal/modalCreditIntro/view.jsx
index 96e2fb801..bacd4ce3f 100644
--- a/src/renderer/modal/modalCreditIntro/view.jsx
+++ b/src/renderer/modal/modalCreditIntro/view.jsx
@@ -25,16 +25,13 @@ const ModalCreditIntro = props => {
can take are limited.
)}
-
- There are a variety of ways to get credits, including more than{' '}
- {totalRewardValue ? (
-
- ) : (
- {__('?? credits')}
- )}{' '}
- {__(' in free rewards for participating in the LBRY beta.')}
-
-
+ {totalRewardValue && (
+
+ There are a variety of ways to get credits, including more than{' '}
+ {' '}
+ {__('in free rewards for participating in the LBRY beta.')}
+
+ )}
Date: Mon, 21 May 2018 16:30:00 -0400
Subject: [PATCH 11/34] move file actions below video player
---
src/renderer/component/common/icon.jsx | 6 +-
src/renderer/component/fileActions/view.jsx | 10 ++-
.../component/fileDownloadLink/view.jsx | 71 ++++++++++---------
.../component/subscribeButton/view.jsx | 2 +-
.../component/video/internal/play-button.jsx | 2 +-
src/renderer/page/file/view.jsx | 15 ++--
src/renderer/scss/component/_card.scss | 5 +-
.../scss/component/_file-download.scss | 25 +------
8 files changed, 63 insertions(+), 73 deletions(-)
diff --git a/src/renderer/component/common/icon.jsx b/src/renderer/component/common/icon.jsx
index b0a05d879..7bfc3ae0c 100644
--- a/src/renderer/component/common/icon.jsx
+++ b/src/renderer/component/common/icon.jsx
@@ -1,10 +1,10 @@
// @flow
import React from 'react';
-// import * as icons from 'constants/icons';
import * as FeatherIcons from 'react-feather';
import * as icons from 'constants/icons';
const RED_COLOR = '#e2495e';
+const PURPLE_COLOR = '#8165b0';
type Props = {
icon: string,
@@ -19,8 +19,10 @@ class IconComponent extends React.PureComponent {
const Icon = FeatherIcons[icon];
let color;
- if (icon === icons.HEART || icon === icons.FEATURED) {
+ if (icon === icons.TRASH || icon === icons.FEATURED) {
color = RED_COLOR;
+ } else if (icon === icons.OPEN) {
+ color = PURPLE_COLOR;
}
let size = 14;
diff --git a/src/renderer/component/fileActions/view.jsx b/src/renderer/component/fileActions/view.jsx
index 94995d245..a485cc90e 100644
--- a/src/renderer/component/fileActions/view.jsx
+++ b/src/renderer/component/fileActions/view.jsx
@@ -1,7 +1,6 @@
// @flow
import React from 'react';
import Button from 'component/button';
-import FileDownloadLink from 'component/fileDownloadLink';
import { MODALS } from 'lbry-redux';
import classnames from 'classnames';
import * as icons from 'constants/icons';
@@ -27,21 +26,20 @@ class FileActions extends React.PureComponent {
return (
-
{showDelete && (
openModal({ id: MODALS.CONFIRM_FILE_REMOVE }, { uri })}
/>
)}
{!claimIsMine && (
)}
diff --git a/src/renderer/component/fileDownloadLink/view.jsx b/src/renderer/component/fileDownloadLink/view.jsx
index c2c413bd6..0658ae253 100644
--- a/src/renderer/component/fileDownloadLink/view.jsx
+++ b/src/renderer/component/fileDownloadLink/view.jsx
@@ -1,19 +1,39 @@
+// @flow
import React from 'react';
import Button from 'component/button';
-import classnames from 'classnames';
import * as icons from 'constants/icons';
-class FileDownloadLink extends React.PureComponent {
+type Props = {
+ uri: string,
+ downloading: boolean,
+ fileInfo: ?{
+ written_bytes: number,
+ total_bytes: number,
+ outpoint: number,
+ download_path: string,
+ },
+ loading: boolean,
+ costInfo: ?{},
+ restartDownload: (string, number) => void,
+ checkAvailability: string => void,
+ openInShell: string => void,
+ purchaseUri: string => void,
+ doPause: () => void,
+};
+
+class FileDownloadLink extends React.PureComponent {
componentWillMount() {
this.checkAvailability(this.props.uri);
}
- componentWillReceiveProps(nextProps) {
+ componentWillReceiveProps(nextProps: Props) {
this.checkAvailability(nextProps.uri);
this.restartDownload(nextProps);
}
- restartDownload(props) {
+ uri: ?string;
+
+ restartDownload = (props: Props) => {
const { downloading, fileInfo, uri, restartDownload } = props;
if (
@@ -25,11 +45,11 @@ class FileDownloadLink extends React.PureComponent {
) {
restartDownload(uri, fileInfo.outpoint);
}
- }
+ };
- checkAvailability(uri) {
- if (!this._uri || uri !== this._uri) {
- this._uri = uri;
+ checkAvailability(uri: string) {
+ if (!this.uri || uri !== this.uri) {
+ this.uri = uri;
this.props.checkAvailability(uri);
}
}
@@ -47,8 +67,10 @@ class FileDownloadLink extends React.PureComponent {
} = this.props;
const openFile = () => {
- openInShell(fileInfo.download_path);
- doPause();
+ if (fileInfo) {
+ openInShell(fileInfo.download_path);
+ doPause();
+ }
};
if (loading || downloading) {
@@ -56,21 +78,11 @@ class FileDownloadLink extends React.PureComponent {
fileInfo && fileInfo.written_bytes
? fileInfo.written_bytes / fileInfo.total_bytes * 100
: 0;
- const label = fileInfo ? progress.toFixed(0) + __('% complete') : __('Connecting...');
+ const label = fileInfo
+ ? __('Downloading: ') + progress.toFixed(0) + __('% complete')
+ : __('Connecting...');
- return (
-
-
- {label}
-
- {label}
-
- );
+ return {label} ;
} else if (fileInfo === null && !downloading) {
if (!costInfo) {
return null;
@@ -78,8 +90,8 @@ class FileDownloadLink extends React.PureComponent {
return (
{
purchaseUri(uri);
@@ -88,12 +100,7 @@ class FileDownloadLink extends React.PureComponent {
);
} else if (fileInfo && fileInfo.download_path) {
return (
- openFile()}
- />
+ openFile()} />
);
}
diff --git a/src/renderer/component/subscribeButton/view.jsx b/src/renderer/component/subscribeButton/view.jsx
index 52516dfb8..5366d107a 100644
--- a/src/renderer/component/subscribeButton/view.jsx
+++ b/src/renderer/component/subscribeButton/view.jsx
@@ -38,7 +38,7 @@ export default (props: Props) => {
return channelName && uri ? (
{
if (!subscriptions.length) {
diff --git a/src/renderer/component/video/internal/play-button.jsx b/src/renderer/component/video/internal/play-button.jsx
index e2df7d455..8055dd5ff 100644
--- a/src/renderer/component/video/internal/play-button.jsx
+++ b/src/renderer/component/video/internal/play-button.jsx
@@ -18,7 +18,7 @@ class VideoPlayButton extends React.PureComponent {
const label = doesPlayback ? 'Play' : 'View';
return (
-
+
);
}
}
diff --git a/src/renderer/page/file/view.jsx b/src/renderer/page/file/view.jsx
index 5ebe44876..f6bec07aa 100644
--- a/src/renderer/page/file/view.jsx
+++ b/src/renderer/page/file/view.jsx
@@ -17,6 +17,8 @@ import Page from 'component/page';
import player from 'render-media';
import * as settings from 'constants/settings';
import type { Claim } from 'types/claim';
+import type { Subscription } from 'types/subscription';
+import FileDownloadLink from 'component/fileDownloadLink';
type Props = {
claim: Claim,
@@ -42,7 +44,7 @@ type Props = {
prepareEdit: ({}) => void,
setClientSetting: (string, boolean | string) => void,
checkSubscription: ({ channelName: string, uri: string }) => void,
- subscriptions: Array<{}>,
+ subscriptions: Array,
};
class FilePage extends React.Component {
@@ -151,11 +153,6 @@ class FilePage extends React.Component {
) : (
)}
- {!isPlaying && (
-
-
-
- )}
{title}
@@ -171,6 +168,7 @@ class FilePage extends React.Component
{
{metadata.nsfw && NSFW
}
+
{claimIsMine ? (
{
+
+
+
+
+
diff --git a/src/renderer/scss/component/_card.scss b/src/renderer/scss/component/_card.scss
index 84e74d3e2..9d5404e42 100644
--- a/src/renderer/scss/component/_card.scss
+++ b/src/renderer/scss/component/_card.scss
@@ -2,7 +2,6 @@
margin-left: auto;
margin-right: auto;
border-radius: var(--card-radius);
- overflow: auto;
user-select: text;
display: flex;
position: relative;
@@ -184,6 +183,10 @@
margin-top: $spacing-vertical * 2/3;
}
+.card__content--extra-padding {
+ margin-top: $spacing-vertical;
+}
+
.card__subtext-title {
color: var(--text-color);
font-size: calc(var(--font-size-subtext-multiple) * 1.5em);
diff --git a/src/renderer/scss/component/_file-download.scss b/src/renderer/scss/component/_file-download.scss
index c4bd7e025..b38d8a520 100644
--- a/src/renderer/scss/component/_file-download.scss
+++ b/src/renderer/scss/component/_file-download.scss
@@ -1,26 +1,3 @@
-.file-download,
-.file-download__overlay {
- padding: 5px;
-}
-
.file-download {
- position: relative;
- background-color: var(--color-black);
- border-radius: var(--btn-radius);
- color: var(--color-download);
- font-size: 12px;
- opacity: 0.8;
- font-family: 'metropolis-medium';
-}
-
-.file-download__overlay {
- background: var(--color-download);
- color: var(--color-download-overlay);
- border-radius: var(--btn-radius);
- position: absolute;
- white-space: nowrap;
- overflow: hidden;
- z-index: 1;
- top: 0px;
- left: 0px;
+ font-size: 0.8em;
}
From 7c4e4c24ad326972f9a58d5157f20ebf71bd03d8 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Mon, 21 May 2018 22:10:47 -0400
Subject: [PATCH 12/34] update lbry redux
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index d279738d6..3337b697d 100644
--- a/package.json
+++ b/package.json
@@ -48,7 +48,7 @@
"formik": "^0.10.4",
"hast-util-sanitize": "^1.1.2",
"keytar": "^4.2.1",
- "lbry-redux": "lbryio/lbry-redux#30c18725d8c6c141c30c57f0a324d0abb8963b99",
+ "lbry-redux": "lbryio/lbry-redux#c41899e78415cae6fcb7bfca0e6ba48bb6bfe6c4",
"localforage": "^1.7.1",
"mixpanel-browser": "^2.17.1",
"moment": "^2.22.0",
From f86bb14591fa6fdfc60fe08363c067cdf545c403 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Tue, 22 May 2018 20:11:20 -0400
Subject: [PATCH 13/34] update tooltip component to show on hover and add
different directions
---
src/renderer/component/categoryList/view.jsx | 1 +
src/renderer/component/common/icon.jsx | 35 +++++-
src/renderer/component/common/tooltip.jsx | 70 +++++-------
src/renderer/component/fileCard/view.jsx | 8 +-
src/renderer/page/file/view.jsx | 2 +-
src/renderer/page/search/view.jsx | 9 +-
src/renderer/scss/_gui.scss | 3 +-
src/renderer/scss/_vars.scss | 5 +-
src/renderer/scss/component/_card.scss | 51 ++++-----
src/renderer/scss/component/_tooltip.scss | 109 +++++++++++++++----
src/renderer/scss/mixin/link.scss | 28 -----
11 files changed, 181 insertions(+), 140 deletions(-)
delete mode 100644 src/renderer/scss/mixin/link.scss
diff --git a/src/renderer/component/categoryList/view.jsx b/src/renderer/component/categoryList/view.jsx
index 0afa57940..56c69f4c9 100644
--- a/src/renderer/component/categoryList/view.jsx
+++ b/src/renderer/component/categoryList/view.jsx
@@ -223,6 +223,7 @@ class CategoryList extends React.PureComponent {
{category &&
category.match(/^community/i) && (
{
- // TODO: Move all icons to constants and add titles for all
- // Add some some sort of hover flyout with the title?
-
+ getTooltip = (icon: string) => {
+ switch (icon) {
+ case icons.FEATURED:
+ return __('Featured content. Earn rewards for watching.');
+ case icons.LOCAL:
+ return __('This file is downloaded.');
+ default:
+ return null;
+ }
+ };
render() {
- const { icon } = this.props;
+ const { icon, tooltip } = this.props;
const Icon = FeatherIcons[icon];
+ if (!Icon) {
+ return null;
+ }
+
let color;
if (icon === icons.TRASH || icon === icons.FEATURED) {
color = RED_COLOR;
@@ -30,7 +43,19 @@ class IconComponent extends React.PureComponent {
size = 20;
}
- return Icon ? : null;
+ let tooltipText;
+ if (tooltip) {
+ tooltipText = this.getTooltip(icon);
+ }
+ const inner = ;
+
+ return tooltip ? (
+
+ {inner}
+
+ ) : (
+ inner
+ );
}
}
diff --git a/src/renderer/component/common/tooltip.jsx b/src/renderer/component/common/tooltip.jsx
index e226a8351..f1c5ca893 100644
--- a/src/renderer/component/common/tooltip.jsx
+++ b/src/renderer/component/common/tooltip.jsx
@@ -1,55 +1,41 @@
// @flow
-import React from 'react';
+import * as React from 'react';
import classnames from 'classnames';
-import Icon from 'component/common/icon';
-import Button from 'component/button';
-import * as icons from 'constants/icons';
type Props = {
- body: string,
- label: string,
+ body: ?string,
+ label?: string,
+ children: ?React.Node,
+ icon: ?boolean,
+ direction: string,
};
-type State = {
- showTooltip: boolean,
-};
-
-class ToolTip extends React.PureComponent {
- constructor(props: Props) {
- super(props);
-
- this.state = {
- showTooltip: false,
- };
-
- (this: any).handleClick = this.handleClick.bind(this);
- }
-
- handleClick() {
- const { showTooltip } = this.state;
-
- if (!showTooltip) {
- document.addEventListener('click', this.handleClick);
- } else {
- document.removeEventListener('click', this.handleClick);
- }
-
- this.setState({
- showTooltip: !showTooltip,
- });
- }
+class ToolTip extends React.PureComponent {
+ static defaultProps = {
+ direction: 'top',
+ };
render() {
- const { label, body } = this.props;
- const { showTooltip } = this.state;
+ const { children, label, body, icon, direction } = this.props;
+
+ const tooltipContent = children || label;
return (
-
-
- {label}
- {showTooltip && }
-
- {body}
+
+ {tooltipContent}
+ {body && (
+ // body may be undefined for some icons until we add messages for them
+ {body}
+ )}
);
}
diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx
index 88bb99946..460006f70 100644
--- a/src/renderer/component/fileCard/view.jsx
+++ b/src/renderer/component/fileCard/view.jsx
@@ -98,14 +98,16 @@ class FileCard extends React.PureComponent {
{title}
-
+
{pending ? (
Pending...
) : (
- {isRewardContent && }
- {fileInfo && }
+
+ {isRewardContent && }
+ {fileInfo && }
+
)}
diff --git a/src/renderer/page/file/view.jsx b/src/renderer/page/file/view.jsx
index f6bec07aa..55a85904a 100644
--- a/src/renderer/page/file/view.jsx
+++ b/src/renderer/page/file/view.jsx
@@ -158,7 +158,7 @@ class FilePage extends React.Component
{
{title}
- {isRewardContent && }
+ {isRewardContent && }
diff --git a/src/renderer/page/search/view.jsx b/src/renderer/page/search/view.jsx
index 0535c34d7..763848def 100644
--- a/src/renderer/page/search/view.jsx
+++ b/src/renderer/page/search/view.jsx
@@ -5,6 +5,8 @@ import FileTile from 'component/fileTile';
import FileListSearch from 'component/fileListSearch';
import ToolTip from 'component/common/tooltip';
import Page from 'component/page';
+import Icon from 'component/common/icon';
+import * as icons from 'constants/icons';
const MODAL_ANIMATION_TIME = 250;
@@ -50,10 +52,11 @@ class SearchPage extends React.PureComponent {
{__('Exact URL')}
+ >
+
+
diff --git a/src/renderer/scss/_gui.scss b/src/renderer/scss/_gui.scss
index d49071623..0ad4197dc 100644
--- a/src/renderer/scss/_gui.scss
+++ b/src/renderer/scss/_gui.scss
@@ -122,12 +122,11 @@ input::placeholder {
}
select {
- min-width: 100px;
+ min-width: 60px;
height: 30px;
border-radius: 8px;
background-color: var(--input-select-bg-color);
font: normal 12px/30px 'metropolis-medium';
- text-indent: 12px;
color: var(--input-select-color);
&:disabled {
diff --git a/src/renderer/scss/_vars.scss b/src/renderer/scss/_vars.scss
index ea591571e..db8bf3e9e 100644
--- a/src/renderer/scss/_vars.scss
+++ b/src/renderer/scss/_vars.scss
@@ -161,9 +161,8 @@ $large-breakpoint: 1760px;
--modal-btn-bg-color: var(--btn-bg-alt);
// /* Tooltip */
- --tooltip-width: 300px;
- --tooltip-bg: var(--color-bg);
- --tooltip-color: var(--text-color);
+ --tooltip-bg: #555;
+ --tooltip-color: var(--color-white);
/* Scrollbar */
--scrollbar-radius: 10px;
diff --git a/src/renderer/scss/component/_card.scss b/src/renderer/scss/component/_card.scss
index 9d5404e42..b872a95e0 100644
--- a/src/renderer/scss/component/_card.scss
+++ b/src/renderer/scss/component/_card.scss
@@ -17,7 +17,6 @@
.card--small {
width: var(--card-small-width);
- overflow-x: hidden;
white-space: normal;
.card__media {
@@ -86,8 +85,7 @@
align-items: center;
.credit-amount,
.icon {
- margin-top: $spacing-vertical * 1/3;
- margin-left: $spacing-vertical * 2/3;
+ margin: $spacing-vertical * 1/3;
}
}
@@ -126,7 +124,11 @@
color: var(--card-text-color);
.icon {
- margin-left: $spacing-vertical * 1/3;
+ margin-top: $spacing-vertical * 1/6;
+
+ &:not(:first-of-type) {
+ margin: 0 $spacing-vertical * 1/3;
+ }
}
}
@@ -134,11 +136,6 @@
padding-top: $spacing-vertical * 1/3;
}
-.card__subtitle--file-info {
- display: flex;
- align-items: center;
-}
-
.card__subtitle--block {
display: block;
}
@@ -243,12 +240,11 @@
}
/*
- .card-row is used on the discover/subscriptions page
+ .card-row is used on the discover page
It is a list of cards that extend past the right edge of the screen
There are left/right arrows to scroll the cards and view hidden content
*/
.card-row {
- overflow: hidden;
white-space: nowrap;
width: 100%;
min-width: var(--card-small-width);
@@ -289,6 +285,18 @@
padding-top: $spacing-vertical * 2/3;
overflow: hidden;
+ .card {
+ display: inline-block;
+ vertical-align: top;
+ overflow-y: visible;
+ // 31 px to handle to padding between cards
+ width: calc((100% / 4) - 31px);
+ }
+
+ .card:not(:first-of-type) {
+ margin-left: 20px;
+ }
+
.card:first-of-type {
margin-left: $spacing-width;
}
@@ -327,27 +335,6 @@
}
}
-.card-row__scrollhouse {
- padding-top: $spacing-vertical * 2/3;
- overflow: hidden;
-
- .card {
- display: inline-block;
- vertical-align: top;
- overflow: visible;
- // 31 px to handle to padding between cards
- width: calc((100% / 4) - 31px);
- }
-
- .card:not(:first-of-type) {
- margin-left: 20px;
- }
-
- .card:last-of-type {
- margin-right: 20px;
- }
-}
-
.card__success-msg {
border-left: 2px solid var(--success-msg-border);
color: var(--success-msg-color);
diff --git a/src/renderer/scss/component/_tooltip.scss b/src/renderer/scss/component/_tooltip.scss
index 504880b09..3e32a7fbe 100644
--- a/src/renderer/scss/component/_tooltip.scss
+++ b/src/renderer/scss/component/_tooltip.scss
@@ -1,30 +1,97 @@
-@import '../mixin/link.scss';
-
.tooltip {
position: relative;
- padding: 0 $spacing-vertical / 3;
- font-size: 12px;
+ display: inline-block;
}
-.tooltip__body {
+// When there is a label for the tooltip and not just using a button or icon
+.tooltip.tooltip--label {
+ font-size: 12px;
+ padding-left: $spacing-vertical * 1/3;
+
+ .tooltip__body {
+ margin-top: 5px;
+ }
+}
+
+.tooltip.tooltip--icon {
+ margin-top: 5px;
+}
+
+/* Tooltip text */
+.tooltip .tooltip__body {
+ background-color: var(--tooltip-bg);
+ font-family: 'metropolis-medium';
+ font-size: 12px;
+ color: var(--tooltip-color);
+ border-radius: 8px;
position: absolute;
z-index: 1;
- left: 50%;
- margin-left: calc(var(--tooltip-width) * -1 / 2);
- white-space: normal;
- box-sizing: border-box;
- padding: $spacing-vertical / 2;
- width: var(--tooltip-width);
- color: var(--tooltip-color);
- background-color: var(--tooltip-bg);
- font-size: calc(var(--font-size) * 7 / 8);
- line-height: var(--font-line-height);
- box-shadow: var(--box-shadow-layer);
- border-radius: var(--card-radius);
+ width: 200px;
+ text-align: center;
+ white-space: pre-wrap;
+ padding: $spacing-vertical * 1/3;
+ visibility: hidden;
}
-.tooltip__link {
- font-size: calc(var(--font-size) * 3 / 4);
- margin-left: var(--button-padding);
- vertical-align: middle;
+.tooltip .tooltip__body::after {
+ content: ' ';
+ width: 0;
+ height: 0;
+ position: absolute;
+ border-width: 5px;
+ border-style: solid;
+}
+
+.tooltip.tooltip--top .tooltip__body {
+ bottom: 100%;
+ left: 50%;
+ margin-left: -100px;
+
+ &::after {
+ top: 100%;
+ left: 50%;
+ margin-left: -5px;
+ border-color: var(--tooltip-bg) transparent transparent transparent;
+ }
+}
+
+.tooltip.tooltip--right .tooltip__body {
+ margin-top: -5px;
+ margin-left: 10px;
+
+ &::after {
+ top: 17px;
+ right: 100%; /* To the left of the tooltip */
+ margin-top: -5px;
+ border-color: transparent var(--tooltip-bg) transparent transparent;
+ }
+}
+
+.tooltip.tooltip--bottom .tooltip__body {
+ top: 90%;
+ left: 50%;
+ margin-left: -100px;
+
+ &::after {
+ bottom: 100%;
+ left: 50%;
+ margin-left: -5px;
+ border-color: transparent transparent var(--tooltip-bg) transparent;
+ }
+}
+
+.tooltip.tooltip--left .tooltip__body {
+ top: -5px;
+ right: 105%;
+
+ &::after {
+ top: 17px;
+ left: 100%;
+ margin-top: -5px;
+ border-color: transparent transparent transparent var(--tooltip-bg);
+ }
+}
+
+.tooltip:hover .tooltip__body {
+ visibility: visible;
}
diff --git a/src/renderer/scss/mixin/link.scss b/src/renderer/scss/mixin/link.scss
deleted file mode 100644
index df55e49ba..000000000
--- a/src/renderer/scss/mixin/link.scss
+++ /dev/null
@@ -1,28 +0,0 @@
-@mixin text-link($color: var(--color-primary), $hover-opacity: 0.7) {
- .icon {
- &:first-child {
- padding-right: 5px;
- }
- &:last-child:not(:only-child) {
- padding-left: 5px;
- }
- }
-
- &:not(.no-underline) {
- text-decoration: underline;
- .icon {
- text-decoration: none;
- }
- }
- &:hover {
- opacity: $hover-opacity;
- transition: opacity var(--transition-duration) var(--transition-type);
- text-decoration: underline;
- .icon {
- text-decoration: none;
- }
- }
-
- color: $color;
- cursor: pointer;
-}
From 2f4395a9e3582d295cef7a20a738b2642def3c95 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Tue, 22 May 2018 20:29:29 -0400
Subject: [PATCH 14/34] cleanup FileDownloadLink
---
.../component/fileDownloadLink/index.js | 2 --
.../component/fileDownloadLink/view.jsx | 27 ++++---------------
2 files changed, 5 insertions(+), 24 deletions(-)
diff --git a/src/renderer/component/fileDownloadLink/index.js b/src/renderer/component/fileDownloadLink/index.js
index d36f4c896..22f4f0a3f 100644
--- a/src/renderer/component/fileDownloadLink/index.js
+++ b/src/renderer/component/fileDownloadLink/index.js
@@ -5,7 +5,6 @@ import {
makeSelectLoadingForUri,
makeSelectCostInfoForUri,
} from 'lbry-redux';
-import { doFetchAvailability } from 'redux/actions/availability';
import { doOpenFileInShell } from 'redux/actions/file';
import { doPurchaseUri, doStartDownload } from 'redux/actions/content';
import { doPause } from 'redux/actions/media';
@@ -20,7 +19,6 @@ const select = (state, props) => ({
});
const perform = dispatch => ({
- checkAvailability: uri => dispatch(doFetchAvailability(uri)),
openInShell: path => dispatch(doOpenFileInShell(path)),
purchaseUri: uri => dispatch(doPurchaseUri(uri)),
restartDownload: (uri, outpoint) => dispatch(doStartDownload(uri, outpoint)),
diff --git a/src/renderer/component/fileDownloadLink/view.jsx b/src/renderer/component/fileDownloadLink/view.jsx
index 0658ae253..8acc17db3 100644
--- a/src/renderer/component/fileDownloadLink/view.jsx
+++ b/src/renderer/component/fileDownloadLink/view.jsx
@@ -11,31 +11,19 @@ type Props = {
total_bytes: number,
outpoint: number,
download_path: string,
+ completed: boolean,
},
loading: boolean,
costInfo: ?{},
restartDownload: (string, number) => void,
- checkAvailability: string => void,
openInShell: string => void,
purchaseUri: string => void,
doPause: () => void,
};
class FileDownloadLink extends React.PureComponent {
- componentWillMount() {
- this.checkAvailability(this.props.uri);
- }
-
- componentWillReceiveProps(nextProps: Props) {
- this.checkAvailability(nextProps.uri);
- this.restartDownload(nextProps);
- }
-
- uri: ?string;
-
- restartDownload = (props: Props) => {
- const { downloading, fileInfo, uri, restartDownload } = props;
-
+ componentWillUpdate() {
+ const { downloading, fileInfo, uri, restartDownload } = this.props;
if (
!downloading &&
fileInfo &&
@@ -45,15 +33,10 @@ class FileDownloadLink extends React.PureComponent {
) {
restartDownload(uri, fileInfo.outpoint);
}
- };
-
- checkAvailability(uri: string) {
- if (!this.uri || uri !== this.uri) {
- this.uri = uri;
- this.props.checkAvailability(uri);
- }
}
+ uri: ?string;
+
render() {
const {
fileInfo,
From e56c21fd22d73afa4be1922e5404545c005a25f8 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Tue, 22 May 2018 23:48:22 -0400
Subject: [PATCH 15/34] use color prop for icon color instead of relying on
type of icon and tooltip cleanup
---
src/renderer/component/button/view.jsx | 6 +++--
src/renderer/component/categoryList/view.jsx | 1 -
src/renderer/component/common/icon.jsx | 23 ++++++++++++++-----
src/renderer/component/common/tooltip.jsx | 9 +++-----
src/renderer/component/fileActions/view.jsx | 1 +
src/renderer/component/fileCard/view.jsx | 2 +-
.../component/fileDownloadLink/view.jsx | 9 +++++++-
.../component/subscribeButton/view.jsx | 3 ++-
src/renderer/page/file/view.jsx | 4 ++--
src/renderer/scss/component/_file-list.scss | 4 ++++
10 files changed, 42 insertions(+), 20 deletions(-)
diff --git a/src/renderer/component/button/view.jsx b/src/renderer/component/button/view.jsx
index f622ff28a..8b496ea12 100644
--- a/src/renderer/component/button/view.jsx
+++ b/src/renderer/component/button/view.jsx
@@ -22,6 +22,7 @@ type Props = {
button: ?string, // primary, secondary, alt, link
noPadding: ?boolean, // to remove padding and allow circular buttons
uppercase: ?boolean,
+ iconColor: ?string,
};
class Button extends React.PureComponent {
@@ -48,6 +49,7 @@ class Button extends React.PureComponent {
type,
noPadding,
uppercase,
+ iconColor,
...otherProps
} = this.props;
@@ -82,10 +84,10 @@ class Button extends React.PureComponent {
const content = (
- {icon && }
+ {icon && }
{label && {label} }
{children && children}
- {iconRight && }
+ {iconRight && }
);
diff --git a/src/renderer/component/categoryList/view.jsx b/src/renderer/component/categoryList/view.jsx
index 56c69f4c9..0afa57940 100644
--- a/src/renderer/component/categoryList/view.jsx
+++ b/src/renderer/component/categoryList/view.jsx
@@ -223,7 +223,6 @@ class CategoryList extends React.PureComponent {
{category &&
category.match(/^community/i) && (
{
@@ -23,8 +24,20 @@ class IconComponent extends React.PureComponent {
return null;
}
};
+
+ getIconColor = (color: string) => {
+ switch (color) {
+ case 'red':
+ return RED_COLOR;
+ case 'purple':
+ return PURPLE_COLOR;
+ default:
+ return null;
+ }
+ };
+
render() {
- const { icon, tooltip } = this.props;
+ const { icon, tooltip, iconColor } = this.props;
const Icon = FeatherIcons[icon];
if (!Icon) {
@@ -32,10 +45,8 @@ class IconComponent extends React.PureComponent {
}
let color;
- if (icon === icons.TRASH || icon === icons.FEATURED) {
- color = RED_COLOR;
- } else if (icon === icons.OPEN) {
- color = PURPLE_COLOR;
+ if (iconColor) {
+ color = this.getIconColor(iconColor);
}
let size = 14;
diff --git a/src/renderer/component/common/tooltip.jsx b/src/renderer/component/common/tooltip.jsx
index f1c5ca893..4bd264516 100644
--- a/src/renderer/component/common/tooltip.jsx
+++ b/src/renderer/component/common/tooltip.jsx
@@ -3,7 +3,7 @@ import * as React from 'react';
import classnames from 'classnames';
type Props = {
- body: ?string,
+ body: string,
label?: string,
children: ?React.Node,
icon: ?boolean,
@@ -12,7 +12,7 @@ type Props = {
class ToolTip extends React.PureComponent {
static defaultProps = {
- direction: 'top',
+ direction: 'bottom',
};
render() {
@@ -32,10 +32,7 @@ class ToolTip extends React.PureComponent {
})}
>
{tooltipContent}
- {body && (
- // body may be undefined for some icons until we add messages for them
- {body}
- )}
+ {body}
);
}
diff --git a/src/renderer/component/fileActions/view.jsx b/src/renderer/component/fileActions/view.jsx
index a485cc90e..4ab110fca 100644
--- a/src/renderer/component/fileActions/view.jsx
+++ b/src/renderer/component/fileActions/view.jsx
@@ -30,6 +30,7 @@ class FileActions extends React.PureComponent {
openModal({ id: MODALS.CONFIRM_FILE_REMOVE }, { uri })}
/>
diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx
index 460006f70..eae87deaa 100644
--- a/src/renderer/component/fileCard/view.jsx
+++ b/src/renderer/component/fileCard/view.jsx
@@ -105,7 +105,7 @@ class FileCard extends React.PureComponent {
- {isRewardContent && }
+ {isRewardContent && }
{fileInfo && }
diff --git a/src/renderer/component/fileDownloadLink/view.jsx b/src/renderer/component/fileDownloadLink/view.jsx
index 8acc17db3..8d96624f8 100644
--- a/src/renderer/component/fileDownloadLink/view.jsx
+++ b/src/renderer/component/fileDownloadLink/view.jsx
@@ -76,6 +76,7 @@ class FileDownloadLink extends React.PureComponent {
button="alt"
label={__('Download')}
icon={icons.DOWNLOAD}
+ iconColor="purple"
onClick={() => {
purchaseUri(uri);
}}
@@ -83,7 +84,13 @@ class FileDownloadLink extends React.PureComponent {
);
} else if (fileInfo && fileInfo.download_path) {
return (
- openFile()} />
+ openFile()}
+ />
);
}
diff --git a/src/renderer/component/subscribeButton/view.jsx b/src/renderer/component/subscribeButton/view.jsx
index 5366d107a..a29b8bb4a 100644
--- a/src/renderer/component/subscribeButton/view.jsx
+++ b/src/renderer/component/subscribeButton/view.jsx
@@ -37,8 +37,9 @@ export default (props: Props) => {
return channelName && uri ? (
{
if (!subscriptions.length) {
diff --git a/src/renderer/page/file/view.jsx b/src/renderer/page/file/view.jsx
index 55a85904a..4071e9125 100644
--- a/src/renderer/page/file/view.jsx
+++ b/src/renderer/page/file/view.jsx
@@ -41,7 +41,7 @@ type Props = {
openModal: ({ id: string }, { uri: string }) => void,
fetchFileInfo: string => void,
fetchCostInfo: string => void,
- prepareEdit: ({}) => void,
+ prepareEdit: ({}, string) => void,
setClientSetting: (string, boolean | string) => void,
checkSubscription: ({ channelName: string, uri: string }) => void,
subscriptions: Array,
@@ -158,7 +158,7 @@ class FilePage extends React.Component {
{title}
- {isRewardContent && }
+ {isRewardContent && }
diff --git a/src/renderer/scss/component/_file-list.scss b/src/renderer/scss/component/_file-list.scss
index 72cee988f..30b2de303 100644
--- a/src/renderer/scss/component/_file-list.scss
+++ b/src/renderer/scss/component/_file-list.scss
@@ -14,6 +14,10 @@
.file-list__header {
margin-top: $spacing-vertical * 4/3;
font-size: 18px;
+
+ .tooltip {
+ margin-left: 5px;
+ }
}
.file-tile {
From 1a6188a7c7bb257c37378373513d4ff06ab962ce Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Tue, 22 May 2018 23:55:11 -0400
Subject: [PATCH 16/34] fix select background color for dark mode
---
static/themes/dark.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/static/themes/dark.css b/static/themes/dark.css
index dc4d666b7..9bf8cac02 100644
--- a/static/themes/dark.css
+++ b/static/themes/dark.css
@@ -29,7 +29,7 @@
--input-copyable-bg: var(--color-blue-grey);
--input-copyable-color: #8696AF;
--input-copyable-border: #53637C;
- --input-select-bg-color: var(--color-blue-grey);
+ --input-select-bg-color: var(--color-bg-alt);
--input-select-color: var(--color-white);
/* input:disabled */
From 37b04993da78c30410b7b38e6bfc671fe2baaf17 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Fri, 25 May 2018 00:36:43 -0400
Subject: [PATCH 17/34] use classname for select styling
---
.eslintrc.json | 3 ++-
.../common/form-components/form-field-price.jsx | 1 -
.../component/common/form-components/form-field.jsx | 2 +-
src/renderer/scss/_gui.scss | 13 -------------
src/renderer/scss/component/_form-field.scss | 13 +++++++++++++
yarn.lock | 4 ++--
6 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/.eslintrc.json b/.eslintrc.json
index 83b2a0606..d3bcd1f7b 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -36,6 +36,7 @@
"func-names": ["warn", "as-needed"],
"jsx-a11y/label-has-for": 0,
"import/prefer-default-export": 0,
- "no-return-assign": 0
+ "no-return-assign": 0,
+ "react/require-default-props": 0
}
}
diff --git a/src/renderer/component/common/form-components/form-field-price.jsx b/src/renderer/component/common/form-components/form-field-price.jsx
index d8fcd2120..eceeb94a7 100644
--- a/src/renderer/component/common/form-components/form-field-price.jsx
+++ b/src/renderer/component/common/form-components/form-field-price.jsx
@@ -62,7 +62,6 @@ export class FormFieldPrice extends React.PureComponent {
name={`${name}_currency`}
type="select"
id={`${name}_currency`}
- className="form-field"
disabled={disabled}
onChange={this.handleCurrencyChange}
value={price.currency}
diff --git a/src/renderer/component/common/form-components/form-field.jsx b/src/renderer/component/common/form-components/form-field.jsx
index ffbc7eabc..441646447 100644
--- a/src/renderer/component/common/form-components/form-field.jsx
+++ b/src/renderer/component/common/form-components/form-field.jsx
@@ -42,7 +42,7 @@ export class FormField extends React.PureComponent {
if (type) {
if (type === 'select') {
input = (
-
+
{children}
);
diff --git a/src/renderer/scss/_gui.scss b/src/renderer/scss/_gui.scss
index 0ad4197dc..e7266b68b 100644
--- a/src/renderer/scss/_gui.scss
+++ b/src/renderer/scss/_gui.scss
@@ -121,19 +121,6 @@ input::placeholder {
opacity: 0.5;
}
-select {
- min-width: 60px;
- height: 30px;
- border-radius: 8px;
- background-color: var(--input-select-bg-color);
- font: normal 12px/30px 'metropolis-medium';
- color: var(--input-select-color);
-
- &:disabled {
- opacity: 0.5;
- }
-}
-
button + input {
margin-left: $spacing-vertical * 2/3;
}
diff --git a/src/renderer/scss/component/_form-field.scss b/src/renderer/scss/component/_form-field.scss
index 406318e8e..8b814dbf0 100644
--- a/src/renderer/scss/component/_form-field.scss
+++ b/src/renderer/scss/component/_form-field.scss
@@ -100,6 +100,19 @@
padding-left: $spacing-vertical * 1/3;
}
+.form-field__select {
+ min-width: 60px;
+ height: 30px;
+ border-radius: 8px;
+ background-color: var(--input-select-bg-color);
+ font: normal 12px/30px 'metropolis-medium';
+ color: var(--input-select-color);
+
+ &:disabled {
+ opacity: 0.5;
+ }
+}
+
// Not sure if I like these
// Maybe this should be in gui.scss?
.input--price-amount {
diff --git a/yarn.lock b/yarn.lock
index ffa56a39f..27fb511b0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5837,9 +5837,9 @@ lazy-val@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.3.tgz#bb97b200ef00801d94c317e29dc6ed39e31c5edc"
-lbry-redux@lbryio/lbry-redux#30c18725d8c6c141c30c57f0a324d0abb8963b99:
+lbry-redux@lbryio/lbry-redux#c41899e78415cae6fcb7bfca0e6ba48bb6bfe6c4:
version "0.0.1"
- resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/30c18725d8c6c141c30c57f0a324d0abb8963b99"
+ resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/c41899e78415cae6fcb7bfca0e6ba48bb6bfe6c4"
dependencies:
proxy-polyfill "0.1.6"
reselect "^3.0.0"
From c6732d3d3f75a6c1190942952465dcbd4549f192 Mon Sep 17 00:00:00 2001
From: Travis Eden
Date: Fri, 30 Mar 2018 12:13:11 -0400
Subject: [PATCH 18/34] add buttons to share spee.ch URLs on file and channel
pages
---
CHANGELOG.md | 3 ---
.../common/form-components/form-row.jsx | 2 --
.../component/viewOnWebButton/index.js | 3 +++
.../component/viewOnWebButton/view.jsx | 21 ++++++++++++++++++
src/renderer/constants/icons.js | 1 +
src/renderer/page/channel/view.jsx | 15 +++++++++++--
src/renderer/page/file/view.jsx | 22 ++++++++++++++-----
src/renderer/scss/component/_form-field.scss | 4 ++++
8 files changed, 58 insertions(+), 13 deletions(-)
create mode 100644 src/renderer/component/viewOnWebButton/index.js
create mode 100644 src/renderer/component/viewOnWebButton/view.jsx
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4f0e50e0f..981bf6cea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -57,7 +57,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
* App category for Linux ([#877](https://github.com/lbryio/lbry-app/pull/877))
* Add YouTube Sync reward ([#1147](https://github.com/lbryio/lbry-app/pull/1147))
* Retain previous screen sizing on startup ([#338](https://github.com/lbryio/lbry-app/issues/338))
- * Add 'Go to page' input on channel pagination ([#1166](https://github.com/lbryio/lbry-app/pull/1166))
### Changed
@@ -372,7 +371,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
* Removed placeholder values from price selection form fields, which was causing confusion that these were real values (#426)
* Fixed showing "other currency" help tip in publish form, which was caused due to not "setting" state for price
* Publish page now properly checks for all required fields are filled
- * Fixed pagination styling for pages > 5 (#416)
* Fixed sizing on squat videos (#419)
* Support claims no longer show up on Published page (#384)
* Fixed rendering of small prices (#461)
@@ -410,7 +408,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
### Added
* Replaced horizontal scrollbars with scroll arrows
* Featured weekly reward content shows with an orange star
- * Added pagination to channel pages
### Fixed
diff --git a/src/renderer/component/common/form-components/form-row.jsx b/src/renderer/component/common/form-components/form-row.jsx
index b18bcf795..f694c305e 100644
--- a/src/renderer/component/common/form-components/form-row.jsx
+++ b/src/renderer/component/common/form-components/form-row.jsx
@@ -4,7 +4,6 @@ import * as React from 'react';
import classnames from 'classnames';
type Props = {
- centered?: boolean,
children: React.Node,
padded?: boolean,
verticallyCentered?: boolean,
@@ -22,7 +21,6 @@ export class FormRow extends React.PureComponent {
return (
{
+ const { uri } = props;
+
+ return uri ? (
+
+ ) : null;
+};
diff --git a/src/renderer/constants/icons.js b/src/renderer/constants/icons.js
index 208c25ed3..845039e9f 100644
--- a/src/renderer/constants/icons.js
+++ b/src/renderer/constants/icons.js
@@ -25,3 +25,4 @@ export const CHECK = 'CheckCircle';
export const HEART = 'Heart';
export const UNLOCK = 'Unlock';
export const CHECK_SIMPLE = 'Check';
+export const GLOBE = 'Globe';
diff --git a/src/renderer/page/channel/view.jsx b/src/renderer/page/channel/view.jsx
index 693cb3c89..369ebcf48 100644
--- a/src/renderer/page/channel/view.jsx
+++ b/src/renderer/page/channel/view.jsx
@@ -1,12 +1,15 @@
// @flow
import React from 'react';
import BusyIndicator from 'component/common/busy-indicator';
+import Button from 'component/button';
import { FormField, FormRow } from 'component/common/form';
import ReactPaginate from 'react-paginate';
import SubscribeButton from 'component/subscribeButton';
+import ViewOnWebButton from 'component/viewOnWebButton';
import Page from 'component/page';
import FileList from 'component/fileList';
import type { Claim } from 'types/claim';
+import { MODALS } from 'lbry-redux';
type Props = {
uri: string,
@@ -19,6 +22,7 @@ type Props = {
fetchClaims: (string, number) => void,
fetchClaimCount: string => void,
navigate: (string, {}) => void,
+ openModal: (string, {}) => void,
};
class ChannelPage extends React.PureComponent
{
@@ -56,8 +60,8 @@ class ChannelPage extends React.PureComponent {
}
render() {
- const { fetching, claimsInChannel, claim, page, totalPages } = this.props;
- const { name, permanent_url: permanentUrl } = claim;
+ const { fetching, claimsInChannel, claim, page, totalPages, uri, openModal } = this.props;
+ const { name, permanent_url: permanentUrl, claim_id: claimId } = claim;
let contentList;
if (fetching) {
@@ -76,7 +80,14 @@ class ChannelPage extends React.PureComponent {
{name}
+ openModal(MODALS.SEND_TIP, { uri })}
+ />
+
diff --git a/src/renderer/page/file/view.jsx b/src/renderer/page/file/view.jsx
index 4071e9125..e8392ff6c 100644
--- a/src/renderer/page/file/view.jsx
+++ b/src/renderer/page/file/view.jsx
@@ -13,6 +13,7 @@ import DateTime from 'component/dateTime';
import * as icons from 'constants/icons';
import Button from 'component/button';
import SubscribeButton from 'component/subscribeButton';
+import ViewOnWebButton from 'component/viewOnWebButton';
import Page from 'component/page';
import player from 'render-media';
import * as settings from 'constants/settings';
@@ -80,12 +81,7 @@ class FilePage extends React.Component {
}
checkSubscription = (props: Props) => {
- if (
- props.claim.value.publisherSignature &&
- props.subscriptions
- .map(subscription => subscription.channelName)
- .indexOf(props.claim.channel_name) !== -1
- ) {
+ if (props.subscriptions.find(sub => sub.channelName === props.claim.channel_name)) {
props.checkSubscription({
channelName: props.claim.channel_name,
uri: buildURI(
@@ -114,6 +110,7 @@ class FilePage extends React.Component {
prepareEdit,
navigate,
autoplay,
+ costInfo,
} = this.props;
// File info
@@ -130,6 +127,11 @@ class FilePage extends React.Component {
if (channelName && channelClaimId) {
subscriptionUri = buildURI({ channelName, claimId: channelClaimId }, false);
}
+ const speechSharable =
+ costInfo &&
+ costInfo.cost === 0 &&
+ contentType &&
+ ['video', 'image'].includes(contentType.split('/')[0]);
// We want to use the short form uri for editing
// This is what the user is used to seeing, they don't care about the claim id
@@ -191,6 +193,14 @@ class FilePage extends React.Component {
)}
+ {speechSharable && (
+
+ )}
diff --git a/src/renderer/scss/component/_form-field.scss b/src/renderer/scss/component/_form-field.scss
index 8b814dbf0..9dd03b5d7 100644
--- a/src/renderer/scss/component/_form-field.scss
+++ b/src/renderer/scss/component/_form-field.scss
@@ -62,6 +62,10 @@
width: 35px;
}
+ input.paginate-channel {
+ width: 35px;
+ }
+
&.form-field--auto-height {
height: auto;
}
From b5d8b57043848aaed1f0be46d84523ad2d67a717 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Fri, 25 May 2018 10:44:48 -0400
Subject: [PATCH 19/34] set default route back to /discover
---
src/renderer/redux/reducers/navigation.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/renderer/redux/reducers/navigation.js b/src/renderer/redux/reducers/navigation.js
index 80a5e0259..e4544b4cc 100644
--- a/src/renderer/redux/reducers/navigation.js
+++ b/src/renderer/redux/reducers/navigation.js
@@ -3,7 +3,7 @@ import * as ACTIONS from 'constants/action_types';
const getCurrentPath = () => {
const { hash } = document.location;
if (hash !== '') return hash.replace(/^#/, '');
- return '/publish';
+ return '/discover';
};
const reducers = {};
From 9e6270ad0efa47f118be4c43c39847b54efea24e Mon Sep 17 00:00:00 2001
From: Travis Eden
Date: Fri, 25 May 2018 12:16:17 -0400
Subject: [PATCH 20/34] do not display "PRICE"; return null when costInfo is
undefined
---
src/renderer/component/filePrice/view.jsx | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/src/renderer/component/filePrice/view.jsx b/src/renderer/component/filePrice/view.jsx
index 090c93126..e40a6c25e 100644
--- a/src/renderer/component/filePrice/view.jsx
+++ b/src/renderer/component/filePrice/view.jsx
@@ -35,20 +35,14 @@ class FilePrice extends React.PureComponent {
render() {
const { costInfo, showFullPrice } = this.props;
- const isEstimate = costInfo ? !costInfo.includesData : false;
-
- if (!costInfo) {
- return PRICE ;
- }
-
- return (
+ return costInfo ? (
- );
+ ) : null;
}
}
From ef3ea8c319bb0c8a13f956db19af8bfa63b47284 Mon Sep 17 00:00:00 2001
From: Travis Eden
Date: Thu, 17 May 2018 16:31:49 -0400
Subject: [PATCH 21/34] Refactor unclaimed rewards as array to keep order from
api.lbry.io. Display reward notification message through snackbar with
fallback for rewards without a message.
---
src/renderer/component/rewardLink/index.js | 2 +-
src/renderer/component/userVerify/index.js | 6 +--
src/renderer/modal/modalFirstReward/index.js | 2 +-
src/renderer/redux/actions/rewards.js | 10 ++---
src/renderer/redux/reducers/rewards.js | 31 +++++++--------
src/renderer/redux/selectors/rewards.js | 15 ++-----
src/renderer/rewards.js | 41 +-------------------
7 files changed, 29 insertions(+), 78 deletions(-)
diff --git a/src/renderer/component/rewardLink/index.js b/src/renderer/component/rewardLink/index.js
index 9ecfe0dba..f7e3561ef 100644
--- a/src/renderer/component/rewardLink/index.js
+++ b/src/renderer/component/rewardLink/index.js
@@ -16,7 +16,7 @@ const makeSelect = () => {
const select = (state, props) => ({
errorMessage: selectError(state, props),
isPending: selectIsPending(state, props),
- reward: selectReward(state, props),
+ reward: selectReward(state, props.reward_type),
});
return select;
diff --git a/src/renderer/component/userVerify/index.js b/src/renderer/component/userVerify/index.js
index a6ca5a554..b139c96c1 100644
--- a/src/renderer/component/userVerify/index.js
+++ b/src/renderer/component/userVerify/index.js
@@ -1,4 +1,5 @@
import { connect } from 'react-redux';
+import { doNotify, MODALS } from 'lbry-redux';
import { doNavigate } from 'redux/actions/navigation';
import { doUserIdentityVerify } from 'redux/actions/user';
import rewards from 'rewards';
@@ -8,15 +9,14 @@ import {
selectIdentityVerifyErrorMessage,
} from 'redux/selectors/user';
import UserVerify from './view';
-import { doNotify, MODALS } from 'lbry-redux';
-const select = (state, props) => {
+const select = state => {
const selectReward = makeSelectRewardByType();
return {
isPending: selectIdentityVerifyIsPending(state),
errorMessage: selectIdentityVerifyErrorMessage(state),
- reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
+ reward: selectReward(state, rewards.TYPE_NEW_USER),
};
};
diff --git a/src/renderer/modal/modalFirstReward/index.js b/src/renderer/modal/modalFirstReward/index.js
index f3f2576e9..c38b9d7e0 100644
--- a/src/renderer/modal/modalFirstReward/index.js
+++ b/src/renderer/modal/modalFirstReward/index.js
@@ -8,7 +8,7 @@ const select = state => {
const selectReward = makeSelectRewardByType();
return {
- reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
+ reward: selectReward(state, rewards.TYPE_NEW_USER),
};
};
diff --git a/src/renderer/redux/actions/rewards.js b/src/renderer/redux/actions/rewards.js
index dd4446f3f..581772a3d 100644
--- a/src/renderer/redux/actions/rewards.js
+++ b/src/renderer/redux/actions/rewards.js
@@ -1,7 +1,7 @@
import * as ACTIONS from 'constants/action_types';
import Lbryio from 'lbryio';
import { doNotify, MODALS } from 'lbry-redux';
-import { selectUnclaimedRewardsByType } from 'redux/selectors/rewards';
+import { selectUnclaimedRewards } from 'redux/selectors/rewards';
import { selectUserIsRewardApproved } from 'redux/selectors/user';
import rewards from 'rewards';
@@ -30,8 +30,8 @@ export function doRewardList() {
export function doClaimRewardType(rewardType) {
return (dispatch, getState) => {
const state = getState();
- const rewardsByType = selectUnclaimedRewardsByType(state);
- const reward = rewardsByType[rewardType];
+ const unclaimedRewards = selectUnclaimedRewards(state);
+ const reward = unclaimedRewards.find(ur => ur.reward_type === rewardType);
const userIsRewardApproved = selectUserIsRewardApproved(state);
if (!reward || reward.transaction_id) {
@@ -84,14 +84,14 @@ export function doClaimRewardType(rewardType) {
export function doClaimEligiblePurchaseRewards() {
return (dispatch, getState) => {
const state = getState();
- const rewardsByType = selectUnclaimedRewardsByType(state);
+ const unclaimedRewards = selectUnclaimedRewards(state);
const userIsRewardApproved = selectUserIsRewardApproved(state);
if (!userIsRewardApproved || !Lbryio.enabled) {
return;
}
- if (rewardsByType[rewards.TYPE_FIRST_STREAM]) {
+ if (unclaimedRewards.find(ur => ur.reward_type === rewards.TYPE_FIRST_STREAM)) {
dispatch(doClaimRewardType(rewards.TYPE_FIRST_STREAM));
} else {
[rewards.TYPE_MANY_DOWNLOADS, rewards.TYPE_FEATURED_DOWNLOAD].forEach(type => {
diff --git a/src/renderer/redux/reducers/rewards.js b/src/renderer/redux/reducers/rewards.js
index f2f42c004..a448ca051 100644
--- a/src/renderer/redux/reducers/rewards.js
+++ b/src/renderer/redux/reducers/rewards.js
@@ -4,7 +4,7 @@ const reducers = {};
const defaultState = {
fetching: false,
claimedRewardsById: {}, // id => reward
- unclaimedRewardsByType: {},
+ unclaimedRewards: [],
claimPendingByType: {},
claimErrorsByType: {},
};
@@ -17,19 +17,19 @@ reducers[ACTIONS.FETCH_REWARDS_STARTED] = state =>
reducers[ACTIONS.FETCH_REWARDS_COMPLETED] = (state, action) => {
const { userRewards } = action.data;
- const unclaimedRewards = {};
+ const unclaimedRewards = [];
const claimedRewards = {};
userRewards.forEach(reward => {
if (reward.transaction_id) {
claimedRewards[reward.id] = reward;
} else {
- unclaimedRewards[reward.reward_type] = reward;
+ unclaimedRewards.push(reward);
}
});
return Object.assign({}, state, {
claimedRewardsById: claimedRewards,
- unclaimedRewardsByType: unclaimedRewards,
+ unclaimedRewards,
fetching: false,
});
};
@@ -62,24 +62,21 @@ reducers[ACTIONS.CLAIM_REWARD_STARTED] = (state, action) => {
reducers[ACTIONS.CLAIM_REWARD_SUCCESS] = (state, action) => {
const { reward } = action.data;
+ let { unclaimedRewards } = state;
- const unclaimedRewardsByType = Object.assign({}, state.unclaimedRewardsByType);
- const existingReward = unclaimedRewardsByType[reward.reward_type];
+ const index = unclaimedRewards.findIndex(ur => ur.reward_type === reward.reward_type);
+ unclaimedRewards = unclaimedRewards.slice(0, index).concat(unclaimedRewards.slice(index + 1));
- const newReward = Object.assign({}, reward, {
- reward_title: existingReward.reward_title,
- reward_description: existingReward.reward_description,
- });
+ const { claimedRewardsById } = state;
+ claimedRewardsById[reward.id] = reward;
- const claimedRewardsById = Object.assign({}, state.claimedRewardsById);
- claimedRewardsById[reward.id] = newReward;
-
- const newState = Object.assign({}, state, {
- unclaimedRewardsByType,
+ const newState = {
+ ...state,
+ unclaimedRewards,
claimedRewardsById,
- });
+ };
- return setClaimRewardState(newState, newReward, false, '');
+ return setClaimRewardState(newState, reward, false, '');
};
reducers[ACTIONS.CLAIM_REWARD_FAILURE] = (state, action) => {
diff --git a/src/renderer/redux/selectors/rewards.js b/src/renderer/redux/selectors/rewards.js
index cb0c83f52..c7fd3ef3d 100644
--- a/src/renderer/redux/selectors/rewards.js
+++ b/src/renderer/redux/selectors/rewards.js
@@ -1,5 +1,4 @@
import { createSelector } from 'reselect';
-import REWARDS from 'rewards';
const selectState = state => state.rewards || {};
@@ -26,16 +25,7 @@ export const selectClaimedRewardsByTransactionId = createSelector(selectClaimedR
}, {})
);
-export const selectUnclaimedRewards = createSelector(
- selectUnclaimedRewardsByType,
- byType =>
- Object.values(byType).sort(
- (a, b) =>
- REWARDS.SORT_ORDER.indexOf(a.reward_type) < REWARDS.SORT_ORDER.indexOf(b.reward_type)
- ? -1
- : 1
- ) || []
-);
+export const selectUnclaimedRewards = createSelector(selectState, state => state.unclaimedRewards);
export const selectFetchingRewards = createSelector(selectState, state => !!state.fetching);
@@ -65,7 +55,8 @@ const selectClaimRewardError = (state, props) =>
export const makeSelectClaimRewardError = () =>
createSelector(selectClaimRewardError, errorMessage => errorMessage);
-const selectRewardByType = (state, props) => selectUnclaimedRewardsByType(state)[props.reward_type];
+const selectRewardByType = (state, rewardType) =>
+ selectUnclaimedRewards(state).find(reward => reward.reward_type === rewardType);
export const makeSelectRewardByType = () => createSelector(selectRewardByType, reward => reward);
diff --git a/src/renderer/rewards.js b/src/renderer/rewards.js
index 9905866d3..840400c6e 100644
--- a/src/renderer/rewards.js
+++ b/src/renderer/rewards.js
@@ -1,46 +1,8 @@
import { Lbry, doNotify } from 'lbry-redux';
import Lbryio from 'lbryio';
-function rewardMessage(type, amount) {
- return {
- new_developer: __('You earned %s for registering as a new developer.', amount),
- new_user: __('You earned %s LBC new user reward.', amount),
- verified_email: __('You earned %s LBC for verifying your email address.', amount),
- new_channel: __('You earned %s LBC for creating a publisher identity.', amount),
- first_stream: __('You earned %s LBC for streaming your first video.', amount),
- many_downloads: __('You earned %s LBC for downloading a bunch of things.', amount),
- first_publish: __('You earned %s LBC for making your first publication.', amount),
- featured_download: __('You earned %s LBC for watching a featured download.', amount),
- referral: __('You earned %s LBC for referring someone.', amount),
- youtube_creator: __('You earned %s LBC for syncing your YouTube channel.', amount),
- }[type];
-}
-
const rewards = {};
-rewards.TYPE_NEW_DEVELOPER = 'new_developer';
-rewards.TYPE_NEW_USER = 'new_user';
-rewards.TYPE_CONFIRM_EMAIL = 'verified_email';
-rewards.TYPE_FIRST_CHANNEL = 'new_channel';
-rewards.TYPE_FIRST_STREAM = 'first_stream';
-rewards.TYPE_MANY_DOWNLOADS = 'many_downloads';
-rewards.TYPE_FIRST_PUBLISH = 'first_publish';
-rewards.TYPE_FEATURED_DOWNLOAD = 'featured_download';
-rewards.TYPE_REFERRAL = 'referral';
-rewards.YOUTUBE_CREATOR = 'youtube_creator';
-rewards.SORT_ORDER = [
- rewards.TYPE_NEW_USER,
- rewards.TYPE_CONFIRM_EMAIL,
- rewards.TYPE_FIRST_STREAM,
- rewards.TYPE_FIRST_CHANNEL,
- rewards.TYPE_FIRST_PUBLISH,
- rewards.TYPE_FEATURED_DOWNLOAD,
- rewards.TYPE_MANY_DOWNLOADS,
- rewards.TYPE_REFERRAL,
- rewards.TYPE_NEW_DEVELOPER,
- rewards.YOUTUBE_CREATOR,
-];
-
rewards.claimReward = type => {
function requestReward(resolve, reject, params) {
if (!Lbryio.enabled) {
@@ -48,7 +10,8 @@ rewards.claimReward = type => {
return;
}
Lbryio.call('reward', 'new', params, 'post').then(reward => {
- const message = rewardMessage(type, reward.reward_amount);
+ const message =
+ reward.reward_notification || `You have claimed a ${reward.reward_amount} LBC reward.`;
// Display global notice
const action = doNotify({
From 6ba6ed5ffbe06a29a304579839e980ba1d423c0a Mon Sep 17 00:00:00 2001
From: seanyesmunt
Date: Tue, 29 May 2018 22:41:59 -0400
Subject: [PATCH 22/34] update changelog
---
CHANGELOG.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 981bf6cea..ff500fb76 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
* Pre-fill publish URL after clicking "Put something here" link ([#1303](https://github.com/lbryio/lbry-app/pull/1303))
* Add Danger JS to automate code reviews ([#1289](https://github.com/lbryio/lbry-app/pull/1289))
* Autoplay downloaded and free media ([#584](https://github.com/lbryio/lbry-app/pull/1453))
+ * Add 'Go to page' input on channel pagination ([#1166](https://github.com/lbryio/lbry-app/pull/1166))
+ * Add "View on web" button on file/channel pages with spee.ch link ([#1222](https://github.com/lbryio/lbry-app/pull/1222))
### Changed
* Add flair to snackbar ([#1313](https://github.com/lbryio/lbry-app/pull/1313))
From 18433c2c9e1617328b0e7784ae8ba9cb646191db Mon Sep 17 00:00:00 2001
From: seanyesmunt
Date: Wed, 30 May 2018 03:23:14 -0400
Subject: [PATCH 23/34] fix build
---
.travis.yml | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 473dc35d6..7997139a5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,16 +1,19 @@
matrix:
include:
- os: osx
+ env: TARGET=mac
osx_image: xcode9.2
language: node_js
node_js: "9"
- env:
- - ELECTRON_CACHE=$HOME/.cache/electron
- - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder
- os: linux
+ env: TARGET=windows
services: docker
language: node_js
node_js: "9"
+ - os: linux
+ env: TARGET=linux
+ language: node_js
+ node_js: "9"
cache: false
before_install:
- |
@@ -20,6 +23,7 @@ before_install:
else
sudo apt-get -qq update
sudo apt-get install -y libsecret-1-dev
+ sudo apt-get install --no-install-recommends -y gcc-multilib g++-multilib
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.6.0
export PATH="$HOME/.yarn/bin:$PATH"
fi
@@ -27,17 +31,15 @@ before_script:
- git lfs pull
script:
- |
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then
+ if [ "$TARGET" == "windows" ]; then
docker run --rm \
--env-file <(env | grep -iE 'DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS|APPVEYOR_|CSC_|GH_|GITHUB_|BT_|AWS_|STRIP|BUILD_') \
-v ${PWD}:/project \
- -v ~/.cache/electron:/root/.cache/electron \
- -v ~/.cache/electron-builder:/root/.cache/electron-builder \
electronuserland/builder:wine \
- /bin/bash -c "yarn --link-duplicates --pure-lockfile && yarn build --linux --win --publish onTag"
- else
- yarn build --publish onTag
+ /bin/bash -c "yarn --link-duplicates --pure-lockfile && yarn build --win --publish onTag";
fi
+ - if [ "$TARGET" == "mac" ]; then yarn build --publish onTag; fi
+ - if [ "$TARGET" == "linux" ]; then yarn --link-duplicates --pure-lockfile && yarn build --linux --publish onTag; fi
branches:
except:
- "/^v\\d+\\.\\d+\\.\\d+$/"
From f0f30e42a9303c6c9ad738806a088e9bcd89d4a3 Mon Sep 17 00:00:00 2001
From: Thomas Zarebczan
Date: Wed, 30 May 2018 09:12:09 -0400
Subject: [PATCH 24/34] changelog note
---
CONTRIBUTING.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d6c05963c..07edc7648 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -146,6 +146,8 @@ There are a few tools integrated to the project that will ease the process of de
manner and, therefore, not begin working on anything reserved (or updated) within the last 3 days.
If someone has been officially assigned an issue via Github's assignment system, it is also not
available. Contributors are encouraged to ask if they have any questions about issue availability.
+* The [changelog](https://github.com/lbryio/lbry-app/blob/master/CHANGELOG.md) should be updated to
+ include a referene to the fix/change/addition. See previous entries for format.
* Once the pull request is visible in the LBRY repo, a LBRY team member will review it and make sure
it is up to our standards. At this point, the contributor may have to change his or her code based
on our suggestions and comments.
From c1496fb8ebb6802d9422a1aac6bf8806e1d8c4c4 Mon Sep 17 00:00:00 2001
From: Thomas Zarebczan
Date: Wed, 30 May 2018 09:16:20 -0400
Subject: [PATCH 25/34] fix windows delete statement
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 2e745e758..8826ff10b 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@ distributable packages.
#### Resetting your Packages
-If the app isn't building, or `yarn xxx` commands aren't working you may need to just reset your `node_modules`. To do so you can run: `rm -r node_modules && yarn` or `del node_modules && yarn` on Windows.
+If the app isn't building, or `yarn xxx` commands aren't working you may need to just reset your `node_modules`. To do so you can run: `rm -r node_modules && yarn` or `del /s /q node_modules && yarn` on Windows.
## Contributing
From b8865b76f9016dbbaf1ad22b1a8cf2a0300b6af8 Mon Sep 17 00:00:00 2001
From: Sean Yesmunt
Date: Wed, 30 May 2018 10:21:16 -0400
Subject: [PATCH 26/34] bump lbry-redux
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 3337b697d..bcf7cf160 100644
--- a/package.json
+++ b/package.json
@@ -48,7 +48,7 @@
"formik": "^0.10.4",
"hast-util-sanitize": "^1.1.2",
"keytar": "^4.2.1",
- "lbry-redux": "lbryio/lbry-redux#c41899e78415cae6fcb7bfca0e6ba48bb6bfe6c4",
+ "lbry-redux": "lbryio/lbry-redux#fb27fb66387043be1b7962cd9439845fa73d7d8e",
"localforage": "^1.7.1",
"mixpanel-browser": "^2.17.1",
"moment": "^2.22.0",
From 8011b1e3beceda61565fe37d76ac1ac5c73b4eb4 Mon Sep 17 00:00:00 2001
From: Travis Eden
Date: Wed, 30 May 2018 12:06:09 -0400
Subject: [PATCH 27/34] re-add reward type constants
---
src/renderer/rewards.js | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src/renderer/rewards.js b/src/renderer/rewards.js
index 840400c6e..9da3727a9 100644
--- a/src/renderer/rewards.js
+++ b/src/renderer/rewards.js
@@ -3,6 +3,17 @@ import Lbryio from 'lbryio';
const rewards = {};
+rewards.TYPE_NEW_DEVELOPER = 'new_developer';
+rewards.TYPE_NEW_USER = 'new_user';
+rewards.TYPE_CONFIRM_EMAIL = 'verified_email';
+rewards.TYPE_FIRST_CHANNEL = 'new_channel';
+rewards.TYPE_FIRST_STREAM = 'first_stream';
+rewards.TYPE_MANY_DOWNLOADS = 'many_downloads';
+rewards.TYPE_FIRST_PUBLISH = 'first_publish';
+rewards.TYPE_FEATURED_DOWNLOAD = 'featured_download';
+rewards.TYPE_REFERRAL = 'referral';
+rewards.YOUTUBE_CREATOR = 'youtube_creator';
+
rewards.claimReward = type => {
function requestReward(resolve, reject, params) {
if (!Lbryio.enabled) {
From 186c4379557e14c3dce68b4ccd2886577c01deab Mon Sep 17 00:00:00 2001
From: Travis Eden
Date: Wed, 30 May 2018 12:07:56 -0400
Subject: [PATCH 28/34] simplify first reward
---
src/renderer/modal/modalFirstReward/view.jsx | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/src/renderer/modal/modalFirstReward/view.jsx b/src/renderer/modal/modalFirstReward/view.jsx
index 5d86e3636..c2f7481eb 100644
--- a/src/renderer/modal/modalFirstReward/view.jsx
+++ b/src/renderer/modal/modalFirstReward/view.jsx
@@ -6,7 +6,7 @@ import CreditAmount from 'component/common/credit-amount';
class ModalFirstReward extends React.PureComponent {
render() {
- const { closeModal, reward } = this.props;
+ const { closeModal } = this.props;
return (
{__('Your First Reward')}
-
- {__('You just earned your first reward of')}{' '}
- .
-
+ {__('You just earned your first reward.')}
{__(
"This reward will show in your Wallet in the top right momentarily (if it hasn't already)."
From cb85b633f770b5d73aad1ee16f1379d21f05260e Mon Sep 17 00:00:00 2001
From: Travis Eden
Date: Wed, 30 May 2018 12:09:01 -0400
Subject: [PATCH 29/34] use splice to remove reward; force update in newState
data
---
src/renderer/redux/reducers/rewards.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/renderer/redux/reducers/rewards.js b/src/renderer/redux/reducers/rewards.js
index a448ca051..67f861e6c 100644
--- a/src/renderer/redux/reducers/rewards.js
+++ b/src/renderer/redux/reducers/rewards.js
@@ -62,18 +62,18 @@ reducers[ACTIONS.CLAIM_REWARD_STARTED] = (state, action) => {
reducers[ACTIONS.CLAIM_REWARD_SUCCESS] = (state, action) => {
const { reward } = action.data;
- let { unclaimedRewards } = state;
+ const { unclaimedRewards } = state;
const index = unclaimedRewards.findIndex(ur => ur.reward_type === reward.reward_type);
- unclaimedRewards = unclaimedRewards.slice(0, index).concat(unclaimedRewards.slice(index + 1));
+ unclaimedRewards.splice(index, 1);
const { claimedRewardsById } = state;
claimedRewardsById[reward.id] = reward;
const newState = {
...state,
- unclaimedRewards,
- claimedRewardsById,
+ unclaimedRewards: [...unclaimedRewards],
+ claimedRewardsById: { ...claimedRewardsById },
};
return setClaimRewardState(newState, reward, false, '');
From 6ce77f7a8b197d448ba4c3f516b2c2e4587d41c9 Mon Sep 17 00:00:00 2001
From: Thomas Zarebczan
Date: Wed, 30 May 2018 13:21:56 -0400
Subject: [PATCH 30/34] adding exclamation after first reward
---
src/renderer/modal/modalFirstReward/view.jsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/renderer/modal/modalFirstReward/view.jsx b/src/renderer/modal/modalFirstReward/view.jsx
index c2f7481eb..510716386 100644
--- a/src/renderer/modal/modalFirstReward/view.jsx
+++ b/src/renderer/modal/modalFirstReward/view.jsx
@@ -18,7 +18,7 @@ class ModalFirstReward extends React.PureComponent {
>
{__('Your First Reward')}
- {__('You just earned your first reward.')}
+ {__('You just earned your first reward!')}
{__(
"This reward will show in your Wallet in the top right momentarily (if it hasn't already)."
From 8b895caf151035e4b8e16cde9bb34f78beafa14a Mon Sep 17 00:00:00 2001
From: Travis Eden
Date: Wed, 30 May 2018 13:51:20 -0400
Subject: [PATCH 31/34] remove amount from new invite component
---
src/renderer/component/inviteNew/index.js | 21 ++++++---------------
src/renderer/component/inviteNew/view.jsx | 5 ++---
2 files changed, 8 insertions(+), 18 deletions(-)
diff --git a/src/renderer/component/inviteNew/index.js b/src/renderer/component/inviteNew/index.js
index b0e00c8db..bfb65ab39 100644
--- a/src/renderer/component/inviteNew/index.js
+++ b/src/renderer/component/inviteNew/index.js
@@ -1,26 +1,17 @@
-import React from 'react';
import { connect } from 'react-redux';
-import InviteNew from './view';
import {
selectUserInvitesRemaining,
selectUserInviteNewIsPending,
selectUserInviteNewErrorMessage,
} from 'redux/selectors/user';
-import rewards from 'rewards';
-import { makeSelectRewardAmountByType } from 'redux/selectors/rewards';
-
import { doUserInviteNew } from 'redux/actions/user';
+import InviteNew from './view';
-const select = state => {
- const selectReward = makeSelectRewardAmountByType();
-
- return {
- errorMessage: selectUserInviteNewErrorMessage(state),
- invitesRemaining: selectUserInvitesRemaining(state),
- isPending: selectUserInviteNewIsPending(state),
- rewardAmount: selectReward(state, { reward_type: rewards.TYPE_REFERRAL }),
- };
-};
+const select = state => ({
+ errorMessage: selectUserInviteNewErrorMessage(state),
+ invitesRemaining: selectUserInvitesRemaining(state),
+ isPending: selectUserInviteNewIsPending(state),
+});
const perform = dispatch => ({
inviteNew: email => dispatch(doUserInviteNew(email)),
diff --git a/src/renderer/component/inviteNew/view.jsx b/src/renderer/component/inviteNew/view.jsx
index e3cafa568..d4c292f70 100644
--- a/src/renderer/component/inviteNew/view.jsx
+++ b/src/renderer/component/inviteNew/view.jsx
@@ -29,8 +29,7 @@ class FormInviteNew extends React.PureComponent {
}
render() {
- const { errorMessage, isPending, rewardAmount } = this.props;
- const label = `${__('Get')} ${rewardAmount} LBC`;
+ const { errorMessage, isPending } = this.props;
return (
-
+
);
From 32fd9e17f77acc28cbf178b4a2a0615611de5232 Mon Sep 17 00:00:00 2001
From: seanyesmunt
Date: Wed, 30 May 2018 14:29:22 -0400
Subject: [PATCH 32/34] Redirect special LBRY urls to pages in App
---
src/main/index.js | 5 ++++-
src/renderer/component/router/index.js | 4 ++--
src/renderer/component/router/view.jsx | 13 +++++++++----
src/renderer/index.js | 15 +++++++++++++--
4 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/src/main/index.js b/src/main/index.js
index 2591e20f6..bb8501d93 100644
--- a/src/main/index.js
+++ b/src/main/index.js
@@ -242,8 +242,11 @@ const isSecondInstance = app.makeSingleInstance(argv => {
// path, so we just strip it off.
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
+ // - ? also interpreted as an anchor, remove slash also.
if (process.platform === 'win32') {
- URI = URI.replace(/\/$/, '').replace('/#', '#');
+ URI = URI.replace(/\/$/, '')
+ .replace('/#', '#')
+ .replace('/?', '?');
}
rendererWindow.webContents.send('open-uri-requested', URI);
diff --git a/src/renderer/component/router/index.js b/src/renderer/component/router/index.js
index 0e2a262cb..20933d960 100644
--- a/src/renderer/component/router/index.js
+++ b/src/renderer/component/router/index.js
@@ -1,5 +1,5 @@
import { connect } from 'react-redux';
-import { selectCurrentPage, selectCurrentParams } from 'lbry-redux';
+import { selectCurrentPage, selectCurrentParams, doNotify } from 'lbry-redux';
import Router from './view';
const select = state => ({
@@ -7,4 +7,4 @@ const select = state => ({
currentPage: selectCurrentPage(state),
});
-export default connect(select, null)(Router);
+export default connect(select, { doNotify })(Router);
diff --git a/src/renderer/component/router/view.jsx b/src/renderer/component/router/view.jsx
index f67e252a3..34728ace5 100644
--- a/src/renderer/component/router/view.jsx
+++ b/src/renderer/component/router/view.jsx
@@ -18,16 +18,21 @@ import InvitePage from 'page/invite';
import BackupPage from 'page/backup';
import SubscriptionsPage from 'page/subscriptions';
-const route = (page, routesMap) => {
+const route = (props, page, routesMap) => {
const component = routesMap[page];
-
- return component || DiscoverPage;
+ if (!component) {
+ props.doNotify({
+ message: __('Invalid page requested'),
+ displayType: ['snackbar'],
+ });
+ }
+ return component || routesMap.discover;
};
const Router = props => {
const { currentPage, params } = props;
- return route(currentPage, {
+ return route(props, currentPage, {
auth: ,
backup: ,
channel: ,
diff --git a/src/renderer/index.js b/src/renderer/index.js
index c82db3287..090b43920 100644
--- a/src/renderer/index.js
+++ b/src/renderer/index.js
@@ -8,7 +8,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { doConditionalAuthNavigate, doDaemonReady, doAutoUpdate } from 'redux/actions/app';
-import { doNotify, doBlackListedOutpointsSubscribe } from 'lbry-redux';
+import { doNotify, doBlackListedOutpointsSubscribe, isURIValid } from 'lbry-redux';
import { doNavigate } from 'redux/actions/navigation';
import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings';
import { doUserEmailVerify } from 'redux/actions/user';
@@ -18,6 +18,7 @@ import app from './app';
import analytics from './analytics';
const { autoUpdater } = remote.require('electron-updater');
+const APPPAGEURL = 'lbry://?';
autoUpdater.logger = remote.require('electron-log');
@@ -41,8 +42,18 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
})
);
}
- } else {
+ } else if (uri.startsWith(APPPAGEURL)) {
+ const navpage = uri.replace(APPPAGEURL, '').toLowerCase();
+ app.store.dispatch(doNavigate(`/${navpage}`));
+ } else if (isURIValid(uri)) {
app.store.dispatch(doNavigate('/show', { uri }));
+ } else {
+ app.store.dispatch(
+ doNotify({
+ message: __('Invalid LBRY URL requested'),
+ displayType: ['snackbar'],
+ })
+ );
}
}
});
From c79affaeb82791befda1b86de50d2cadbdea5dc7 Mon Sep 17 00:00:00 2001
From: seanyesmunt
Date: Thu, 31 May 2018 00:42:45 -0400
Subject: [PATCH 33/34] use Uppercase for button label
---
src/renderer/component/inviteNew/view.jsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/renderer/component/inviteNew/view.jsx b/src/renderer/component/inviteNew/view.jsx
index d4c292f70..8b9a54b6b 100644
--- a/src/renderer/component/inviteNew/view.jsx
+++ b/src/renderer/component/inviteNew/view.jsx
@@ -48,7 +48,7 @@ class FormInviteNew extends React.PureComponent {
/>
-
+
);
From 27819a295659faf140618483f30985d5be235a21 Mon Sep 17 00:00:00 2001
From: seanyesmunt
Date: Thu, 31 May 2018 00:45:58 -0400
Subject: [PATCH 34/34] update changelog
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4f0e50e0f..db53fa589 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
* Add flair to snackbar ([#1313](https://github.com/lbryio/lbry-app/pull/1313))
* Made font in price badge larger ([#1420](https://github.com/lbryio/lbry-app/pull/1420))
* Store subscriptions in internal database ([#1424](https://github.com/lbryio/lbry-app/pull/1424))
+ * Move rewards logic to interal api ([#1509](https://github.com/lbryio/lbry-app/pull/1509))
### Fixed
* Fix content-type not shown correctly in file description ([#863](https://github.com/lbryio/lbry-app/pull/863))