commit
2342bad84b
10 changed files with 218 additions and 12 deletions
|
@ -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) {
|
||||
|
|
|
@ -15,8 +15,8 @@ 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')}.
|
||||
{__('Read our')} <Link href="https://lbry.io/faq/rewards">{__('FAQ')}</Link>{' '}
|
||||
{__('to learn more about LBRY Rewards')}.
|
||||
</p>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -63,7 +63,7 @@ ipcRenderer.on('window-is-focused', () => {
|
|||
|
||||
document.addEventListener('dragover', event => {
|
||||
event.preventDefault();
|
||||
})
|
||||
});
|
||||
document.addEventListener('drop', event => {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue