Merge branch 'master' into three-v2
This commit is contained in:
commit
fe616ad5ab
8 changed files with 66 additions and 52 deletions
|
@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
* CSV and JSON viewer ([#1410](https://github.com/lbryio/lbry-desktop/pull/1410))
|
* CSV and JSON viewer ([#1410](https://github.com/lbryio/lbry-desktop/pull/1410))
|
||||||
* Recommended content on file viewer page ([#1845](https://github.com/lbryio/lbry-desktop/pull/1845))
|
* Recommended content on file viewer page ([#1845](https://github.com/lbryio/lbry-desktop/pull/1845))
|
||||||
* 3D File viewer improvements ([#1870](https://github.com/lbryio/lbry-desktop/pull/1870))
|
* 3D File viewer improvements ([#1870](https://github.com/lbryio/lbry-desktop/pull/1870))
|
||||||
|
* Desktop notification when publish is completed ([#1892](https://github.com/lbryio/lbry-desktop/pull/1892))
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Pass error message from spee.ch API during thumbnail upload ([#1840](https://github.com/lbryio/lbry-desktop/pull/1840))
|
* Pass error message from spee.ch API during thumbnail upload ([#1840](https://github.com/lbryio/lbry-desktop/pull/1840))
|
||||||
|
|
10
README.md
10
README.md
|
@ -5,7 +5,7 @@
|
||||||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/78b627d4f5524792adc48719835e1523)](https://www.codacy.com/app/LBRY/lbry-desktop?utm_source=github.com&utm_medium=referral&utm_content=lbryio/lbry-desktop&utm_campaign=Badge_Grade)
|
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/78b627d4f5524792adc48719835e1523)](https://www.codacy.com/app/LBRY/lbry-desktop?utm_source=github.com&utm_medium=referral&utm_content=lbryio/lbry-desktop&utm_campaign=Badge_Grade)
|
||||||
[![chat on Discord](https://img.shields.io/discord/362322208485277697.svg?logo=discord)](https://chat.lbry.io)
|
[![chat on Discord](https://img.shields.io/discord/362322208485277697.svg?logo=discord)](https://chat.lbry.io)
|
||||||
|
|
||||||
[![forthebadge](https://forthebadge.com/images/badges/certified-steve-bruhle.svg)](https://forthebadge.com)
|
[![forthebadge](https://forthebadge.com/images/badges/60-percent-of-the-time-works-every-time.svg)](https://forthebadge.com)
|
||||||
|
|
||||||
The LBRY app is a graphical browser for the decentralized content marketplace provided by the
|
The LBRY app is a graphical browser for the decentralized content marketplace provided by the
|
||||||
[LBRY](https://lbry.io) protocol. It is essentially the
|
[LBRY](https://lbry.io) protocol. It is essentially the
|
||||||
|
@ -32,10 +32,10 @@ To install from source or make changes to the application, continue to the next
|
||||||
**Community maintained** builds for Arch Linux and Flatpak are available, see below. These installs will need to be updated manually as the in-app update process only supports deb installs at this time.
|
**Community maintained** builds for Arch Linux and Flatpak are available, see below. These installs will need to be updated manually as the in-app update process only supports deb installs at this time.
|
||||||
*Note: If coming from a deb install, the directory structure is different and you'll need to [migrate data](https://lbry.io/faq/backup-data).*
|
*Note: If coming from a deb install, the directory structure is different and you'll need to [migrate data](https://lbry.io/faq/backup-data).*
|
||||||
|
|
||||||
| | Flatpak | Arch
|
| | Flatpak | Arch | Raspberry Pi |
|
||||||
| --------------------- | ------------------------------------------| --------------------------------------------
|
| --------------------- | ------------------------------------------|------------------| --------------------------------------------
|
||||||
| Latest Release | [FlatHub Page](https://flathub.org/apps/details/io.lbry.lbry-app) | [AUR Package](https://aur.archlinux.org/packages/lbry-app-bin/)
|
| Latest Release | [FlatHub Page](https://flathub.org/apps/details/io.lbry.lbry-app) | [AUR Package](https://aur.archlinux.org/packages/lbry-app-bin/) | [Pi Installer](https://lbrypi.com) |
|
||||||
| Maintainers | [@choofee](https://github.com/choffee)/[@iuyte](https://github.com/iuyte) | [@kcseb](https://github.com/kcseb)/[@TimurKiyivinski](https://github.com/TimurKiyivinski)
|
| Maintainers | [@choofee](https://github.com/choffee)/[@iuyte](https://github.com/iuyte) | [@kcseb](https://github.com/kcseb)/[@TimurKiyivinski](https://github.com/TimurKiyivinski) |[@Madiator2011](https://github.com/kodxana)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
Double click the installed application to browse with the LBRY network.
|
Double click the installed application to browse with the LBRY network.
|
||||||
|
|
|
@ -97,10 +97,13 @@ class FilePage extends React.Component<Props> {
|
||||||
checkSubscription = (props: Props) => {
|
checkSubscription = (props: Props) => {
|
||||||
if (props.subscriptions.find(sub => sub.channelName === props.claim.channel_name)) {
|
if (props.subscriptions.find(sub => sub.channelName === props.claim.channel_name)) {
|
||||||
props.checkSubscription(
|
props.checkSubscription(
|
||||||
buildURI({
|
buildURI(
|
||||||
|
{
|
||||||
contentName: props.claim.channel_name,
|
contentName: props.claim.channel_name,
|
||||||
claimId: props.claim.value.publisherSignature.certificateId,
|
claimId: props.claim.value.publisherSignature.certificateId,
|
||||||
}, false)
|
},
|
||||||
|
false
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -157,6 +160,13 @@ class FilePage extends React.Component<Props> {
|
||||||
editUri = buildURI(uriObject);
|
editUri = buildURI(uriObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let recommendedUri = uri;
|
||||||
|
if (!recommendedUri.includes('#')) {
|
||||||
|
// at a vanity url
|
||||||
|
// append the claim ID so we can properly strip it out of reccomended videos
|
||||||
|
recommendedUri = `${recommendedUri}#${claim.claim_id}`;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page forContent>
|
<Page forContent>
|
||||||
<section className="content__wrapper">
|
<section className="content__wrapper">
|
||||||
|
@ -241,7 +251,7 @@ class FilePage extends React.Component<Props> {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<RecommendedContent uri={uri} />
|
<RecommendedContent uri={recommendedUri} />
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import * as settings from 'constants/settings';
|
||||||
import {
|
import {
|
||||||
selectSubscriptionClaims,
|
selectSubscriptionClaims,
|
||||||
selectSubscriptions,
|
selectSubscriptions,
|
||||||
|
@ -6,25 +7,26 @@ import {
|
||||||
selectIsFetchingSubscriptions,
|
selectIsFetchingSubscriptions,
|
||||||
selectNotifications,
|
selectNotifications,
|
||||||
} from 'redux/selectors/subscriptions';
|
} from 'redux/selectors/subscriptions';
|
||||||
import { doFetchClaimsByChannel } from 'redux/actions/content';
|
|
||||||
import { setSubscriptionNotifications, doFetchMySubscriptions } from 'redux/actions/subscriptions';
|
import { setSubscriptionNotifications, doFetchMySubscriptions } from 'redux/actions/subscriptions';
|
||||||
|
import { doSetClientSetting } from 'redux/actions/settings';
|
||||||
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import SubscriptionsPage from './view';
|
import SubscriptionsPage from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
loading:
|
loading:
|
||||||
selectIsFetchingSubscriptions(state) ||
|
selectIsFetchingSubscriptions(state) ||
|
||||||
Boolean(Object.keys(selectSubscriptionsBeingFetched(state)).length),
|
Boolean(Object.keys(selectSubscriptionsBeingFetched(state)).length),
|
||||||
subscriptionsBeingFetched: selectSubscriptionsBeingFetched(state),
|
|
||||||
subscriptions: selectSubscriptions(state),
|
subscriptions: selectSubscriptions(state),
|
||||||
subscriptionClaims: selectSubscriptionClaims(state),
|
subscriptionClaims: selectSubscriptionClaims(state),
|
||||||
notifications: selectNotifications(state),
|
notifications: selectNotifications(state),
|
||||||
|
autoDownload: makeSelectClientSetting(settings.AUTO_DOWNLOAD)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
select,
|
select,
|
||||||
{
|
{
|
||||||
doFetchClaimsByChannel,
|
|
||||||
setSubscriptionNotifications,
|
setSubscriptionNotifications,
|
||||||
doFetchMySubscriptions,
|
doFetchMySubscriptions,
|
||||||
|
doSetClientSetting,
|
||||||
}
|
}
|
||||||
)(SubscriptionsPage);
|
)(SubscriptionsPage);
|
||||||
|
|
|
@ -1,26 +1,32 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
|
import * as settings from 'constants/settings';
|
||||||
import type { Subscription } from 'types/subscription';
|
import type { Subscription } from 'types/subscription';
|
||||||
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import FileList from 'component/fileList';
|
import FileList from 'component/fileList';
|
||||||
import type { Claim } from 'types/claim';
|
import type { Claim } from 'types/claim';
|
||||||
import isDev from 'electron-is-dev';
|
|
||||||
import HiddenNsfwClaims from 'component/hiddenNsfwClaims';
|
import HiddenNsfwClaims from 'component/hiddenNsfwClaims';
|
||||||
|
import { FormField, FormRow } from 'component/common/form';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
doFetchClaimsByChannel: (string, number) => void,
|
|
||||||
doFetchMySubscriptions: () => void,
|
doFetchMySubscriptions: () => void,
|
||||||
setSubscriptionNotifications: ({}) => void,
|
setSubscriptionNotifications: ({}) => void,
|
||||||
subscriptions: Array<Subscription>,
|
subscriptions: Array<Subscription>,
|
||||||
subscriptionClaims: Array<{ uri: string, claims: Array<Claim> }>,
|
subscriptionClaims: Array<{ uri: string, claims: Array<Claim> }>,
|
||||||
subscriptionsBeingFetched: {},
|
|
||||||
notifications: {},
|
notifications: {},
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
|
autoDownload: boolean,
|
||||||
|
doSetClientSetting: (string, boolean) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class extends React.PureComponent<Props> {
|
export default class extends React.PureComponent<Props> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
(this: any).onAutoDownloadChange = this.onAutoDownloadChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { notifications, setSubscriptionNotifications, doFetchMySubscriptions } = this.props;
|
const { notifications, setSubscriptionNotifications, doFetchMySubscriptions } = this.props;
|
||||||
doFetchMySubscriptions();
|
doFetchMySubscriptions();
|
||||||
|
@ -37,43 +43,12 @@ export default class extends React.PureComponent<Props> {
|
||||||
setSubscriptionNotifications(newNotifications);
|
setSubscriptionNotifications(newNotifications);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
onAutoDownloadChange(event: SyntheticInputEvent<*>) {
|
||||||
const {
|
this.props.doSetClientSetting(settings.AUTO_DOWNLOAD, event.target.checked);
|
||||||
subscriptions,
|
|
||||||
subscriptionClaims,
|
|
||||||
doFetchClaimsByChannel,
|
|
||||||
subscriptionsBeingFetched,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const subscriptionClaimMap = {};
|
|
||||||
subscriptionClaims.forEach(claim => {
|
|
||||||
/*
|
|
||||||
This check added 6/20/18 to fix function receiving empty claims unexpectedly.
|
|
||||||
The better fix is ensuring channels aren't added to byId if there are no associated claims
|
|
||||||
We are adding this now with the redesign release to ensure users see the correct subscriptions
|
|
||||||
*/
|
|
||||||
if (claim.claims.length) {
|
|
||||||
subscriptionClaimMap[claim.uri] = 1;
|
|
||||||
} else if (isDev) {
|
|
||||||
// eslint-disable no-console
|
|
||||||
console.error(
|
|
||||||
`Claim for ${
|
|
||||||
claim.uri
|
|
||||||
} was added to byId in redux but there are no loaded fetched claims. This shouldn't happen because a subscription should have claims attached to it.`
|
|
||||||
);
|
|
||||||
// eslint-enable no-console
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
subscriptions.forEach(sub => {
|
|
||||||
if (!subscriptionClaimMap[sub.uri] && !subscriptionsBeingFetched[sub.uri]) {
|
|
||||||
doFetchClaimsByChannel(sub.uri, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { subscriptions, subscriptionClaims, loading } = this.props;
|
const { subscriptions, subscriptionClaims, loading, autoDownload } = this.props;
|
||||||
|
|
||||||
let claimList = [];
|
let claimList = [];
|
||||||
subscriptionClaims.forEach(claimData => {
|
subscriptionClaims.forEach(claimData => {
|
||||||
|
@ -85,6 +60,15 @@ export default class extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<Page notContained loading={loading}>
|
<Page notContained loading={loading}>
|
||||||
<HiddenNsfwClaims uris={subscriptionUris} />
|
<HiddenNsfwClaims uris={subscriptionUris} />
|
||||||
|
<FormRow alignRight>
|
||||||
|
<FormField
|
||||||
|
type="checkbox"
|
||||||
|
name="auto_download"
|
||||||
|
onChange={this.onAutoDownloadChange}
|
||||||
|
checked={autoDownload}
|
||||||
|
prefix={__('Automatically download new content from your subscriptions')}
|
||||||
|
/>
|
||||||
|
</FormRow>
|
||||||
{!subscriptions.length && (
|
{!subscriptions.length && (
|
||||||
<div className="page__empty">
|
<div className="page__empty">
|
||||||
{__("It looks like you aren't subscribed to any channels yet.")}
|
{__("It looks like you aren't subscribed to any channels yet.")}
|
||||||
|
|
|
@ -14,6 +14,8 @@ import type {
|
||||||
UpdatePublishFormAction,
|
UpdatePublishFormAction,
|
||||||
PublishParams,
|
PublishParams,
|
||||||
} from 'redux/reducers/publish';
|
} from 'redux/reducers/publish';
|
||||||
|
import { selectosNotificationsEnabled } from 'redux/selectors/settings';
|
||||||
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
|
@ -274,6 +276,19 @@ export const doCheckPendingPublishes = () => (dispatch: Dispatch, getState: GetS
|
||||||
});
|
});
|
||||||
|
|
||||||
delete pendingPublishMap[claim.name];
|
delete pendingPublishMap[claim.name];
|
||||||
|
if (selectosNotificationsEnabled(getState())) {
|
||||||
|
const notif = new window.Notification('LBRY Publish Complete', {
|
||||||
|
body: `${claim.value.stream.metadata.title} has been published to lbry://${claim.name}. Click here to view it` ,
|
||||||
|
silent: false,
|
||||||
|
});
|
||||||
|
notif.onclick = () => {
|
||||||
|
dispatch(
|
||||||
|
doNavigate('/show', {
|
||||||
|
uri: claim.name,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import type { Subscription } from 'types/subscription';
|
||||||
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import { Lbry, buildURI, parseURI } from 'lbry-redux';
|
import { Lbry, buildURI, parseURI } from 'lbry-redux';
|
||||||
import { doPurchaseUri } from 'redux/actions/content';
|
import { doPurchaseUri, doFetchClaimsByChannel } from 'redux/actions/content';
|
||||||
import { doClaimRewardType } from 'redux/actions/rewards';
|
import { doClaimRewardType } from 'redux/actions/rewards';
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
import Lbryio from 'lbryio';
|
import Lbryio from 'lbryio';
|
||||||
|
@ -91,6 +91,8 @@ export const doFetchMySubscriptions = () => (dispatch: Dispatch, getState: () =>
|
||||||
type: ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS,
|
type: ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS,
|
||||||
data: subscriptions,
|
data: subscriptions,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
subscriptions.forEach(({ uri }) => dispatch(doFetchClaimsByChannel(uri)));
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
|
@ -40,7 +40,7 @@ export function doInstallNew() {
|
||||||
const payload = { app_version: pjson.version };
|
const payload = { app_version: pjson.version };
|
||||||
Lbry.status().then(status => {
|
Lbry.status().then(status => {
|
||||||
payload.app_id = status.installation_id;
|
payload.app_id = status.installation_id;
|
||||||
payload.node_id = status.lbry_id;
|
if (status.dht) payload.node_id = status.dht.node_id;
|
||||||
Lbry.version().then(version => {
|
Lbry.version().then(version => {
|
||||||
payload.daemon_version = version.lbrynet_version;
|
payload.daemon_version = version.lbrynet_version;
|
||||||
payload.operating_system = version.os_system;
|
payload.operating_system = version.os_system;
|
||||||
|
|
Loading…
Reference in a new issue