lbry-desktop/ui/index.jsx

303 lines
9 KiB
React
Raw Normal View History

import 'babel-polyfill';
2020-02-14 19:58:09 +01:00
import * as Sentry from '@sentry/browser';
import ErrorBoundary from 'component/errorBoundary';
import App from 'component/app';
import SnackBar from 'component/snackBar';
2019-02-22 06:01:59 +01:00
// @if TARGET='app'
2019-03-28 17:53:13 +01:00
import SplashScreen from 'component/splash';
import * as ACTIONS from 'constants/action_types';
2019-02-22 06:01:59 +01:00
// @endif
2019-07-29 16:34:20 +02:00
import { ipcRenderer, remote, shell } from 'electron';
import moment from 'moment';
import * as MODALS from 'constants/modal_types';
2019-08-27 16:43:42 +02:00
import React, { Fragment, useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import {
doDaemonReady,
doAutoUpdate,
doOpenModal,
doHideModal,
doToggle3PAnalytics,
doMinVersionSubscribe,
} from 'redux/actions/app';
import Lbry, { apiCall } from 'lbry';
import { isURIValid } from 'util/lbryURI';
2020-07-27 22:04:12 +02:00
import { setSearchApi } from 'redux/actions/search';
import { doSetLanguage, doFetchLanguage, doUpdateIsNightAsync, doFetchHomepages } from 'redux/actions/settings';
import { doFetchUserLocale } from 'redux/actions/user';
import { Lbryio, doBlackListedOutpointsSubscribe, doFilteredOutpointsSubscribe } from 'lbryinc';
import rewards from 'rewards';
2019-07-23 10:05:51 +02:00
import { store, persistor, history } from 'store';
2017-12-21 23:09:30 +01:00
import app from './app';
import doLogWarningConsoleMessage from './logWarningConsoleMessage';
2019-04-18 21:10:46 +02:00
import { ConnectedRouter, push } from 'connected-react-router';
2019-12-03 18:55:29 +01:00
import { formatLbryUrlForWeb, formatInAppUrl } from 'util/url';
2019-07-23 10:05:51 +02:00
import { PersistGate } from 'redux-persist/integration/react';
2019-10-02 20:20:25 +02:00
import analytics from 'analytics';
import { doToast } from 'redux/actions/notifications';
2022-03-03 03:48:40 +01:00
import { getAuthToken, setAuthToken, doAuthTokenRefresh } from 'util/saved-passwords';
import { X_LBRY_AUTH_TOKEN } from 'constants/token';
import { PROXY_URL, DEFAULT_LANGUAGE, LBRY_API_URL } from 'config';
2019-04-18 21:10:46 +02:00
// Import 3rd-party styles before ours for the current way we are code-splitting.
import 'scss/third-party.scss';
2019-04-18 21:40:53 +02:00
// Import our app styles
// If a style is not necessary for the initial page load, it should be removed from `all.scss`
// and loaded dynamically in the component that consumes it
import 'scss/all.scss';
2019-09-30 22:11:45 +02:00
// @if TARGET='web'
// These overrides can't live in web/ because they need to use the same instance of `Lbry`
import apiPublishCallViaWeb from 'web/setup/publish';
import { doSendPastRecsysEntries } from 'redux/actions/content';
2020-02-05 04:46:00 +01:00
// Sentry error logging setup
// Will only work if you have a SENTRY_AUTH_TOKEN env
// We still add code in analytics.js to send the error to sentry manually
// If it's caught by componentDidCatch in component/errorBoundary, it will not bubble up to this error reporter
2020-02-14 19:58:09 +01:00
if (process.env.NODE_ENV === 'production') {
Sentry.init({
2022-03-02 18:45:26 +01:00
dsn: 'https://1f3c88e2e4b341328a638e138a60fb73@sentry.odysee.tv/2',
2020-02-14 19:58:09 +01:00
whitelistUrls: [/\/public\/ui.js/],
});
}
2020-02-05 04:46:00 +01:00
2020-03-24 19:43:51 +01:00
if (process.env.SDK_API_URL) {
console.warn('SDK_API_URL env var is deprecated. Use SDK_API_HOST instead'); // @eslint-disable-line
2020-03-24 19:43:51 +01:00
}
Lbry.setDaemonConnectionString(PROXY_URL);
Lbry.setOverride(
'publish',
(params) =>
new Promise((resolve, reject) => {
apiPublishCallViaWeb(
2019-11-15 20:42:31 +01:00
apiCall,
Lbry.getApiRequestHeaders() && Object.keys(Lbry.getApiRequestHeaders()).includes(X_LBRY_AUTH_TOKEN)
? Lbry.getApiRequestHeaders()[X_LBRY_AUTH_TOKEN]
: '',
'publish',
params,
resolve,
reject
);
})
);
2019-09-30 22:11:45 +02:00
// @endif
analytics.initAppStartTime(Date.now());
2019-10-22 22:42:13 +02:00
2019-02-22 06:01:59 +01:00
// @if TARGET='app'
const { autoUpdater } = remote.require('electron-updater');
2018-02-24 01:24:00 +01:00
autoUpdater.logger = remote.require('electron-log');
2019-02-22 06:01:59 +01:00
// @endif
2017-12-10 09:06:30 +01:00
2020-08-25 18:08:41 +02:00
if (LBRY_API_URL) {
Lbryio.setLocalApi(LBRY_API_URL);
2019-01-08 03:46:33 +01:00
}
2019-01-29 17:46:56 +01:00
if (process.env.SEARCH_API_URL) {
setSearchApi(process.env.SEARCH_API_URL);
}
2020-03-12 15:56:13 +01:00
doAuthTokenRefresh();
2018-09-24 05:44:42 +02:00
// We need to override Lbryio for getting/setting the authToken
2019-10-13 19:41:51 +02:00
// We interact with ipcRenderer to get the auth key from a users keyring
// We keep a local variable for authToken because `ipcRenderer.send` does not
// contain a response, so there is no way to know when it's been set
2018-11-30 06:55:45 +01:00
let authToken;
Lbryio.setOverride('setAuthToken', (authToken) => {
2020-09-04 17:02:30 +02:00
setAuthToken(authToken);
return authToken;
});
2018-09-24 05:44:42 +02:00
Lbryio.setOverride(
'getAuthToken',
() =>
new Promise((resolve) => {
2019-10-24 20:07:48 +02:00
const authTokenToReturn = authToken || getAuthToken();
resolve(authTokenToReturn);
2018-09-24 05:44:42 +02:00
})
);
rewards.setCallback('claimFirstRewardSuccess', () => {
app.store.dispatch(doOpenModal(MODALS.FIRST_REWARD));
});
rewards.setCallback('claimRewardSuccess', (reward) => {
if (reward && reward.type === rewards.TYPE_REWARD_CODE) {
app.store.dispatch(doHideModal());
}
});
2019-02-22 06:01:59 +01:00
// @if TARGET='app'
ipcRenderer.on('open-uri-requested', (event, url, newSession) => {
function handleError() {
app.store.dispatch(
doToast({
message: __('Invalid LBRY URL requested'),
})
);
}
const path = url.slice('lbry://'.length);
if (path.startsWith('?')) {
2019-12-03 18:55:29 +01:00
const redirectUrl = formatInAppUrl(path);
return app.store.dispatch(push(redirectUrl));
2017-06-08 02:56:52 +02:00
}
if (isURIValid(url)) {
const formattedUrl = formatLbryUrlForWeb(url);
analytics.openUrlEvent(formattedUrl);
return app.store.dispatch(push(formattedUrl));
}
// If nothing redirected before here the url must be messed up
handleError();
});
2019-11-05 19:54:58 +01:00
ipcRenderer.on('language-set', (event, language) => {
app.store.dispatch(doSetLanguage(language));
});
ipcRenderer.on('open-menu', (event, uri) => {
if (uri && uri.startsWith('/help')) {
2019-04-18 21:10:46 +02:00
app.store.dispatch(push('/$/help'));
}
});
const { dock } = remote.app;
ipcRenderer.on('window-is-focused', () => {
if (!dock) return;
app.store.dispatch({ type: ACTIONS.WINDOW_FOCUSED });
dock.setBadge('');
});
ipcRenderer.on('devtools-is-opened', () => {
doLogWarningConsoleMessage();
});
2019-05-26 08:18:47 +02:00
// Force exit mode for html5 fullscreen api
// See: https://github.com/electron/electron/issues/18188
remote.getCurrentWindow().on('leave-full-screen', (event) => {
2019-05-26 08:18:47 +02:00
document.webkitExitFullscreen();
});
document.addEventListener('click', (event) => {
let { target } = event;
2018-11-07 23:44:38 +01:00
2017-06-08 02:56:52 +02:00
while (target && target !== document) {
if (target.matches('a[href^="http"]') || target.matches('a[href^="mailto"]')) {
2017-06-08 02:56:52 +02:00
event.preventDefault();
shell.openExternal(target.href);
return;
}
target = target.parentNode;
}
2017-05-21 18:15:41 +02:00
});
2020-08-21 17:49:13 +02:00
// @endif
document.addEventListener('dragover', (event) => {
2020-08-21 17:49:13 +02:00
event.preventDefault();
});
document.addEventListener('drop', (event) => {
2020-08-21 17:49:13 +02:00
event.preventDefault();
});
2017-05-21 18:15:41 +02:00
2019-07-23 10:05:51 +02:00
function AppWrapper() {
2019-11-18 19:30:15 +01:00
// Splash screen and sdk setup not needed on web
const [readyToLaunch, setReadyToLaunch] = useState(IS_WEB);
2019-11-18 19:30:15 +01:00
const [persistDone, setPersistDone] = useState(false);
2018-10-14 19:47:18 +02:00
2019-07-23 10:05:51 +02:00
useEffect(() => {
2019-07-29 16:34:20 +02:00
// @if TARGET='app'
2019-07-23 10:05:51 +02:00
moment.locale(remote.app.getLocale());
autoUpdater.on('error', (error) => {
2019-07-23 10:05:51 +02:00
console.error(error.message); // eslint-disable-line no-console
});
2018-04-24 20:17:11 +02:00
if (['win32', 'darwin'].includes(process.platform) || !!process.env.APPIMAGE) {
2019-07-23 10:05:51 +02:00
autoUpdater.on('update-available', () => {
console.log('Update available'); // eslint-disable-line no-console
});
autoUpdater.on('update-not-available', () => {
console.log('Update not available'); // eslint-disable-line no-console
});
autoUpdater.on('update-downloaded', () => {
console.log('Update downloaded'); // eslint-disable-line no-console
app.store.dispatch(doAutoUpdate());
});
}
2019-07-29 16:34:20 +02:00
// @endif
2019-07-23 10:05:51 +02:00
}, []);
2019-02-28 00:50:00 +01:00
useEffect(() => {
if (persistDone) {
app.store.dispatch(doToggle3PAnalytics(null, true));
app.store.dispatch(doSendPastRecsysEntries());
}
}, [persistDone]);
2019-07-23 10:05:51 +02:00
useEffect(() => {
2019-11-18 19:30:15 +01:00
if (readyToLaunch && persistDone) {
2019-07-23 10:05:51 +02:00
app.store.dispatch(doDaemonReady());
Re-design comment threads (#1489) * Redesign threadline and fetching state - threadline goes right below channel avatar, mimicking reddits implementation, has a increase effect on hover and is slimmer, creating more space for comments on screen - fetching state now replaces show/hide button, also mimicking reddit, and now says that it is loading, instead of a blank spinner, and also improves space a bit * Redesign comment threads - Allow for infinite comment chains - Can go back and forth between the pages - Can go back to all comments or to the first comment in the chain - Some other improvements, which include: - add title on non-drawer comment sections (couldn't see amount of comments) - fix Expandable component (would begin expanded and collapse after the effect runs, which looked bad and shifted the layout, now each comments greater than the set length begins collapsed) - used constants for consistency * Fix replying to last thread comment * Fix buttons condition (only on fetched comment to avoid deleted case) * Fix auto-scroll * Bring back instant feedback for Show More replies * Improve thread back links - Now going back to all comments links the top-level comment for easier navigation - Going back to ~ previous ~ now goes back into the chain instead of topmost level * Clear timeouts due to unrelated issue * Fix deep thread linked comment case and more scroll improvements * More minor changes * Flow * Fix commentList tile style * Fix long channel names overflowing on small screens * More scroll changes * Fix threadline * Revert "Fix long channel names overflowing on small screens" This reverts commit e4d2dc7da5861ed8136a60f3352e41a690cd4d33. * Fix replies fetch * Revert "Fix replies fetch" This reverts commit ec70054675a604a7a5f3764ba07c36bf7b0f49c8. * Cleanup and make smooth * Always use linked comment on threads * Cleanup * Higlight thread comment * Fix comment body styles
2022-05-16 12:22:13 +02:00
const timer = setTimeout(() => {
if (DEFAULT_LANGUAGE) {
app.store.dispatch(doFetchLanguage(DEFAULT_LANGUAGE));
}
app.store.dispatch(doFetchHomepages());
app.store.dispatch(doUpdateIsNightAsync());
app.store.dispatch(doBlackListedOutpointsSubscribe());
app.store.dispatch(doFilteredOutpointsSubscribe());
app.store.dispatch(doFetchUserLocale());
}, 25);
2019-10-02 20:20:25 +02:00
const nonCriticalTimer = setTimeout(() => {
app.store.dispatch(doMinVersionSubscribe());
}, 5000);
analytics.startupEvent(Date.now());
Re-design comment threads (#1489) * Redesign threadline and fetching state - threadline goes right below channel avatar, mimicking reddits implementation, has a increase effect on hover and is slimmer, creating more space for comments on screen - fetching state now replaces show/hide button, also mimicking reddit, and now says that it is loading, instead of a blank spinner, and also improves space a bit * Redesign comment threads - Allow for infinite comment chains - Can go back and forth between the pages - Can go back to all comments or to the first comment in the chain - Some other improvements, which include: - add title on non-drawer comment sections (couldn't see amount of comments) - fix Expandable component (would begin expanded and collapse after the effect runs, which looked bad and shifted the layout, now each comments greater than the set length begins collapsed) - used constants for consistency * Fix replying to last thread comment * Fix buttons condition (only on fetched comment to avoid deleted case) * Fix auto-scroll * Bring back instant feedback for Show More replies * Improve thread back links - Now going back to all comments links the top-level comment for easier navigation - Going back to ~ previous ~ now goes back into the chain instead of topmost level * Clear timeouts due to unrelated issue * Fix deep thread linked comment case and more scroll improvements * More minor changes * Flow * Fix commentList tile style * Fix long channel names overflowing on small screens * More scroll changes * Fix threadline * Revert "Fix long channel names overflowing on small screens" This reverts commit e4d2dc7da5861ed8136a60f3352e41a690cd4d33. * Fix replies fetch * Revert "Fix replies fetch" This reverts commit ec70054675a604a7a5f3764ba07c36bf7b0f49c8. * Cleanup and make smooth * Always use linked comment on threads * Cleanup * Higlight thread comment * Fix comment body styles
2022-05-16 12:22:13 +02:00
return () => {
clearTimeout(timer);
clearTimeout(nonCriticalTimer);
};
2019-07-23 10:05:51 +02:00
}
2019-11-18 19:30:15 +01:00
}, [readyToLaunch, persistDone]);
2017-06-06 06:21:55 +02:00
2019-07-23 10:05:51 +02:00
return (
<Provider store={store}>
2019-11-18 19:30:15 +01:00
<PersistGate
persistor={persistor}
onBeforeLift={() => setPersistDone(true)}
loading={<div className="main--launching" />}
>
2019-08-27 16:43:42 +02:00
<Fragment>
2019-07-23 10:05:51 +02:00
{readyToLaunch ? (
<ConnectedRouter history={history}>
<ErrorBoundary>
<App />
<SnackBar />
</ErrorBoundary>
</ConnectedRouter>
) : (
2019-12-11 21:27:03 +01:00
<Fragment>
<SplashScreen onReadyToLaunch={() => setReadyToLaunch(true)} />
2019-12-12 21:18:13 +01:00
<SnackBar />
2019-12-11 21:27:03 +01:00
</Fragment>
2019-07-23 10:05:51 +02:00
)}
2019-08-27 16:43:42 +02:00
</Fragment>
2019-07-23 10:05:51 +02:00
</PersistGate>
</Provider>
);
}
2019-07-23 10:05:51 +02:00
ReactDOM.render(<AppWrapper />, document.getElementById('app'));