Merge pull request #1872 from lbryio/subscriptions-overhaul
Subscriptions overhaul
This commit is contained in:
commit
a5bc6adaff
14 changed files with 168 additions and 116 deletions
|
@ -25,10 +25,7 @@ type Props = {
|
||||||
const SideBar = (props: Props) => {
|
const SideBar = (props: Props) => {
|
||||||
const { navLinks, notifications } = props;
|
const { navLinks, notifications } = props;
|
||||||
|
|
||||||
const badges = Object.keys(notifications).reduce(
|
const badges = Object.keys(notifications).length;
|
||||||
(acc, cur) => (notifications[cur].type === NOTIFICATION_TYPES.DOWNLOADING ? acc : acc + 1),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="nav">
|
<nav className="nav">
|
||||||
|
|
|
@ -15,3 +15,4 @@ export const AUTOMATIC_DARK_MODE_ENABLED = 'automaticDarkModeEnabled';
|
||||||
export const AUTOPLAY = 'autoplay';
|
export const AUTOPLAY = 'autoplay';
|
||||||
export const RESULT_COUNT = 'resultCount';
|
export const RESULT_COUNT = 'resultCount';
|
||||||
export const OS_NOTIFICATIONS_ENABLED = 'osNotificationsEnabled';
|
export const OS_NOTIFICATIONS_ENABLED = 'osNotificationsEnabled';
|
||||||
|
export const AUTO_DOWNLOAD = 'autoDownload';
|
||||||
|
|
|
@ -40,7 +40,7 @@ const perform = dispatch => ({
|
||||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||||
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
|
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
|
||||||
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
|
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
|
||||||
checkSubscription: subscription => dispatch(doCheckSubscription(subscription)),
|
checkSubscription: uri => dispatch(doCheckSubscription(uri)),
|
||||||
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
||||||
prepareEdit: (publishData, uri) => dispatch(doPrepareEdit(publishData, uri)),
|
prepareEdit: (publishData, uri) => dispatch(doPrepareEdit(publishData, uri)),
|
||||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||||
|
|
|
@ -44,7 +44,7 @@ type Props = {
|
||||||
fetchFileInfo: string => void,
|
fetchFileInfo: string => void,
|
||||||
fetchCostInfo: string => void,
|
fetchCostInfo: string => void,
|
||||||
prepareEdit: ({}, string) => void,
|
prepareEdit: ({}, string) => void,
|
||||||
checkSubscription: ({ channelName: string, uri: string }) => void,
|
checkSubscription: (uri: string) => void,
|
||||||
subscriptions: Array<Subscription>,
|
subscriptions: Array<Subscription>,
|
||||||
setClientSetting: (string, boolean | string) => void,
|
setClientSetting: (string, boolean | string) => void,
|
||||||
autoplay: boolean,
|
autoplay: boolean,
|
||||||
|
@ -96,16 +96,12 @@ 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(
|
||||||
channelName: props.claim.channel_name,
|
buildURI({
|
||||||
uri: buildURI(
|
contentName: props.claim.channel_name,
|
||||||
{
|
claimId: props.claim.value.publisherSignature.certificateId,
|
||||||
contentName: props.claim.channel_name,
|
}, false)
|
||||||
claimId: props.claim.value.publisherSignature.certificateId,
|
);
|
||||||
},
|
|
||||||
false
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ const select = state => ({
|
||||||
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
||||||
walletEncrypted: selectWalletIsEncrypted(state),
|
walletEncrypted: selectWalletIsEncrypted(state),
|
||||||
osNotificationsEnabled: selectosNotificationsEnabled(state),
|
osNotificationsEnabled: selectosNotificationsEnabled(state),
|
||||||
|
autoDownload: makeSelectClientSetting(settings.AUTO_DOWNLOAD)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -31,6 +31,7 @@ type Props = {
|
||||||
themes: Array<string>,
|
themes: Array<string>,
|
||||||
automaticDarkModeEnabled: boolean,
|
automaticDarkModeEnabled: boolean,
|
||||||
autoplay: boolean,
|
autoplay: boolean,
|
||||||
|
autoDownload: boolean,
|
||||||
encryptWallet: () => void,
|
encryptWallet: () => void,
|
||||||
decryptWallet: () => void,
|
decryptWallet: () => void,
|
||||||
walletEncrypted: boolean,
|
walletEncrypted: boolean,
|
||||||
|
@ -59,6 +60,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
(this: any).onAutoplayChange = this.onAutoplayChange.bind(this);
|
(this: any).onAutoplayChange = this.onAutoplayChange.bind(this);
|
||||||
(this: any).clearCache = this.clearCache.bind(this);
|
(this: any).clearCache = this.clearCache.bind(this);
|
||||||
(this: any).onDesktopNotificationsChange = this.onDesktopNotificationsChange.bind(this);
|
(this: any).onDesktopNotificationsChange = this.onDesktopNotificationsChange.bind(this);
|
||||||
|
(this: any).onAutoDownloadChange = this.onAutoDownloadChange.bind(this);
|
||||||
// (this: any).onLanguageChange = this.onLanguageChange.bind(this)
|
// (this: any).onLanguageChange = this.onLanguageChange.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +121,10 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
this.props.setClientSetting(settings.SHOW_NSFW, event.target.checked);
|
this.props.setClientSetting(settings.SHOW_NSFW, event.target.checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAutoDownloadChange(event: SyntheticInputEvent<*>) {
|
||||||
|
this.props.setClientSetting(settings.AUTO_DOWNLOAD, event.target.checked);
|
||||||
|
}
|
||||||
|
|
||||||
onChangeEncryptWallet() {
|
onChangeEncryptWallet() {
|
||||||
const { props } = this;
|
const { props } = this;
|
||||||
props.walletEncrypted ? props.decryptWallet() : props.encryptWallet();
|
props.walletEncrypted ? props.decryptWallet() : props.encryptWallet();
|
||||||
|
@ -157,6 +163,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
autoplay,
|
autoplay,
|
||||||
walletEncrypted,
|
walletEncrypted,
|
||||||
osNotificationsEnabled,
|
osNotificationsEnabled,
|
||||||
|
autoDownload,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
|
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
|
||||||
|
@ -265,6 +272,13 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
checked={autoplay}
|
checked={autoplay}
|
||||||
postfix={__('Autoplay media files')}
|
postfix={__('Autoplay media files')}
|
||||||
/>
|
/>
|
||||||
|
<FormField
|
||||||
|
type="checkbox"
|
||||||
|
name="auto_download"
|
||||||
|
onChange={this.onAutoDownloadChange}
|
||||||
|
checked={autoDownload}
|
||||||
|
postfix={__('Automatically download new content from your subscriptions')}
|
||||||
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
name="show_nsfw"
|
name="show_nsfw"
|
||||||
|
|
|
@ -25,6 +25,9 @@ export default class extends React.PureComponent<Props> {
|
||||||
const { notifications, setSubscriptionNotifications, doFetchMySubscriptions } = this.props;
|
const { notifications, setSubscriptionNotifications, doFetchMySubscriptions } = this.props;
|
||||||
doFetchMySubscriptions();
|
doFetchMySubscriptions();
|
||||||
|
|
||||||
|
// @sean will change this behavior when implementing new content labeling
|
||||||
|
// notifications should be cleared individually
|
||||||
|
// do we want a way to clear individual claims without viewing?
|
||||||
const newNotifications = {};
|
const newNotifications = {};
|
||||||
Object.keys(notifications).forEach(cur => {
|
Object.keys(notifications).forEach(cur => {
|
||||||
if (notifications[cur].type === NOTIFICATION_TYPES.DOWNLOADING) {
|
if (notifications[cur].type === NOTIFICATION_TYPES.DOWNLOADING) {
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { doFetchDaemonSettings } from 'redux/actions/settings';
|
||||||
import { doAuthNavigate } from 'redux/actions/navigation';
|
import { doAuthNavigate } from 'redux/actions/navigation';
|
||||||
import { doAuthenticate } from 'redux/actions/user';
|
import { doAuthenticate } from 'redux/actions/user';
|
||||||
import { doPause } from 'redux/actions/media';
|
import { doPause } from 'redux/actions/media';
|
||||||
import { doCheckSubscriptions } from 'redux/actions/subscriptions';
|
import { doCheckSubscriptionsInit } from 'redux/actions/subscriptions';
|
||||||
import {
|
import {
|
||||||
selectIsUpgradeSkipped,
|
selectIsUpgradeSkipped,
|
||||||
selectUpdateUrl,
|
selectUpdateUrl,
|
||||||
|
@ -347,7 +347,7 @@ export function doDaemonReady() {
|
||||||
dispatch(doCheckUpgradeAvailable());
|
dispatch(doCheckUpgradeAvailable());
|
||||||
}
|
}
|
||||||
dispatch(doCheckUpgradeSubscribe());
|
dispatch(doCheckUpgradeSubscribe());
|
||||||
dispatch(doCheckSubscriptions());
|
dispatch(doCheckSubscriptionsInit());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,7 @@ export function doUpdateLoadStatus(uri, outpoint) {
|
||||||
dispatch(doUpdateLoadStatus(uri, outpoint));
|
dispatch(doUpdateLoadStatus(uri, outpoint));
|
||||||
}, DOWNLOAD_POLL_INTERVAL);
|
}, DOWNLOAD_POLL_INTERVAL);
|
||||||
} else if (fileInfo.completed) {
|
} else if (fileInfo.completed) {
|
||||||
|
const state = getState();
|
||||||
// TODO this isn't going to get called if they reload the client before
|
// TODO this isn't going to get called if they reload the client before
|
||||||
// the download finished
|
// the download finished
|
||||||
dispatch({
|
dispatch({
|
||||||
|
@ -121,13 +122,13 @@ export function doUpdateLoadStatus(uri, outpoint) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const badgeNumber = selectBadgeNumber(getState());
|
const badgeNumber = selectBadgeNumber(state);
|
||||||
setBadge(badgeNumber === 0 ? '' : `${badgeNumber}`);
|
setBadge(badgeNumber === 0 ? '' : `${badgeNumber}`);
|
||||||
|
|
||||||
const totalProgress = selectTotalDownloadProgress(getState());
|
const totalProgress = selectTotalDownloadProgress(state);
|
||||||
setProgressBar(totalProgress);
|
setProgressBar(totalProgress);
|
||||||
|
|
||||||
const notifications = selectNotifications(getState());
|
const notifications = selectNotifications(state);
|
||||||
if (notifications[uri] && notifications[uri].type === NOTIFICATION_TYPES.DOWNLOADING) {
|
if (notifications[uri] && notifications[uri].type === NOTIFICATION_TYPES.DOWNLOADING) {
|
||||||
const count = Object.keys(notifications).reduce(
|
const count = Object.keys(notifications).reduce(
|
||||||
(acc, cur) =>
|
(acc, cur) =>
|
||||||
|
@ -138,7 +139,7 @@ export function doUpdateLoadStatus(uri, outpoint) {
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
if (selectosNotificationsEnabled(getState())) {
|
if (selectosNotificationsEnabled(state)) {
|
||||||
const notif = new window.Notification(notifications[uri].subscription.channelName, {
|
const notif = new window.Notification(notifications[uri].subscription.channelName, {
|
||||||
body: `Posted ${fileInfo.metadata.title}${
|
body: `Posted ${fileInfo.metadata.title}${
|
||||||
count > 1 && count < 10 ? ` and ${count - 1} other new items` : ''
|
count > 1 && count < 10 ? ` and ${count - 1} other new items` : ''
|
||||||
|
@ -153,13 +154,15 @@ export function doUpdateLoadStatus(uri, outpoint) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
dispatch(
|
if (state.navigation.currentPath !== '/subscriptions') {
|
||||||
setSubscriptionNotification(
|
dispatch(
|
||||||
notifications[uri].subscription,
|
setSubscriptionNotification(
|
||||||
uri,
|
notifications[uri].subscription,
|
||||||
NOTIFICATION_TYPES.DOWNLOADED
|
uri,
|
||||||
)
|
NOTIFICATION_TYPES.DOWNLOADED
|
||||||
);
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// If notifications are disabled(false) just return
|
// If notifications are disabled(false) just return
|
||||||
if (!selectosNotificationsEnabled(getState())) return;
|
if (!selectosNotificationsEnabled(getState())) return;
|
||||||
|
@ -376,17 +379,18 @@ export function doFetchClaimsByChannel(uri, page) {
|
||||||
buildURI({ contentName: latest.name, claimId: latest.claim_id }, false)
|
buildURI({ contentName: latest.name, claimId: latest.claim_id }, false)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const notifications = selectNotifications(getState());
|
// commented out as a note for @sean, notification will be clared individually
|
||||||
const newNotifications = {};
|
// const notifications = selectNotifications(getState());
|
||||||
Object.keys(notifications).forEach(cur => {
|
// const newNotifications = {};
|
||||||
if (
|
// Object.keys(notifications).forEach(cur => {
|
||||||
notifications[cur].subscription.channelName !== latest.channel_name ||
|
// if (
|
||||||
notifications[cur].type === NOTIFICATION_TYPES.DOWNLOADING
|
// notifications[cur].subscription.channelName !== latest.channel_name ||
|
||||||
) {
|
// notifications[cur].type === NOTIFICATION_TYPES.DOWNLOADING
|
||||||
newNotifications[cur] = { ...notifications[cur] };
|
// ) {
|
||||||
}
|
// newNotifications[cur] = { ...notifications[cur] };
|
||||||
});
|
// }
|
||||||
dispatch(setSubscriptionNotifications(newNotifications));
|
// });
|
||||||
|
// dispatch(setSubscriptionNotifications(newNotifications));
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
|
@ -40,11 +40,13 @@ export function doClaimRewardType(rewardType, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userIsRewardApproved && rewardType !== rewards.TYPE_CONFIRM_EMAIL) {
|
if (!userIsRewardApproved && rewardType !== rewards.TYPE_CONFIRM_EMAIL) {
|
||||||
const action = doNotify({
|
if (!options || !options.failSilently) {
|
||||||
id: MODALS.REWARD_APPROVAL_REQUIRED,
|
const action = doNotify({
|
||||||
isError: false,
|
id: MODALS.REWARD_APPROVAL_REQUIRED,
|
||||||
});
|
isError: false,
|
||||||
dispatch(action);
|
});
|
||||||
|
dispatch(action);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
||||||
import type {
|
import * as SETTINGS from 'constants/settings';
|
||||||
Dispatch,
|
import rewards from 'rewards';
|
||||||
SubscriptionState,
|
import type { Dispatch, SubscriptionNotifications } from 'redux/reducers/subscriptions';
|
||||||
SubscriptionNotifications,
|
|
||||||
} from 'redux/reducers/subscriptions';
|
|
||||||
import type { Subscription } from 'types/subscription';
|
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 { Lbry, buildURI, parseURI } from 'lbry-redux';
|
import { Lbry, buildURI, parseURI } from 'lbry-redux';
|
||||||
import { doPurchaseUri } from 'redux/actions/content';
|
import { doPurchaseUri } from 'redux/actions/content';
|
||||||
|
import { doClaimRewardType } from 'redux/actions/rewards';
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
import Lbryio from 'lbryio';
|
import Lbryio from 'lbryio';
|
||||||
|
|
||||||
const CHECK_SUBSCRIPTIONS_INTERVAL = 60 * 60 * 1000;
|
const CHECK_SUBSCRIPTIONS_INTERVAL = 15 * 60 * 1000;
|
||||||
const SUBSCRIPTION_DOWNLOAD_LIMIT = 1;
|
const SUBSCRIPTION_DOWNLOAD_LIMIT = 1;
|
||||||
|
|
||||||
export const doFetchMySubscriptions = () => (dispatch: Dispatch, getState: () => any) => {
|
export const doFetchMySubscriptions = () => (dispatch: Dispatch, getState: () => any) => {
|
||||||
|
@ -124,63 +124,83 @@ export const setSubscriptionNotification = (
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const doCheckSubscription = (subscription: Subscription, notify?: boolean) => (
|
export const doCheckSubscription = (subscriptionUri: string, notify?: boolean) => (
|
||||||
dispatch: Dispatch
|
dispatch: Dispatch,
|
||||||
|
getState: () => {}
|
||||||
) => {
|
) => {
|
||||||
dispatch({
|
// no dispatching FETCH_CHANNEL_CLAIMS_STARTED; causes loading issues on <SubscriptionsPage>
|
||||||
type: ACTIONS.CHECK_SUBSCRIPTION_STARTED,
|
|
||||||
data: subscription,
|
|
||||||
});
|
|
||||||
|
|
||||||
Lbry.claim_list_by_channel({ uri: subscription.uri, page: 1 }).then(result => {
|
const state = getState();
|
||||||
const claimResult = result[subscription.uri] || {};
|
const savedSubscription = state.subscriptions.subscriptions.find(
|
||||||
|
sub => sub.uri === subscriptionUri
|
||||||
|
);
|
||||||
|
|
||||||
|
Lbry.claim_list_by_channel({ uri: subscriptionUri, page: 1 }).then(result => {
|
||||||
|
const claimResult = result[subscriptionUri] || {};
|
||||||
const { claims_in_channel: claimsInChannel } = claimResult;
|
const { claims_in_channel: claimsInChannel } = claimResult;
|
||||||
|
|
||||||
if (claimsInChannel) {
|
const latestIndex = claimsInChannel.findIndex(
|
||||||
if (notify) {
|
claim => `${claim.name}#${claim.claim_id}` === savedSubscription.latest
|
||||||
claimsInChannel.reduce((prev, cur, index) => {
|
);
|
||||||
const uri = buildURI({ contentName: cur.name, claimId: cur.claim_id }, false);
|
|
||||||
if (prev === -1 && uri !== subscription.latest) {
|
|
||||||
dispatch(
|
|
||||||
setSubscriptionNotification(
|
|
||||||
subscription,
|
|
||||||
uri,
|
|
||||||
index < SUBSCRIPTION_DOWNLOAD_LIMIT && !cur.value.stream.metadata.fee
|
|
||||||
? NOTIFICATION_TYPES.DOWNLOADING
|
|
||||||
: NOTIFICATION_TYPES.NOTIFY_ONLY
|
|
||||||
)
|
|
||||||
);
|
|
||||||
if (index < SUBSCRIPTION_DOWNLOAD_LIMIT && !cur.value.stream.metadata.fee) {
|
|
||||||
dispatch(doPurchaseUri(uri, { cost: 0 }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return uri === subscription.latest || !subscription.latest ? index : prev;
|
|
||||||
}, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(
|
// if latest is 0, nothing has changed
|
||||||
setSubscriptionLatest(
|
// when there is no subscription latest, it is either a newly subscriubed channel or
|
||||||
{
|
// the user has cleared their cache. Either way, do not download or notify about new content
|
||||||
channelName: claimsInChannel[0].channel_name,
|
// as that would download/notify 10 claims per channel
|
||||||
uri: buildURI(
|
if (claimsInChannel.length && latestIndex !== 0 && savedSubscription.latest) {
|
||||||
{
|
let downloadCount = 0;
|
||||||
channelName: claimsInChannel[0].channel_name,
|
claimsInChannel.slice(0, latestIndex === -1 ? 10 : latestIndex).forEach(claim => {
|
||||||
claimId: claimsInChannel[0].claim_id,
|
const uri = buildURI({ contentName: claim.name, claimId: claim.claim_id }, false);
|
||||||
},
|
const shouldDownload = Boolean(
|
||||||
false
|
downloadCount < SUBSCRIPTION_DOWNLOAD_LIMIT &&
|
||||||
),
|
!claim.value.stream.metadata.fee &&
|
||||||
},
|
makeSelectClientSetting(SETTINGS.AUTO_DOWNLOAD)(state)
|
||||||
buildURI(
|
);
|
||||||
{ contentName: claimsInChannel[0].name, claimId: claimsInChannel[0].claim_id },
|
if (notify) {
|
||||||
false
|
dispatch(
|
||||||
)
|
setSubscriptionNotification(
|
||||||
)
|
savedSubscription,
|
||||||
);
|
uri,
|
||||||
|
shouldDownload ? NOTIFICATION_TYPES.DOWNLOADING : NOTIFICATION_TYPES.NOTIFY_ONLY
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (shouldDownload) {
|
||||||
|
downloadCount += 1;
|
||||||
|
dispatch(doPurchaseUri(uri, { cost: 0 }));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// always setLatest; important for newly subscribed channels
|
||||||
|
dispatch(
|
||||||
|
setSubscriptionLatest(
|
||||||
|
{
|
||||||
|
channelName: claimsInChannel[0].channel_name,
|
||||||
|
uri: buildURI(
|
||||||
|
{
|
||||||
|
channelName: claimsInChannel[0].channel_name,
|
||||||
|
claimId: claimsInChannel[0].claim_id,
|
||||||
|
},
|
||||||
|
false
|
||||||
|
),
|
||||||
|
},
|
||||||
|
buildURI(
|
||||||
|
{ contentName: claimsInChannel[0].name, claimId: claimsInChannel[0].claim_id },
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// calling FETCH_CHANNEL_CLAIMS_COMPLETED after not calling STARTED
|
||||||
|
// means it will delete a non-existant fetchingChannelClaims[uri]
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
|
type: ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED,
|
||||||
data: subscription,
|
data: {
|
||||||
|
uri: subscriptionUri,
|
||||||
|
claims: claimsInChannel || [],
|
||||||
|
page: 1,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -217,8 +237,11 @@ export const doChannelSubscribe = (subscription: Subscription) => (
|
||||||
channel_name: subscription.channelName,
|
channel_name: subscription.channelName,
|
||||||
claim_id: claimId,
|
claim_id: claimId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dispatch(doClaimRewardType(rewards.SUBSCRIPTION, { failSilently: true }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// should be subUri
|
||||||
dispatch(doCheckSubscription(subscription, true));
|
dispatch(doCheckSubscription(subscription, true));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -244,15 +267,22 @@ export const doChannelUnsubscribe = (subscription: Subscription) => (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const doCheckSubscriptions = () => (
|
export const doCheckSubscriptions = () => (dispatch: Dispatch, getState: () => any) => {
|
||||||
dispatch: Dispatch,
|
const state = getState();
|
||||||
getState: () => SubscriptionState
|
const subscriptions = selectSubscriptions(state);
|
||||||
) => {
|
subscriptions.forEach((sub: Subscription) => {
|
||||||
|
dispatch(doCheckSubscription(sub.uri, true));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const doCheckSubscriptionsInit = () => (dispatch: Dispatch) => {
|
||||||
|
// doCheckSubscriptionsInit is called by doDaemonReady
|
||||||
|
// setTimeout below is a hack to ensure redux is hydrated when subscriptions are checked
|
||||||
|
// this will be replaced with <PersistGate> which reqiures a package upgrade
|
||||||
|
setTimeout(() => dispatch(doFetchMySubscriptions()), 5000);
|
||||||
|
setTimeout(() => dispatch(doCheckSubscriptions()), 10000);
|
||||||
const checkSubscriptionsTimer = setInterval(
|
const checkSubscriptionsTimer = setInterval(
|
||||||
() =>
|
() => dispatch(doCheckSubscriptions()),
|
||||||
selectSubscriptions(getState()).map((subscription: Subscription) =>
|
|
||||||
dispatch(doCheckSubscription(subscription, true))
|
|
||||||
),
|
|
||||||
CHECK_SUBSCRIPTIONS_INTERVAL
|
CHECK_SUBSCRIPTIONS_INTERVAL
|
||||||
);
|
);
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
|
@ -26,6 +26,7 @@ const defaultState = {
|
||||||
automaticDarkModeEnabled: getLocalStorageSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED, false),
|
automaticDarkModeEnabled: getLocalStorageSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED, false),
|
||||||
autoplay: getLocalStorageSetting(SETTINGS.AUTOPLAY, false),
|
autoplay: getLocalStorageSetting(SETTINGS.AUTOPLAY, false),
|
||||||
resultCount: Number(getLocalStorageSetting(SETTINGS.RESULT_COUNT, 50)),
|
resultCount: Number(getLocalStorageSetting(SETTINGS.RESULT_COUNT, 50)),
|
||||||
|
autoDownload: getLocalStorageSetting(SETTINGS.AUTO_DOWNLOAD, true),
|
||||||
osNotificationsEnabled: Boolean(
|
osNotificationsEnabled: Boolean(
|
||||||
getLocalStorageSetting(SETTINGS.OS_NOTIFICATIONS_ENABLED, true)
|
getLocalStorageSetting(SETTINGS.OS_NOTIFICATIONS_ENABLED, true)
|
||||||
),
|
),
|
||||||
|
|
|
@ -25,7 +25,7 @@ export const selectSubscriptionClaims = createSelector(
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchedSubscriptions = [];
|
let fetchedSubscriptions = [];
|
||||||
|
|
||||||
savedSubscriptions.forEach(subscription => {
|
savedSubscriptions.forEach(subscription => {
|
||||||
let channelClaims = [];
|
let channelClaims = [];
|
||||||
|
@ -39,18 +39,20 @@ export const selectSubscriptionClaims = createSelector(
|
||||||
// loop over the list of ids and grab the claim
|
// loop over the list of ids and grab the claim
|
||||||
pageOneChannelIds.forEach(id => {
|
pageOneChannelIds.forEach(id => {
|
||||||
const grabbedClaim = allClaims[id];
|
const grabbedClaim = allClaims[id];
|
||||||
channelClaims.push(grabbedClaim);
|
channelClaims = channelClaims.concat([grabbedClaim]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchedSubscriptions.push({
|
fetchedSubscriptions = fetchedSubscriptions.concat([
|
||||||
claims: channelClaims,
|
{
|
||||||
channelName: subscription.channelName,
|
claims: [...channelClaims],
|
||||||
uri: subscription.uri,
|
channelName: subscription.channelName,
|
||||||
});
|
uri: subscription.uri,
|
||||||
|
},
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
return fetchedSubscriptions;
|
return [...fetchedSubscriptions];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ rewards.TYPE_FIRST_PUBLISH = 'first_publish';
|
||||||
rewards.TYPE_FEATURED_DOWNLOAD = 'featured_download';
|
rewards.TYPE_FEATURED_DOWNLOAD = 'featured_download';
|
||||||
rewards.TYPE_REFERRAL = 'referral';
|
rewards.TYPE_REFERRAL = 'referral';
|
||||||
rewards.YOUTUBE_CREATOR = 'youtube_creator';
|
rewards.YOUTUBE_CREATOR = 'youtube_creator';
|
||||||
|
rewards.SUBSCRIPTION = 'subscription';
|
||||||
|
|
||||||
rewards.claimReward = type => {
|
rewards.claimReward = type => {
|
||||||
function requestReward(resolve, reject, params) {
|
function requestReward(resolve, reject, params) {
|
||||||
|
|
Loading…
Reference in a new issue