commit
5ce7152bba
26 changed files with 215 additions and 151 deletions
|
@ -50,7 +50,7 @@
|
|||
"hast-util-sanitize": "^1.1.2",
|
||||
"keytar": "^4.2.1",
|
||||
"lbry-redux": "lbryio/lbry-redux#1ed2ea8b2de99bbcba652aa7b00478d02df4a290",
|
||||
"lbryinc": "lbryio/lbryinc#82308ece97188747adbf6d71d55b6e7a6fa0bd95",
|
||||
"lbryinc": "lbryio/lbryinc#e9508e259fa9bce3b69915b91534516cf5937075",
|
||||
"localforage": "^1.7.1",
|
||||
"mammoth": "^1.4.6",
|
||||
"mime": "^2.3.1",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
import type { Claim } from 'types/claim';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as React from 'react';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { normalizeURI } from 'lbry-redux';
|
||||
import ToolTip from 'component/common/tooltip';
|
||||
import FileCard from 'component/fileCard';
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import * as React from 'react';
|
||||
|
||||
type Props = {
|
||||
text: string,
|
||||
text: ?string,
|
||||
lines: number,
|
||||
};
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ import {
|
|||
makeSelectCostInfoForUri,
|
||||
makeSelectFileInfoForUri,
|
||||
makeSelectClaimIsMine,
|
||||
doOpenModal,
|
||||
} from 'lbry-redux';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import FileActions from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
makeSelectContentPositionForUri,
|
||||
} from 'redux/selectors/content';
|
||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
|
||||
import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions';
|
||||
import { doClearContentHistoryUri } from 'redux/actions/content';
|
||||
import FileCard from './view';
|
||||
|
||||
|
@ -29,6 +29,7 @@ const select = (state, props) => ({
|
|||
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
|
||||
position: makeSelectContentPositionForUri(props.uri)(state),
|
||||
isSubscribed: makeSelectIsSubscribed(props.uri)(state),
|
||||
isNew: makeSelectIsNew(props.uri)(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -23,7 +23,7 @@ const select = (state, props) => ({
|
|||
|
||||
const perform = dispatch => ({
|
||||
openFolder: path => dispatch(doOpenFileInFolder(path)),
|
||||
showSnackBar: message => dispatch(doToast(message)),
|
||||
showSnackBar: message => dispatch(doToast({ message })),
|
||||
clickCommentButton: () => dispatch(doClickCommentButton()),
|
||||
});
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import { selectShowNsfw } from 'redux/selectors/settings';
|
|||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doClearPublish, doUpdatePublishForm } from 'redux/actions/publish';
|
||||
import { selectRewardContentClaimIds } from 'redux/selectors/content';
|
||||
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
|
||||
import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions';
|
||||
import FileTile from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
|
@ -23,6 +23,7 @@ const select = (state, props) => ({
|
|||
obscureNsfw: !selectShowNsfw(state),
|
||||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||
isSubscribed: makeSelectIsSubscribed(props.uri)(state),
|
||||
isNew: makeSelectIsNew(props.uri)(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -30,6 +30,7 @@ type Props = {
|
|||
displayDescription?: boolean,
|
||||
size: string,
|
||||
isSubscribed: boolean,
|
||||
isNew: boolean,
|
||||
};
|
||||
|
||||
class FileTile extends React.PureComponent<Props> {
|
||||
|
@ -49,12 +50,21 @@ class FileTile extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
renderFileProperties() {
|
||||
const { isSubscribed, isDownloaded, claim, uri, rewardedContentClaimIds, size } = this.props;
|
||||
const {
|
||||
isSubscribed,
|
||||
isDownloaded,
|
||||
claim,
|
||||
uri,
|
||||
rewardedContentClaimIds,
|
||||
size,
|
||||
isNew,
|
||||
} = this.props;
|
||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||
|
||||
return (
|
||||
<div className={classnames('card__file-properties', { card__subtitle: size === 'large' })}>
|
||||
<FilePrice hideFree uri={uri} />
|
||||
{isNew && <span className="badge badge--alert icon">{__('NEW')}</span>}
|
||||
{isSubscribed && <Icon icon={ICONS.HEART} />}
|
||||
{isRewardContent && <Icon iconColor="red" icon={ICONS.FEATURED} />}
|
||||
{isDownloaded && <Icon icon={ICONS.LOCAL} />}
|
||||
|
|
10
src/renderer/component/subscribeMarkAsRead/index.js
Normal file
10
src/renderer/component/subscribeMarkAsRead/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doRemoveUnreadSubscriptions } from 'redux/actions/subscriptions';
|
||||
import MarkAsRead from './view';
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
{
|
||||
doRemoveUnreadSubscriptions,
|
||||
}
|
||||
)(MarkAsRead);
|
42
src/renderer/component/subscribeMarkAsRead/view.jsx
Normal file
42
src/renderer/component/subscribeMarkAsRead/view.jsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import React, { PureComponent } from 'react';
|
||||
import Button from 'component/button';
|
||||
|
||||
type Props = {
|
||||
channel: ?string,
|
||||
doRemoveUnreadSubscriptions: (?string) => void,
|
||||
};
|
||||
|
||||
export default class MarkAsRead extends PureComponent<Props> {
|
||||
constructor() {
|
||||
super();
|
||||
(this: any).handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
const { channel, doRemoveUnreadSubscriptions } = this.props;
|
||||
|
||||
// If there is no channel, mark all as read
|
||||
// If there is a channel, only mark that channel as read
|
||||
if (channel) {
|
||||
doRemoveUnreadSubscriptions(channel);
|
||||
} else {
|
||||
doRemoveUnreadSubscriptions();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { channel } = this.props;
|
||||
const label = channel ? __('Mark as read') : __('Mark all as read');
|
||||
return (
|
||||
<Button
|
||||
noPadding
|
||||
button="inverse"
|
||||
icon={ICONS.CHECK_SIMPLE}
|
||||
label={label}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,8 +4,8 @@ export default function doLogWarningConsoleMessage(activeOnDev = false) {
|
|||
if (isDev && !activeOnDev) return;
|
||||
const style = {
|
||||
redTitle:
|
||||
'color: red; font-size: 50px; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;, font-weight: bold;',
|
||||
normalText: 'font-size: 24px;',
|
||||
'color: red; font-size: 36px; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;, font-weight: bold;',
|
||||
normalText: 'font-size: 18px;',
|
||||
redText:
|
||||
'color: red; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; font-size: 24px;',
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doFetchClaimsByChannel, doFetchClaimCountByChannel } from 'redux/actions/content';
|
||||
import { doFetchClaimsByChannel } from 'redux/actions/content';
|
||||
import { PAGE_SIZE } from 'constants/claim';
|
||||
import {
|
||||
makeSelectClaimForUri,
|
||||
|
@ -26,7 +26,6 @@ const select = (state, props) => ({
|
|||
|
||||
const perform = dispatch => ({
|
||||
fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)),
|
||||
fetchClaimCount: uri => dispatch(doFetchClaimCountByChannel(uri)),
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
||||
});
|
||||
|
|
|
@ -22,28 +22,22 @@ type Props = {
|
|||
claimsInChannel: Array<Claim>,
|
||||
channelIsMine: boolean,
|
||||
fetchClaims: (string, number) => void,
|
||||
fetchClaimCount: string => void,
|
||||
navigate: (string, {}) => void,
|
||||
openModal: ({ id: string }, { uri: string }) => void,
|
||||
};
|
||||
|
||||
class ChannelPage extends React.PureComponent<Props> {
|
||||
componentDidMount() {
|
||||
const { uri, page, fetchClaims, fetchClaimCount } = this.props;
|
||||
|
||||
const { uri, page, fetchClaims } = this.props;
|
||||
fetchClaims(uri, page || 1);
|
||||
fetchClaimCount(uri);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
const { page, uri, fetchClaims, fetchClaimCount } = this.props;
|
||||
const { page, fetchClaims } = this.props;
|
||||
|
||||
if (nextProps.page && page !== nextProps.page) {
|
||||
fetchClaims(nextProps.uri, nextProps.page);
|
||||
}
|
||||
if (nextProps.uri !== uri) {
|
||||
fetchClaimCount(uri);
|
||||
}
|
||||
}
|
||||
|
||||
changePage(pageNumber: number) {
|
||||
|
|
|
@ -11,6 +11,7 @@ import FileCard from 'component/fileCard';
|
|||
import { parseURI } from 'lbry-redux';
|
||||
import Native from 'native';
|
||||
import SuggestedSubscriptions from 'component/subscribeSuggested';
|
||||
import MarkAsRead from 'component/subscribeMarkAsRead';
|
||||
|
||||
type Props = {
|
||||
viewMode: ViewMode,
|
||||
|
@ -90,7 +91,10 @@ export default (props: Props) => {
|
|||
<div className="card__content">
|
||||
{viewMode === VIEW_ALL && (
|
||||
<Fragment>
|
||||
<div className="card__title">{__('Your subscriptions')}</div>
|
||||
<div className="card__title card__actions card__actions--no-margin">
|
||||
{__('Your subscriptions')}
|
||||
{unreadSubscriptions.length > 0 && <MarkAsRead />}
|
||||
</div>
|
||||
<FileList hideFilter sortByHeight fileInfos={subscriptions} />
|
||||
</Fragment>
|
||||
)}
|
||||
|
@ -102,16 +106,17 @@ export default (props: Props) => {
|
|||
const { claimName } = parseURI(channel);
|
||||
return (
|
||||
<section key={channel}>
|
||||
<div className="card__title">
|
||||
<div className="card__title card__actions card__actions--no-margin">
|
||||
<Button
|
||||
button="link"
|
||||
navigate="/show"
|
||||
navigateParams={{ uri: channel }}
|
||||
label={claimName}
|
||||
/>
|
||||
<MarkAsRead channel={channel} />
|
||||
</div>
|
||||
<div className="card__list card__content">
|
||||
{uris.map(uri => <FileCard isNew key={uri} uri={uri} />)}
|
||||
{uris.map(uri => <FileCard key={uri} uri={uri} />)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
@ -120,7 +125,7 @@ export default (props: Props) => {
|
|||
<Fragment>
|
||||
<div className="page__empty">
|
||||
<h3 className="card__title">{__('All caught up!')}</h3>
|
||||
<p className="card__subtitle">{__('You might like these channels.')}</p>
|
||||
<p className="card__subtitle">{__('You might like these channels below.')}</p>
|
||||
</div>
|
||||
<SuggestedSubscriptions />
|
||||
</Fragment>
|
||||
|
|
|
@ -4,12 +4,7 @@ import path from 'path';
|
|||
import { ipcRenderer, remote } from 'electron';
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
import * as MODALS from 'constants/modal_types';
|
||||
import {
|
||||
Lbry,
|
||||
doBalanceSubscribe,
|
||||
doFetchFileInfosAndPublishedClaims,
|
||||
selectNotification,
|
||||
} from 'lbry-redux';
|
||||
import { Lbry, doBalanceSubscribe, doFetchFileInfosAndPublishedClaims, doError } from 'lbry-redux';
|
||||
import Native from 'native';
|
||||
import { doFetchDaemonSettings } from 'redux/actions/settings';
|
||||
import { doAuthNavigate } from 'redux/actions/navigation';
|
||||
|
@ -23,8 +18,9 @@ import {
|
|||
selectAutoUpdateDeclined,
|
||||
selectRemoteVersion,
|
||||
selectUpgradeTimer,
|
||||
selectModal,
|
||||
} from 'redux/selectors/app';
|
||||
import { doAuthenticate, doFetchRewardedContent } from 'lbryinc';
|
||||
import { doAuthenticate } from 'lbryinc';
|
||||
import { lbrySettings as config, version as appVersion } from 'package.json';
|
||||
|
||||
const { autoUpdater } = remote.require('electron-updater');
|
||||
|
@ -33,6 +29,22 @@ const Fs = remote.require('fs');
|
|||
|
||||
const CHECK_UPGRADE_INTERVAL = 10 * 60 * 1000;
|
||||
|
||||
export function doOpenModal(id, modalProps = {}) {
|
||||
return {
|
||||
type: ACTIONS.SHOW_MODAL,
|
||||
data: {
|
||||
id,
|
||||
modalProps,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function doHideModal() {
|
||||
return {
|
||||
type: ACTIONS.HIDE_MODAL,
|
||||
};
|
||||
}
|
||||
|
||||
export function doUpdateDownloadProgress(percent) {
|
||||
return {
|
||||
type: ACTIONS.UPGRADE_DOWNLOAD_PROGRESSED,
|
||||
|
@ -88,9 +100,7 @@ export function doDownloadUpgrade() {
|
|||
type: ACTIONS.UPGRADE_DOWNLOAD_STARTED,
|
||||
});
|
||||
dispatch(doHideModal());
|
||||
dispatch(
|
||||
doOpenModal(MODALS.DOWNLOADING)
|
||||
);
|
||||
dispatch(doOpenModal(MODALS.DOWNLOADING));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -109,15 +119,11 @@ export function doDownloadUpgradeRequested() {
|
|||
// electron-updater behavior
|
||||
if (autoUpdateDeclined) {
|
||||
// The user declined an update before, so show the "confirm" dialog
|
||||
dispatch(
|
||||
doOpenModal(MODALS.AUTO_UPDATE_CONFIRM)
|
||||
);
|
||||
dispatch(doOpenModal(MODALS.AUTO_UPDATE_CONFIRM));
|
||||
} else {
|
||||
// The user was never shown the original update dialog (e.g. because they were
|
||||
// watching a video). So show the inital "update downloaded" dialog.
|
||||
dispatch(
|
||||
doOpenModal(MODALS.AUTO_UPDATE_DOWNLOADED)
|
||||
);
|
||||
dispatch(doOpenModal(MODALS.AUTO_UPDATE_DOWNLOADED));
|
||||
}
|
||||
} else {
|
||||
// Old behavior for Linux
|
||||
|
@ -145,9 +151,7 @@ export function doAutoUpdate() {
|
|||
type: ACTIONS.AUTO_UPDATE_DOWNLOADED,
|
||||
});
|
||||
|
||||
dispatch(
|
||||
doOpenModal(MODALS.AUTO_UPDATE_DOWNLOADED)
|
||||
);
|
||||
dispatch(doOpenModal(MODALS.AUTO_UPDATE_DOWNLOADED));
|
||||
|
||||
dispatch(doClearUpgradeTimer());
|
||||
};
|
||||
|
@ -216,12 +220,10 @@ export function doCheckUpgradeAvailable() {
|
|||
|
||||
if (
|
||||
upgradeAvailable &&
|
||||
!selectNotification(state) &&
|
||||
!selectModal(state) &&
|
||||
(!selectIsUpgradeSkipped(state) || remoteVersion !== selectRemoteVersion(state))
|
||||
) {
|
||||
dispatch(
|
||||
doOpenModal(MODALS.UPGRADE)
|
||||
);
|
||||
dispatch(doOpenModal(MODALS.UPGRADE));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -266,42 +268,32 @@ export function doCheckDaemonVersion() {
|
|||
type: ACTIONS.DAEMON_VERSION_MISMATCH,
|
||||
});
|
||||
|
||||
return dispatch(
|
||||
doOpenModal(MODALS.INCOMPATIBLE_DAEMON)
|
||||
);
|
||||
return dispatch(doOpenModal(MODALS.INCOMPATIBLE_DAEMON));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doNotifyEncryptWallet() {
|
||||
return dispatch => {
|
||||
dispatch(
|
||||
doOpenModal(MODALS.WALLET_ENCRYPT)
|
||||
);
|
||||
dispatch(doOpenModal(MODALS.WALLET_ENCRYPT));
|
||||
};
|
||||
}
|
||||
|
||||
export function doNotifyDecryptWallet() {
|
||||
return dispatch => {
|
||||
dispatch(
|
||||
doOpenModal(MODALS.WALLET_DECRYPT)
|
||||
);
|
||||
dispatch(doOpenModal(MODALS.WALLET_DECRYPT));
|
||||
};
|
||||
}
|
||||
|
||||
export function doNotifyUnlockWallet() {
|
||||
return dispatch => {
|
||||
dispatch(
|
||||
doOpenModal(MODALS.WALLET_UNLOCK)
|
||||
);
|
||||
dispatch(doOpenModal(MODALS.WALLET_UNLOCK));
|
||||
};
|
||||
}
|
||||
|
||||
export function doAlertError(errorList) {
|
||||
return dispatch => {
|
||||
dispatch(
|
||||
doError(errorList)
|
||||
);
|
||||
dispatch(doError(errorList));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -314,7 +306,6 @@ export function doDaemonReady() {
|
|||
dispatch(doFetchDaemonSettings());
|
||||
dispatch(doBalanceSubscribe());
|
||||
dispatch(doFetchFileInfosAndPublishedClaims());
|
||||
dispatch(doFetchRewardedContent());
|
||||
if (!selectIsUpgradeSkipped(state)) {
|
||||
dispatch(doCheckUpgradeAvailable());
|
||||
}
|
||||
|
@ -373,26 +364,10 @@ export function doClickCommentButton() {
|
|||
export function doConditionalAuthNavigate(newSession) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const notification = selectNotification(state);
|
||||
const notification = selectModal(state);
|
||||
|
||||
if (newSession || (notification && notification.id !== 'email_collection')) {
|
||||
dispatch(doAuthNavigate());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function doOpenModal(id, modalProps = {}) {
|
||||
return {
|
||||
type: ACTIONS.SHOW_MODAL,
|
||||
data: {
|
||||
id,
|
||||
modalProps,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function doHideModal() {
|
||||
return {
|
||||
type: ACTIONS.HIDE_MODAL
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import {
|
|||
Lbry,
|
||||
Lbryapi,
|
||||
buildURI,
|
||||
doFetchClaimListMine,
|
||||
makeSelectCostInfoForUri,
|
||||
makeSelectFileInfoForUri,
|
||||
selectFileInfosByOutpoint,
|
||||
|
@ -331,28 +330,6 @@ export function doFetchClaimsByChannel(uri, page, pageSize) {
|
|||
};
|
||||
}
|
||||
|
||||
export function doFetchClaimCountByChannel(uri) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_CHANNEL_CLAIM_COUNT_STARTED,
|
||||
data: { uri },
|
||||
});
|
||||
|
||||
Lbry.claim_list_by_channel({ uri }).then(result => {
|
||||
const claimResult = result[uri];
|
||||
const totalClaims = claimResult ? claimResult.claims_in_channel : 0;
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_CHANNEL_CLAIM_COUNT_COMPLETED,
|
||||
data: {
|
||||
uri,
|
||||
totalClaims,
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doPlayUri(uri) {
|
||||
return dispatch => {
|
||||
dispatch(doSetPlayingUri(uri));
|
||||
|
@ -405,24 +382,6 @@ export function doCreateChannel(name: string, amount: number) {
|
|||
};
|
||||
}
|
||||
|
||||
export function doPublish(params) {
|
||||
return dispatch =>
|
||||
new Promise((resolve, reject) => {
|
||||
const success = claim => {
|
||||
resolve(claim);
|
||||
|
||||
if (claim === true) dispatch(doFetchClaimListMine());
|
||||
else
|
||||
setTimeout(() => dispatch(doFetchClaimListMine()), 20000, {
|
||||
once: true,
|
||||
});
|
||||
};
|
||||
const failure = err => reject(err);
|
||||
|
||||
Lbry.publishDeprecated(params, null, success, failure);
|
||||
});
|
||||
}
|
||||
|
||||
export function savePosition(claimId: string, outpoint: string, position: number) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
|
|
|
@ -15,7 +15,7 @@ import * as NOTIFICATION_TYPES from 'constants/subscriptions';
|
|||
import { Lbryio, rewards, doClaimRewardType } from 'lbryinc';
|
||||
import { selectSubscriptions, selectUnreadByChannel } from 'redux/selectors/subscriptions';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import { Lbry, buildURI, parseURI } from 'lbry-redux';
|
||||
import { Lbry, buildURI, parseURI, doResolveUris } from 'lbry-redux';
|
||||
import { doPurchaseUri, doFetchClaimsByChannel } from 'redux/actions/content';
|
||||
import Promise from 'bluebird';
|
||||
|
||||
|
@ -101,6 +101,7 @@ export const doFetchMySubscriptions = () => (dispatch: ReduxDispatch, getState:
|
|||
data: subscriptions,
|
||||
});
|
||||
|
||||
dispatch(doResolveUris(subscriptions.map(({ uri }) => uri)));
|
||||
subscriptions.forEach(({ uri }) => dispatch(doFetchClaimsByChannel(uri, 1)));
|
||||
})
|
||||
.catch(() => {
|
||||
|
@ -167,28 +168,44 @@ export const doUpdateUnreadSubscriptions = (
|
|||
};
|
||||
|
||||
// Remove multiple files (or all) from a channels unread subscriptions
|
||||
export const doRemoveUnreadSubscriptions = (channelUri: string, readUris: Array<string>) => (
|
||||
export const doRemoveUnreadSubscriptions = (channelUri: ?string, readUris: ?Array<string>) => (
|
||||
dispatch: ReduxDispatch,
|
||||
getState: GetState
|
||||
) => {
|
||||
const state = getState();
|
||||
const unreadByChannel = selectUnreadByChannel(state);
|
||||
|
||||
// If no channel is passed in, remove all unread subscriptions from all channels
|
||||
if (!channelUri) {
|
||||
return dispatch({
|
||||
type: ACTIONS.REMOVE_SUBSCRIPTION_UNREADS,
|
||||
data: { channel: null },
|
||||
});
|
||||
}
|
||||
|
||||
const currentChannelUnread = unreadByChannel[channelUri];
|
||||
if (!currentChannelUnread || !currentChannelUnread.uris) {
|
||||
// Channel passed in doesn't have any unreads
|
||||
return;
|
||||
}
|
||||
|
||||
// For each uri passed in, remove it from the list of unread uris
|
||||
const urisToRemoveMap = readUris.reduce(
|
||||
(acc, val) => ({
|
||||
...acc,
|
||||
[val]: true,
|
||||
}),
|
||||
{}
|
||||
);
|
||||
// If no uris are passed in, remove them all
|
||||
let newUris;
|
||||
if (readUris) {
|
||||
const urisToRemoveMap = readUris.reduce(
|
||||
(acc, val) => ({
|
||||
...acc,
|
||||
[val]: true,
|
||||
}),
|
||||
{}
|
||||
);
|
||||
|
||||
const filteredUris = currentChannelUnread.uris.filter(uri => !urisToRemoveMap[uri]);
|
||||
const newUris = filteredUris.length ? filteredUris : null;
|
||||
const filteredUris = currentChannelUnread.uris.filter(uri => !urisToRemoveMap[uri]);
|
||||
newUris = filteredUris.length ? filteredUris : null;
|
||||
} else {
|
||||
newUris = null;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.REMOVE_SUBSCRIPTION_UNREADS,
|
||||
|
|
|
@ -66,10 +66,11 @@ 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
|
||||
),
|
||||
}),
|
||||
[ACTIONS.UPDATE_SUBSCRIPTION_UNREADS]: (
|
||||
|
@ -94,12 +95,19 @@ export default handleActions(
|
|||
action: DoRemoveSubscriptionUnreads
|
||||
): SubscriptionState => {
|
||||
const { channel, uris } = action.data;
|
||||
const newUnread = { ...state.unread };
|
||||
|
||||
if (!uris) {
|
||||
delete newUnread[channel];
|
||||
// If no channel is passed in, remove all unreads
|
||||
let newUnread;
|
||||
if (channel) {
|
||||
newUnread = { ...state.unread };
|
||||
|
||||
if (!uris) {
|
||||
delete newUnread[channel];
|
||||
} else {
|
||||
newUnread[channel].uris = uris;
|
||||
}
|
||||
} else {
|
||||
newUnread[channel].uris = uris;
|
||||
newUnread = {};
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -253,3 +253,23 @@ export const makeSelectIsSubscribed = uri =>
|
|||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
export const makeSelectIsNew = uri =>
|
||||
createSelector(
|
||||
makeSelectIsSubscribed(uri),
|
||||
makeSelectChannelForClaimUri(uri),
|
||||
selectUnreadByChannel,
|
||||
(isSubscribed, channel, unreadByChannel) => {
|
||||
if (!isSubscribed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const unreadForChannel = unreadByChannel[`lbry://${channel}`];
|
||||
if (unreadForChannel) {
|
||||
return unreadForChannel.uris.includes(uri);
|
||||
}
|
||||
|
||||
return false;
|
||||
// If they are subscribed, check to see if this uri is in the list of unreads
|
||||
}
|
||||
);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// component specific styling should go in the component scss file
|
||||
|
||||
html {
|
||||
background-color: $lbry-white;
|
||||
background-color: $lbry-teal-5;
|
||||
font-family: 'Inter UI', sans-serif;
|
||||
height: 100%;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.btn--no-padding {
|
||||
.btn__content {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn--alt {
|
||||
&:not(:disabled) {
|
||||
background-color: $lbry-white;
|
||||
|
|
|
@ -324,6 +324,7 @@
|
|||
|
||||
.card-row__scrollhouse {
|
||||
padding-top: $spacing-vertical * 2/3;
|
||||
padding-bottom: $spacing-vertical * 1/6;
|
||||
overflow: hidden;
|
||||
|
||||
.card {
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
html[data-theme='dark'] {
|
||||
//
|
||||
// HTML Elements
|
||||
//
|
||||
blockquote {
|
||||
background-color: rgba($lbry-black, 0.9);
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: rgba($lbry-black, 0.9);
|
||||
}
|
||||
|
@ -203,4 +210,11 @@ html[data-theme='dark'] {
|
|||
.expandable--closed::after {
|
||||
background-image: linear-gradient(to bottom, transparent 0%, $lbry-black 90%);
|
||||
}
|
||||
|
||||
//
|
||||
// File Viewer
|
||||
//
|
||||
.document-viewer {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 180 KiB |
Binary file not shown.
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 181 KiB |
20
yarn.lock
20
yarn.lock
|
@ -5663,6 +5663,14 @@ lazy-val@^1.0.3:
|
|||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.3.tgz#bb97b200ef00801d94c317e29dc6ed39e31c5edc"
|
||||
|
||||
lbry-redux@lbryio/lbry-redux#1ed2ea8b2de99bbcba652aa7b00478d02df4a290:
|
||||
version "0.0.1"
|
||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/1ed2ea8b2de99bbcba652aa7b00478d02df4a290"
|
||||
dependencies:
|
||||
proxy-polyfill "0.1.6"
|
||||
reselect "^3.0.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
lbry-redux@lbryio/lbry-redux#2375860d6269d0369418879c2531b1d48c4e47f2:
|
||||
version "0.0.1"
|
||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/2375860d6269d0369418879c2531b1d48c4e47f2"
|
||||
|
@ -5670,17 +5678,9 @@ lbry-redux@lbryio/lbry-redux#2375860d6269d0369418879c2531b1d48c4e47f2:
|
|||
proxy-polyfill "0.1.6"
|
||||
reselect "^3.0.0"
|
||||
|
||||
lbry-redux@lbryio/lbry-redux#df8e8c6b44718f8de36aabb9222e74ca9433e13c:
|
||||
lbryinc@lbryio/lbryinc#e9508e259fa9bce3b69915b91534516cf5937075:
|
||||
version "0.0.1"
|
||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/df8e8c6b44718f8de36aabb9222e74ca9433e13c"
|
||||
dependencies:
|
||||
proxy-polyfill "0.1.6"
|
||||
reselect "^3.0.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
lbryinc@lbryio/lbryinc#82308ece97188747adbf6d71d55b6e7a6fa0bd95:
|
||||
version "0.0.1"
|
||||
resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/82308ece97188747adbf6d71d55b6e7a6fa0bd95"
|
||||
resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/e9508e259fa9bce3b69915b91534516cf5937075"
|
||||
dependencies:
|
||||
lbry-redux lbryio/lbry-redux#2375860d6269d0369418879c2531b1d48c4e47f2
|
||||
reselect "^3.0.0"
|
||||
|
|
Loading…
Reference in a new issue