Subscribe notify #1066
|
@ -64,8 +64,8 @@ app.on('ready', async () => {
|
|||
dialog.showErrorBox(
|
||||
'Daemon has Exited',
|
||||
'The daemon may have encountered an unexpected error, or another daemon instance is already running. \n\n' +
|
||||
'For more information please visit: \n' +
|
||||
'https://lbry.io/faq/startup-troubleshooting'
|
||||
'For more information please visit: \n' +
|
||||
'https://lbry.io/faq/startup-troubleshooting'
|
||||
);
|
||||
app.quit();
|
||||
}
|
||||
|
|
|
@ -15,27 +15,27 @@ 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) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
});
|
||||
},
|
||||
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) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
});
|
||||
},
|
||||
title(fileInfos) {
|
||||
return fileInfos.slice().sort((fileInfo1, fileInfo2) => {
|
||||
|
|
|
@ -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 ? (
|
||||
|
|
|
@ -69,7 +69,7 @@ ipcRenderer.on('window-is-focused', () => {
|
|||
|
||||
document.addEventListener('dragover', event => {
|
||||
event.preventDefault();
|
||||
})
|
||||
});
|
||||
document.addEventListener('drop', event => {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
|
|
@ -30,7 +30,8 @@ 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)),
|
||||
checkSubscriptionLatest: (subscription, uri) =>
|
||||
dispatch(checkSubscriptionLatest(subscription, uri)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(FilePage);
|
||||
|
|
|
@ -37,10 +37,13 @@ class FilePage extends React.PureComponent {
|
|||
}
|
||||
|
||||
checkSubscriptionLatest(props) {
|
||||
props.checkSubscriptionLatest({
|
||||
channelName: props.claim.channel_name,
|
||||
uri: `${props.claim.channel_name}#${props.claim.value.publisherSignature.certificateId}`,
|
||||
}, `${props.claim.name}#${props.claim.claim_id}`);
|
||||
props.checkSubscriptionLatest(
|
||||
{
|
||||
channelName: props.claim.channel_name,
|
||||
uri: `${props.claim.channel_name}#${props.claim.value.publisherSignature.certificateId}`,
|
||||
},
|
||||
`${props.claim.name}#${props.claim.claim_id}`
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -359,12 +359,17 @@ export function doFetchClaimsByChannel(uri, page) {
|
|||
const claimResult = result[uri] || {};
|
||||
const { claims_in_channel: claimsInChannel, returned_page: returnedPage } = claimResult;
|
||||
|
||||
if(claimsInChannel && claimsInChannel.length) {
|
||||
if (claimsInChannel && claimsInChannel.length) {
|
||||
let latest = claimsInChannel[0];
|
||||
dispatch(setSubscriptionLatest({
|
||||
channelName: latest.channel_name,
|
||||
uri: `${latest.channel_name}#${latest.value.publisherSignature.certificateId}`
|
||||
}, `${latest.name}#${latest.claim_id}`));
|
||||
dispatch(
|
||||
setSubscriptionLatest(
|
||||
{
|
||||
channelName: latest.channel_name,
|
||||
uri: `${latest.channel_name}#${latest.value.publisherSignature.certificateId}`,
|
||||
},
|
||||
`${latest.name}#${latest.claim_id}`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
dispatch({
|
||||
|
|
|
@ -70,7 +70,8 @@ export function doUpdateIsNight() {
|
|||
const momentNow = moment();
|
||||
return {
|
||||
type: ACTIONS.UPDATE_IS_NIGHT,
|
||||
data: { isNight: (() => {
|
||||
data: {
|
||||
isNight: (() => {
|
||||
const startNightMoment = moment('21:00', 'HH:mm');
|
||||
const endNightMoment = moment('8:00', 'HH:mm');
|
||||
return !(momentNow.isAfter(endNightMoment) && momentNow.isBefore(startNightMoment));
|
||||
|
|
|
@ -20,9 +20,15 @@ export const doChannelUnsubscribe = (subscription: Subscription) => (dispatch: D
|
|||
data: subscription,
|
||||
![]() Can we wait to show this notification until after content is ready to watch? I.e. after Can we wait to show this notification until after content is ready to watch? I.e. after `get` has successfully started? That way when the user clicks the notification they get something immediately.
![]() its is more efficient this way because I already have the cost information so we don't need to fetch it again and its is more efficient this way because I already have the cost information so we don't need to fetch it again and
![]() Yes, @seanyesmunt brought this up as well. I have reasons for why I didn't make it this way, which I think we should discuss -- although I think you are right that we probably want to download it first and I probably should have implemented it this way. I will schedule this in the next sprint. Yes, @seanyesmunt brought this up as well. I have reasons for why I didn't make it this way, which I think we should discuss -- although I think you are right that we probably want to download it first and I probably should have implemented it this way. I will schedule this in the next sprint.
![]() I checked out the code here:
I checked out the code here:
1) `doLoadVideo` and `doPurchaseUri` are confusingly -- almost backwardly -- named. It may make sense to tweak these.
2) Since you are already checking that the price is free, it seems like you could potentially skip `doPurchaseUri` and go right to `doLoadVideo`.
3) Both `doLoadVideo` and `doPurchaseUri` can trigger modal popups. It is weird that asynchronous background loading of content can trigger a modal. Fairly guaranteed that this will cause confusion at some point.
4) It doesn't seem particularly tricky to attach a notification to the success of the call to `get`. I think a light modification of `doLoadVideo` to take a notification or callback would get you there.
|
||||
});
|
||||
|
||||
export const doCheckSubscriptions = () => (dispatch: Dispatch, getState: () => SubscriptionState) => {
|
||||
export const doCheckSubscriptions = () => (
|
||||
dispatch: Dispatch,
|
||||
getState: () => SubscriptionState
|
||||
) => {
|
||||
const checkSubscriptionsTimer = setInterval(
|
||||
() => selectSubscriptions(getState()).map((subscription: Subscription) => dispatch(doCheckSubscription(subscription))),
|
||||
() =>
|
||||
selectSubscriptions(getState()).map((subscription: Subscription) =>
|
||||
dispatch(doCheckSubscription(subscription))
|
||||
),
|
||||
CHECK_SUBSCRIPTIONS_INTERVAL
|
||||
);
|
||||
dispatch({
|
||||
|
@ -41,47 +47,69 @@ export const doCheckSubscription = (subscription: Subscription) => (dispatch: Di
|
|||
const claimResult = result[subscription.uri] || {};
|
||||
const { claims_in_channel: claimsInChannel } = claimResult;
|
||||
|
||||
let count = subscription.latest ? claimsInChannel.reduce((prev, cur, index) => `${cur.name}#${cur.claim_id}` === subscription.latest ? index : prev, -1) : 1;
|
||||
let count = subscription.latest
|
||||
? claimsInChannel.reduce(
|
||||
(prev, cur, index) =>
|
||||
`${cur.name}#${cur.claim_id}` === subscription.latest ? index : prev,
|
||||
-1
|
||||
)
|
||||
: 1;
|
||||
|
||||
if(count !== 0) {
|
||||
if(!claimsInChannel[0].value.stream.metadata.fee) {
|
||||
dispatch(doPurchaseUri(`${claimsInChannel[0].name}#${claimsInChannel[0].claim_id}`, {cost: 0}));
|
||||
if (count !== 0) {
|
||||
if (!claimsInChannel[0].value.stream.metadata.fee) {
|
||||
dispatch(
|
||||
doPurchaseUri(`${claimsInChannel[0].name}#${claimsInChannel[0].claim_id}`, { 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' : ''}`,
|
||||
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: `lbry://${claimsInChannel[0].name}#${claimsInChannel[0].claim_id}` }))
|
||||
dispatch(
|
||||
doNavigate('/show', {
|
||||
uri: `lbry://${claimsInChannel[0].name}#${claimsInChannel[0].claim_id}`,
|
||||
})
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
|
||||
data: subscription
|
||||
data: subscription,
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const checkSubscriptionLatest = (channel: Subscription, uri: string) => (dispatch: Dispatch) => {
|
||||
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;
|
||||
|
||||
![]() I think this should have a case for I think this should have a case for `count === 1`, which is probably the most likely scenario. I think in that case just showing the title would make the most sense.
![]() it does, it just says
instead of, for example,
it does, it just says
```
"Sean"
"Posted myVideo"
```
instead of, for example,
```
"Sean"
"Posted myVideo and 9+ other new items"
```
|
||||
if(claimsInChannel && claimsInChannel.length && `${claimsInChannel[0].name}#${claimsInChannel[0].claim_id}` === uri) {
|
||||
if (
|
||||
claimsInChannel &&
|
||||
claimsInChannel.length &&
|
||||
`${claimsInChannel[0].name}#${claimsInChannel[0].claim_id}` === uri
|
||||
) {
|
||||
dispatch(setSubscriptionLatest(channel, uri));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const setSubscriptionLatest = (subscription: Subscription, uri: string) => (dispatch: Dispatch) =>
|
||||
dispatch({
|
||||
export const setSubscriptionLatest = (subscription: Subscription, uri: string) => (
|
||||
dispatch: Dispatch
|
||||
) =>
|
||||
dispatch({
|
||||
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
||||
data: {
|
||||
subscription,
|
||||
uri
|
||||
}
|
||||
uri,
|
||||
},
|
||||
});
|
||||
|
||||
export const setHasFetchedSubscriptions = () => (dispatch: Dispatch) =>
|
||||
|
|
|
@ -5,7 +5,7 @@ import { handleActions } from 'util/redux-utils';
|
|||
export type Subscription = {
|
||||
channelName: string,
|
||||
uri: string,
|
||||
latest: ?string
|
||||
latest: ?string,
|
||||
};
|
||||
|
||||
// Subscription redux types
|
||||
|
@ -33,19 +33,26 @@ type setSubscriptionLatest = {
|
|||
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
||||
data: {
|
||||
subscription: Subscription,
|
||||
uri: string
|
||||
}
|
||||
}
|
||||
uri: string,
|
||||
},
|
||||
};
|
||||
|
||||
type CheckSubscriptionStarted = {
|
||||
type: ACTIONS.CHECK_SUBSCRIPTION_STARTED
|
||||
}
|
||||
type: ACTIONS.CHECK_SUBSCRIPTION_STARTED,
|
||||
};
|
||||
|
||||
type CheckSubscriptionCompleted = {
|
||||
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED
|
||||
}
|
||||
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
|
||||
};
|
||||
|
||||
export type Action = doChannelSubscribe | doChannelUnsubscribe | HasFetchedSubscriptions | setSubscriptionLatest | CheckSubscriptionStarted | CheckSubscriptionCompleted | Function;
|
||||
export type Action =
|
||||
| doChannelSubscribe
|
||||
| doChannelUnsubscribe
|
||||
| HasFetchedSubscriptions
|
||||
| setSubscriptionLatest
|
||||
| CheckSubscriptionStarted
|
||||
| CheckSubscriptionCompleted
|
||||
| Function;
|
||||
export type Dispatch = (action: Action) => any;
|
||||
|
||||
const defaultState = {
|
||||
|
@ -92,8 +99,13 @@ export default handleActions(
|
|||
action: setSubscriptionLatest
|
||||
): SubscriptionState => ({
|
||||
...state,
|
||||
subscriptions: state.subscriptions.map(subscription => subscription.channelName === action.data.subscription.channelName ? {...subscription, latest: action.data.uri} : subscription)
|
||||
})
|
||||
subscriptions: state.subscriptions.map(
|
||||
subscription =>
|
||||
subscription.channelName === action.data.subscription.channelName
|
||||
? { ...subscription, latest: action.data.uri }
|
||||
: subscription
|
||||
),
|
||||
}),
|
||||
},
|
||||
defaultState
|
||||
);
|
||||
|
|
Why do you need to pass in the new cost object. Shouldn't
doPurchaseUri
be able to select that data with the uri?