Merge pull request #1066 from lbryio/subscribe-notify

Subscribe notify
This commit is contained in:
Liam Cardenas 2018-03-07 21:13:26 -08:00 committed by GitHub
commit 2342bad84b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 218 additions and 12 deletions

View file

@ -15,8 +15,8 @@ class FileList extends React.PureComponent {
this._sortFunctions = {
dateNew(fileInfos) {
return fileInfos.slice().sort((fileInfo1, fileInfo2) => {
const height1 = fileInfo1.height
const height2 = fileInfo2.height
const height1 = fileInfo1.height;
const height2 = fileInfo2.height;
if (height1 > height2) {
return -1;
} else if (height1 < height2) {
@ -27,8 +27,8 @@ class FileList extends React.PureComponent {
},
dateOld(fileInfos) {
return fileInfos.slice().sort((fileInfo1, fileInfo2) => {
const height1 = fileInfo1.height
const height2 = fileInfo2.height
const height1 = fileInfo1.height;
const height2 = fileInfo2.height;
if (height1 < height2) {
return -1;
} else if (height1 > height2) {

View file

@ -15,9 +15,9 @@ const RewardSummary = (props: Props) => {
<div className="card__title-primary">
<h3>{__('Rewards')}</h3>
<p className="help">
{__('Read our')}{' '}
<Link href="https://lbry.io/faq/rewards">{__('FAQ')}</Link>{' '}{__('to learn more about LBRY Rewards')}.
</p>
{__('Read our')} <Link href="https://lbry.io/faq/rewards">{__('FAQ')}</Link>{' '}
{__('to learn more about LBRY Rewards')}.
</p>
</div>
<div className="card__content">
{unclaimedRewardAmount > 0 ? (

View file

@ -164,6 +164,10 @@ export const CLEAR_SHAPE_SHIFT = 'CLEAR_SHAPE_SHIFT';
export const CHANNEL_SUBSCRIBE = 'CHANNEL_SUBSCRIBE';
export const CHANNEL_UNSUBSCRIBE = 'CHANNEL_UNSUBSCRIBE';
export const HAS_FETCHED_SUBSCRIPTIONS = 'HAS_FETCHED_SUBSCRIPTIONS';
export const SET_SUBSCRIPTION_LATEST = 'SET_SUBSCRIPTION_LATEST';
export const CHECK_SUBSCRIPTION_STARTED = 'CHECK_SUBSCRIPTION_STARTED';
export const CHECK_SUBSCRIPTION_COMPLETED = 'CHECK_SUBSCRIPTION_COMPLETED';
export const CHECK_SUBSCRIPTIONS_SUBSCRIBE = 'CHECK_SUBSCRIPTIONS_SUBSCRIBE';
// Video controls
export const SET_VIDEO_PAUSE = 'SET_VIDEO_PAUSE';

View file

@ -63,7 +63,7 @@ ipcRenderer.on('window-is-focused', () => {
document.addEventListener('dragover', event => {
event.preventDefault();
})
});
document.addEventListener('drop', event => {
event.preventDefault();
});

View file

@ -4,6 +4,7 @@ import { doFetchFileInfo } from 'redux/actions/file_info';
import { makeSelectFileInfoForUri } from 'redux/selectors/file_info';
import { selectRewardContentClaimIds } from 'redux/selectors/content';
import { doFetchCostInfoForUri } from 'redux/actions/cost_info';
import { checkSubscriptionLatest } from 'redux/actions/subscriptions';
import {
makeSelectClaimForUri,
makeSelectContentTypeForUri,
@ -13,6 +14,7 @@ import { makeSelectCostInfoForUri } from 'redux/selectors/cost_info';
import { selectShowNsfw } from 'redux/selectors/settings';
import FilePage from './view';
import { makeSelectCurrentParam } from 'redux/selectors/navigation';
import { selectSubscriptions } from 'redux/selectors/subscriptions';
const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state),
@ -23,12 +25,15 @@ const select = (state, props) => ({
tab: makeSelectCurrentParam('tab')(state),
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
subscriptions: selectSubscriptions(state),
});
const perform = dispatch => ({
navigate: (path, params) => dispatch(doNavigate(path, params)),
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
checkSubscriptionLatest: (subscription, uri) =>
dispatch(checkSubscriptionLatest(subscription, uri)),
});
export default connect(select, perform)(FilePage);

View file

@ -17,6 +17,7 @@ class FilePage extends React.PureComponent {
componentDidMount() {
this.fetchFileInfo(this.props);
this.fetchCostInfo(this.props);
this.checkSubscriptionLatest(this.props);
}
componentWillReceiveProps(nextProps) {
@ -35,6 +36,28 @@ class FilePage extends React.PureComponent {
}
}
checkSubscriptionLatest(props) {
if (
props.subscriptions
.map(subscription => subscription.channelName)
.indexOf(props.claim.channel_name) !== -1
) {
props.checkSubscriptionLatest(
{
channelName: props.claim.channel_name,
uri: buildURI(
{
contentName: props.claim.channel_name,
claimId: props.claim.value.publisherSignature.certificateId,
},
false
),
},
buildURI({ contentName: props.claim.name, claimId: props.claim.claim_id }, false)
);
}
}
render() {
const {
claim,

View file

@ -11,6 +11,8 @@ import { doFetchDaemonSettings } from 'redux/actions/settings';
import { doAuthenticate } from 'redux/actions/user';
import { doBalanceSubscribe } from 'redux/actions/wallet';
import { doPause } from 'redux/actions/media';
import { doCheckSubscriptions } from 'redux/actions/subscriptions';
import {
selectCurrentModal,
selectIsUpgradeSkipped,
@ -253,6 +255,7 @@ export function doDaemonReady() {
dispatch(doCheckUpgradeAvailable());
}
dispatch(doCheckUpgradeSubscribe());
dispatch(doCheckSubscriptions());
};
}

View file

@ -7,6 +7,7 @@ import Lbryio from 'lbryio';
import { normalizeURI, buildURI } from 'lbryURI';
import { doAlertError, doOpenModal } from 'redux/actions/app';
import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
import { setSubscriptionLatest } from 'redux/actions/subscriptions';
import { selectBadgeNumber } from 'redux/selectors/app';
import { selectMyClaimsRaw } from 'redux/selectors/claims';
import { selectResolvingUris } from 'redux/selectors/content';
@ -288,7 +289,7 @@ export function doLoadVideo(uri) {
};
}
export function doPurchaseUri(uri) {
export function doPurchaseUri(uri, specificCostInfo) {
return (dispatch, getState) => {
const state = getState();
const balance = selectBalance(state);
@ -321,7 +322,7 @@ export function doPurchaseUri(uri) {
return;
}
const costInfo = makeSelectCostInfoForUri(uri)(state);
const costInfo = makeSelectCostInfoForUri(uri)(state) || specificCostInfo;
const { cost } = costInfo;
if (cost > balance) {
@ -358,6 +359,25 @@ export function doFetchClaimsByChannel(uri, page) {
const claimResult = result[uri] || {};
const { claims_in_channel: claimsInChannel, returned_page: returnedPage } = claimResult;
if (claimsInChannel && claimsInChannel.length) {
const latest = claimsInChannel[0];
dispatch(
setSubscriptionLatest(
{
channelName: latest.channel_name,
uri: buildURI(
{
contentName: latest.channel_name,
claimId: latest.value.publisherSignature.certificateId,
},
false
),
},
buildURI({ contentName: latest.name, claimId: latest.claim_id }, false)
)
);
}
dispatch({
type: ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED,
data: {

View file

@ -1,6 +1,13 @@
// @flow
import * as ACTIONS from 'constants/action_types';
import type { Subscription, Dispatch } from 'redux/reducers/subscriptions';
import type { Subscription, Dispatch, SubscriptionState } from 'redux/reducers/subscriptions';
import { selectSubscriptions } from 'redux/selectors/subscriptions';
import Lbry from 'lbry';
import { doPurchaseUri } from 'redux/actions/content';
import { doNavigate } from 'redux/actions/navigation';
import { buildURI } from 'lbryURI';
const CHECK_SUBSCRIPTIONS_INTERVAL = 10 * 60 * 1000;
export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dispatch) =>
dispatch({
@ -14,5 +21,113 @@ export const doChannelUnsubscribe = (subscription: Subscription) => (dispatch: D
data: subscription,
});
export const doCheckSubscriptions = () => (
dispatch: Dispatch,
getState: () => SubscriptionState
) => {
const checkSubscriptionsTimer = setInterval(
() =>
selectSubscriptions(getState()).map((subscription: Subscription) =>
dispatch(doCheckSubscription(subscription))
),
CHECK_SUBSCRIPTIONS_INTERVAL
);
dispatch({
type: ACTIONS.CHECK_SUBSCRIPTIONS_SUBSCRIBE,
data: { checkSubscriptionsTimer },
});
};
export const doCheckSubscription = (subscription: Subscription) => (dispatch: Dispatch) => {
dispatch({
type: ACTIONS.CHECK_SUBSCRIPTION_STARTED,
data: subscription,
});
Lbry.claim_list_by_channel({ uri: subscription.uri, page: 1 }).then(result => {
const claimResult = result[subscription.uri] || {};
const { claims_in_channel: claimsInChannel } = claimResult;
const count = subscription.latest
? claimsInChannel.reduce(
(prev, cur, index) =>
buildURI({ contentName: cur.name, claimId: cur.claim_id }, false) ===
subscription.latest
? index
: prev,
-1
)
: 1;
if (count !== 0) {
if (!claimsInChannel[0].value.stream.metadata.fee) {
dispatch(
doPurchaseUri(
buildURI(
{ contentName: claimsInChannel[0].name, claimId: claimsInChannel[0].claim_id },
false
),
{ cost: 0 }
)
);
}
const notif = new window.Notification(subscription.channelName, {
body: `Posted ${claimsInChannel[0].value.stream.metadata.title}${
count > 1 ? ` and ${count - 1} other new items` : ''
}${count < 0 ? ' and 9+ other new items' : ''}`,
silent: false,
});
notif.onclick = () => {
dispatch(
doNavigate('/show', {
uri: buildURI(
{ contentName: claimsInChannel[0].name, claimId: claimsInChannel[0].claim_id },
true
),
})
);
};
}
//$FlowIssue
dispatch({
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
data: subscription,
});
});
};
export const checkSubscriptionLatest = (channel: Subscription, uri: string) => (
dispatch: Dispatch
) => {
Lbry.claim_list_by_channel({ uri: channel.uri, page: 1 }).then(result => {
const claimResult = result[channel.uri] || {};
const { claims_in_channel: claimsInChannel } = claimResult;
if (
claimsInChannel &&
claimsInChannel.length &&
buildURI(
{ contentName: claimsInChannel[0].name, claimId: claimsInChannel[0].claim_id },
false
) === uri
) {
dispatch(setSubscriptionLatest(channel, uri));
}
});
};
export const setSubscriptionLatest = (subscription: Subscription, uri: string) => (
dispatch: Dispatch
) =>
dispatch({
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
data: {
subscription,
uri,
},
});
export const setHasFetchedSubscriptions = () => (dispatch: Dispatch) =>
dispatch({ type: ACTIONS.HAS_FETCHED_SUBSCRIPTIONS });

View file

@ -5,6 +5,7 @@ import { handleActions } from 'util/redux-utils';
export type Subscription = {
channelName: string,
uri: string,
latest: ?string,
};
// Subscription redux types
@ -28,7 +29,30 @@ type HasFetchedSubscriptions = {
type: ACTIONS.HAS_FETCHED_SUBSCRIPTIONS,
};
export type Action = doChannelSubscribe | doChannelUnsubscribe | HasFetchedSubscriptions;
type setSubscriptionLatest = {
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
data: {
subscription: Subscription,
uri: string,
},
};
type CheckSubscriptionStarted = {
type: ACTIONS.CHECK_SUBSCRIPTION_STARTED,
};
type CheckSubscriptionCompleted = {
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
};
export type Action =
| doChannelSubscribe
| doChannelUnsubscribe
| HasFetchedSubscriptions
| setSubscriptionLatest
| CheckSubscriptionStarted
| CheckSubscriptionCompleted
| Function;
export type Dispatch = (action: Action) => any;
const defaultState = {
@ -70,6 +94,18 @@ export default handleActions(
...state,
hasFetchedSubscriptions: true,
}),
[ACTIONS.SET_SUBSCRIPTION_LATEST]: (
state: SubscriptionState,
action: setSubscriptionLatest
): SubscriptionState => ({
...state,
subscriptions: state.subscriptions.map(
subscription =>
subscription.channelName === action.data.subscription.channelName
? { ...subscription, latest: action.data.uri }
: subscription
),
}),
},
defaultState
);