From 27c9e79595aecee0ecf856d0ca1e463e4be6faab Mon Sep 17 00:00:00 2001 From: Madiator2011 Date: Mon, 16 Aug 2021 12:11:25 +0200 Subject: [PATCH] Uploaded source --- .env.defaults | 64 + .eslintignore | 4 + .eslintrc | 62 + .flowconfig | 43 + .gitignore | 36 + .lintstagedrc.json | 9 + .prettierrc.json | 5 + .sentryclirc | 4 + .tx/config | 7 + CHANGELOG.md | 1873 +++ CONTRIBUTING.md | 201 + LICENSE | 21 + README.md | 178 + add | 0 babel.config.js | 16 + build/afterAllArtifactBuild.js | 12 + build/afterSignHook.js | 33 + build/background.png | Bin 0 -> 8656 bytes build/downloadDaemon.js | 89 + build/downloadLBRYFirst.js | 91 + build/icon.icns | Bin 0 -> 91655 bytes build/icon.ico | Bin 0 -> 370070 bytes build/icons/128x128.png | Bin 0 -> 7552 bytes build/icons/256x256.png | Bin 0 -> 18944 bytes build/icons/32x32.png | Bin 0 -> 1248 bytes build/icons/48x48.png | Bin 0 -> 2675 bytes build/icons/96x96.png | Bin 0 -> 6294 bytes build/icons/lbry128.ico | Bin 0 -> 99678 bytes build/icons/lbry16.ico | Bin 0 -> 1150 bytes build/icons/lbry256.ico | Bin 0 -> 370070 bytes build/icons/lbry32.ico | Bin 0 -> 5430 bytes build/icons/lbry48.ico | Bin 0 -> 15086 bytes build/icons/lbry96.ico | Bin 0 -> 32038 bytes build/signBuildFiles.js | 158 + config.js | 56 + custom/homepage.example.js | 306 + custom/homepages/.gitkeep | 0 custom/robots.allowall | 2 + custom/robots.disallowall | 2 + electron-builder.json | 102 + electron/Daemon.js | 69 + electron/LbryFirstInstance.js | 59 + electron/createTray.js | 67 + electron/createWindow.js | 224 + electron/devServer.js | 70 + electron/index.js | 388 + electron/installDevtools.js | 11 + electron/menu/setupBarMenu.js | 127 + electron/sandboxTest.js | 4 + electron/startSandbox.js | 38 + electron/unpackByOutpoint.js | 23 + flow-typed/18nj.js | 2 + flow-typed/Comment.js | 114 + flow-typed/bluebird.js | 3 + flow-typed/classnames.js | 3 + flow-typed/content.js | 8 + flow-typed/electron.js | 3 + flow-typed/formik.js | 3 + flow-typed/homepage.js | 26 + flow-typed/livestream.js | 26 + flow-typed/location.js | 18 + flow-typed/notification.js | 43 + flow-typed/npm/@babel/core_vx.x.x.js | 298 + ...plugin-proposal-class-properties_vx.x.x.js | 32 + .../plugin-proposal-decorators_vx.x.x.js | 39 + ...lugin-transform-flow-strip-types_vx.x.x.js | 32 + flow-typed/npm/@babel/polyfill_v7.x.x.js | 4 + flow-typed/npm/@babel/preset-flow_vx.x.x.js | 32 + flow-typed/npm/@babel/preset-react_vx.x.x.js | 32 + flow-typed/npm/@babel/register_v7.x.x.js | 47 + .../npm/@hot-loader/react-dom_vx.x.x.js | 318 + flow-typed/npm/@lbry/color_vx.x.x.js | 18 + flow-typed/npm/@lbry/components_vx.x.x.js | 18 + flow-typed/npm/@types/three_vx.x.x.js | 18 + flow-typed/npm/async-exit-hook_vx.x.x.js | 33 + flow-typed/npm/babel-eslint_vx.x.x.js | 109 + flow-typed/npm/babel-loader_vx.x.x.js | 60 + .../babel-plugin-add-module-exports_vx.x.x.js | 32 + .../babel-plugin-transform-imports_vx.x.x.js | 52 + flow-typed/npm/bluebird_v3.x.x.js | 329 + flow-typed/npm/chalk_v2.x.x.js | 98 + flow-typed/npm/classnames_v2.x.x.js | 23 + flow-typed/npm/codemirror_vx.x.x.js | 1761 +++ flow-typed/npm/copy-webpack-plugin_vx.x.x.js | 95 + flow-typed/npm/country-data_vx.x.x.js | 129 + flow-typed/npm/cross-env_vx.x.x.js | 60 + flow-typed/npm/css-loader_vx.x.x.js | 102 + flow-typed/npm/dat.gui_vx.x.x.js | 228 + flow-typed/npm/decompress_vx.x.x.js | 33 + flow-typed/npm/del_v3.x.x.js | 50 + flow-typed/npm/devtron_vx.x.x.js | 46 + flow-typed/npm/dom-scroll-into-view_vx.x.x.js | 46 + flow-typed/npm/electron-builder_vx.x.x.js | 67 + .../npm/electron-devtools-installer_vx.x.x.js | 67 + flow-typed/npm/electron-dl_vx.x.x.js | 33 + flow-typed/npm/electron-is-dev_vx.x.x.js | 33 + flow-typed/npm/electron-log_vx.x.x.js | 108 + .../npm/electron-publisher-s3_vx.x.x.js | 53 + flow-typed/npm/electron-updater_vx.x.x.js | 186 + flow-typed/npm/electron-webpack_vx.x.x.js | 235 + .../npm/electron-window-state_vx.x.x.js | 33 + flow-typed/npm/electron_vx.x.x.js | 45 + flow-typed/npm/eslint-config-airbnb_vx.x.x.js | 73 + .../npm/eslint-config-prettier_vx.x.x.js | 66 + .../npm/eslint-config-standard-jsx_vx.x.x.js | 33 + .../npm/eslint-config-standard_vx.x.x.js | 33 + .../eslint-import-resolver-webpack_vx.x.x.js | 38 + .../npm/eslint-plugin-flowtype_vx.x.x.js | 424 + flow-typed/npm/eslint-plugin-import_vx.x.x.js | 410 + .../npm/eslint-plugin-jsx-a11y_vx.x.x.js | 1194 ++ flow-typed/npm/eslint-plugin-node_vx.x.x.js | 333 + .../npm/eslint-plugin-prettier_vx.x.x.js | 32 + .../npm/eslint-plugin-promise_vx.x.x.js | 185 + flow-typed/npm/eslint-plugin-react_vx.x.x.js | 696 + .../npm/eslint-plugin-standard_vx.x.x.js | 59 + flow-typed/npm/eslint_vx.x.x.js | 2524 ++++ flow-typed/npm/express_v4.16.x.js | 304 + flow-typed/npm/flow-bin_v0.x.x.js | 6 + flow-typed/npm/flow-typed_vx.x.x.js | 193 + flow-typed/npm/formik_vx.x.x.js | 53 + flow-typed/npm/hast-util-sanitize_vx.x.x.js | 38 + flow-typed/npm/husky_vx.x.x.js | 88 + flow-typed/npm/json-loader_vx.x.x.js | 33 + flow-typed/npm/lbry-format_vx.x.x.js | 33 + flow-typed/npm/lbry-redux_vx.x.x.js | 305 + flow-typed/npm/lbryinc_vx.x.x.js | 277 + flow-typed/npm/lint-staged_vx.x.x.js | 108 + flow-typed/npm/localforage_v1.5.x.js | 84 + flow-typed/npm/make-runnable_vx.x.x.js | 80 + flow-typed/npm/mammoth_vx.x.x.js | 564 + flow-typed/npm/mixpanel-browser_v2.11.x.js | 37 + flow-typed/npm/moment_v2.x.x.js | 378 + flow-typed/npm/node-abi_vx.x.x.js | 38 + flow-typed/npm/node-fetch_vx.x.x.js | 46 + flow-typed/npm/node-libs-browser_vx.x.x.js | 94 + flow-typed/npm/node-loader_vx.x.x.js | 33 + flow-typed/npm/preprocess-loader_vx.x.x.js | 38 + flow-typed/npm/prettier_v1.x.x.js | 178 + flow-typed/npm/prop-types_v15.x.x.js | 35 + flow-typed/npm/qrcode.react_vx.x.x.js | 32 + flow-typed/npm/raw-loader_vx.x.x.js | 33 + flow-typed/npm/rc-progress_vx.x.x.js | 109 + flow-typed/npm/react-hot-loader_v4.6.x.js | 60 + flow-typed/npm/react-modal_v3.1.x.js | 52 + flow-typed/npm/react-paginate_vx.x.x.js | 123 + flow-typed/npm/react-redux_v5.x.x.js | 276 + .../npm/react-simplemde-editor_vx.x.x.js | 32 + flow-typed/npm/react-toggle_v4.0.x.js | 26 + ...redux-persist-transform-compress_vx.x.x.js | 39 + .../redux-persist-transform-filter_vx.x.x.js | 38 + flow-typed/npm/redux-thunk_vx.x.x.js | 60 + flow-typed/npm/remark-emoji_vx.x.x.js | 38 + flow-typed/npm/remark-react_vx.x.x.js | 33 + flow-typed/npm/remark_vx.x.x.js | 33 + flow-typed/npm/render-media_vx.x.x.js | 33 + flow-typed/npm/reselect_v3.x.x.js | 895 ++ flow-typed/npm/sass-loader_vx.x.x.js | 67 + flow-typed/npm/semver_v5.1.x.js | 198 + flow-typed/npm/stream-to-blob-url_vx.x.x.js | 33 + flow-typed/npm/style-loader_vx.x.x.js | 66 + flow-typed/npm/three-full_vx.x.x.js | 3784 +++++ flow-typed/npm/three_vx.x.x.js | 3910 +++++ flow-typed/npm/tree-kill_vx.x.x.js | 38 + flow-typed/npm/video.js_vx.x.x.js | 361 + flow-typed/npm/webpack-config-utils_vx.x.x.js | 53 + .../npm/webpack-dev-middleware_vx.x.x.js | 73 + flow-typed/npm/webpack-dev-server_vx.x.x.js | 165 + .../npm/webpack-hot-middleware_vx.x.x.js | 60 + flow-typed/npm/webpack-merge_vx.x.x.js | 60 + .../npm/webpack-node-externals_vx.x.x.js | 38 + flow-typed/npm/webpack_v4.x.x.js | 594 + flow-typed/npm/y18n_vx.x.x.js | 33 + flow-typed/npm/yarnhook_vx.x.x.js | 33 + flow-typed/publish.js | 54 + flow-typed/qrcode.react.js | 3 + flow-typed/react-markdown.js | 3 + flow-typed/react-modal.js | 3 + flow-typed/react-paginate.js | 3 + flow-typed/react-simplemde-editor.js | 7 + flow-typed/react-transition-group.js | 3 + flow-typed/redux.js | 3 + flow-typed/reportContent.js | 9 + flow-typed/reselect.js | 5 + flow-typed/reward.js | 16 + flow-typed/search.js | 49 + flow-typed/shapeshift.io.js | 3 + flow-typed/subscription.js | 19 + flow-typed/user.js | 34 + flow-typed/web-file.js | 6 + flow-typed/web.js | 3 + homepages/homepage.js | 257 + homepages/index.js | 5 + package.json | 240 + postcss.config.js | 16 + static/app-strings.json | 1951 +++ static/font/v1/300.woff | Bin 0 -> 28712 bytes static/font/v1/300i.woff | Bin 0 -> 32032 bytes static/font/v1/400.woff | Bin 0 -> 27416 bytes static/font/v1/400i.woff | Bin 0 -> 30464 bytes static/font/v1/700.woff | Bin 0 -> 29956 bytes static/font/v1/700i.woff | Bin 0 -> 32584 bytes static/img/busy.gif | Bin 0 -> 1262 bytes static/img/favicon.png | Bin 0 -> 1349 bytes static/img/tray/default/tray.png | Bin 0 -> 2002 bytes static/img/tray/mac/trayTemplate.png | Bin 0 -> 1414 bytes static/img/tray/mac/trayTemplate@2x copy.png | Bin 0 -> 3331 bytes static/img/tray/mac/trayTemplate@2x.png | Bin 0 -> 3331 bytes static/img/tray/windows/tray.ico | Bin 0 -> 370070 bytes static/img/unlocklbry.svg | 210 + static/img/v2-og.png | Bin 0 -> 492778 bytes static/index-electron.html | 70 + static/index-web.html | 72 + static/opensearch.xml | 4 + static/robots.txt | 2 + static/webworkers/wasm-gen/libarchive.js | 5112 +++++++ static/webworkers/wasm-gen/libarchive.wasm | Bin 0 -> 896488 bytes static/webworkers/worker-bundle.js | 3960 +++++ ui/analytics.js | 325 + ui/app.js | 20 + ui/comments.js | 51 + ui/component/IframeReact/index.js | 8 + ui/component/IframeReact/view.jsx | 35 + ui/component/abandonedChannelPreview/index.js | 6 + ui/component/abandonedChannelPreview/view.jsx | 43 + ui/component/app/index.js | 68 + ui/component/app/view.jsx | 404 + ui/component/autoplayCountdown/index.js | 42 + ui/component/autoplayCountdown/view.jsx | 147 + ui/component/button/index.js | 13 + ui/component/button/view.jsx | 240 + ui/component/cardVerify/index.js | 11 + ui/component/cardVerify/view.jsx | 184 + ui/component/channelAbout/index.js | 13 + ui/component/channelAbout/view.jsx | 122 + ui/component/channelBlockButton/index.js | 14 + ui/component/channelBlockButton/view.jsx | 41 + ui/component/channelContent/index.js | 40 + ui/component/channelContent/view.jsx | 175 + ui/component/channelDiscussion/index.js | 19 + ui/component/channelDiscussion/view.jsx | 25 + ui/component/channelEdit/index.js | 55 + ui/component/channelEdit/view.jsx | 486 + ui/component/channelMuteButton/index.js | 12 + ui/component/channelMuteButton/view.jsx | 24 + ui/component/channelSelector/index.js | 16 + ui/component/channelSelector/view.jsx | 101 + ui/component/channelStakedIndicator/index.js | 15 + ui/component/channelStakedIndicator/view.jsx | 94 + ui/component/channelThumbnail/gerbil.png | Bin 0 -> 4697 bytes ui/component/channelThumbnail/index.js | 13 + .../channelThumbnail/transparent_1x1.png | Bin 0 -> 120 bytes ui/component/channelThumbnail/view.jsx | 129 + ui/component/channelTitle/index.js | 10 + ui/component/channelTitle/view.jsx | 19 + ui/component/claimAbandonButton/index.js | 13 + ui/component/claimAbandonButton/view.jsx | 40 + ui/component/claimAuthor/index.js | 9 + ui/component/claimAuthor/view.jsx | 20 + ui/component/claimCollectionAdd/index.js | 23 + ui/component/claimCollectionAdd/view.jsx | 133 + .../claimCollectionAddButton/index.js | 12 + .../claimCollectionAddButton/view.jsx | 40 + ui/component/claimEffectiveAmount/index.js | 9 + ui/component/claimEffectiveAmount/view.jsx | 20 + .../claimInsufficientCredits/index.js | 11 + .../claimInsufficientCredits/view.jsx | 37 + ui/component/claimLink/index.js | 22 + ui/component/claimLink/view.jsx | 119 + ui/component/claimList/index.js | 12 + ui/component/claimList/view.jsx | 218 + ui/component/claimListDiscover/index.js | 34 + ui/component/claimListDiscover/view.jsx | 560 + ui/component/claimListHeader/index.js | 22 + ui/component/claimListHeader/view.jsx | 473 + ui/component/claimMenuList/index.js | 48 + ui/component/claimMenuList/view.jsx | 390 + .../claimPreview/claim-preview-loading.jsx | 30 + .../claimPreview/claim-preview-no-content.jsx | 32 + .../claimPreview/claim-preview-no-mature.jsx | 33 + ui/component/claimPreview/index.js | 58 + ui/component/claimPreview/view.jsx | 430 + ui/component/claimPreviewSubtitle/index.js | 27 + ui/component/claimPreviewSubtitle/view.jsx | 56 + ui/component/claimPreviewTile/index.js | 37 + ui/component/claimPreviewTile/view.jsx | 254 + ui/component/claimPreviewTitle/index.js | 10 + ui/component/claimPreviewTitle/view.jsx | 21 + ui/component/claimProperties/index.js | 12 + ui/component/claimProperties/view.jsx | 38 + ui/component/claimRepostAuthor/index.js | 9 + ui/component/claimRepostAuthor/view.jsx | 58 + ui/component/claimSupportButton/index.js | 14 + ui/component/claimSupportButton/view.jsx | 36 + ui/component/claimTags/index.js | 11 + ui/component/claimTags/view.jsx | 61 + ui/component/claimTilesDiscover/index.js | 30 + ui/component/claimTilesDiscover/view.jsx | 297 + ui/component/claimType/index.js | 10 + ui/component/claimType/view.jsx | 29 + ui/component/claimUri/index.js | 12 + ui/component/claimUri/view.jsx | 33 + ui/component/collectionActions/index.js | 30 + ui/component/collectionActions/view.jsx | 130 + .../collectionContentSidebar/index.js | 24 + .../collectionContentSidebar/view.jsx | 42 + ui/component/collectionEdit/index.js | 53 + ui/component/collectionEdit/view.jsx | 441 + ui/component/collectionMenuList/index.js | 16 + ui/component/collectionMenuList/view.jsx | 59 + .../collectionPreviewOverlay/index.js | 30 + .../collectionPreviewOverlay/view.jsx | 42 + .../collectionPreviewTile/collectionCount.jsx | 19 + .../collectionPrivate.jsx | 14 + ui/component/collectionPreviewTile/index.js | 58 + ui/component/collectionPreviewTile/view.jsx | 174 + ui/component/collectionSelectItem/index.js | 24 + ui/component/collectionSelectItem/view.jsx | 59 + ui/component/collectionsListMine/index.js | 17 + ui/component/collectionsListMine/view.jsx | 91 + ui/component/comment/index.js | 31 + ui/component/comment/view.jsx | 325 + ui/component/commentCreate/index.js | 34 + ui/component/commentCreate/view.jsx | 309 + ui/component/commentMenuList/index.js | 29 + ui/component/commentMenuList/view.jsx | 143 + ui/component/commentReactions/index.js | 22 + ui/component/commentReactions/view.jsx | 113 + ui/component/commentsList/index.js | 31 + ui/component/commentsList/view.jsx | 256 + ui/component/commentsReplies/index.js | 14 + ui/component/commentsReplies/view.jsx | 126 + ui/component/common/busy-indicator.jsx | 24 + ui/component/common/card.jsx | 130 + ui/component/common/credit-amount.jsx | 102 + ui/component/common/empty.jsx | 24 + ui/component/common/error-text.jsx | 20 + ui/component/common/file-exporter.jsx | 89 + ui/component/common/file-list.jsx | 74 + ui/component/common/file-selector.jsx | 112 + .../form-components/form-field-price.jsx | 81 + .../common/form-components/form-field.jsx | 334 + .../common/form-components/form-row.jsx | 38 + ui/component/common/form-components/form.jsx | 28 + .../common/form-components/submit.jsx | 21 + ui/component/common/form.jsx | 4 + ui/component/common/help-link.jsx | 30 + ui/component/common/hidden-nsfw.jsx | 31 + ui/component/common/icon-custom.jsx | 2319 +++ ui/component/common/icon.jsx | 84 + ui/component/common/lbc-message.jsx | 26 + ui/component/common/lbc-symbol.jsx | 35 + ui/component/common/loading-screen.jsx | 34 + ui/component/common/markdown-preview.jsx | 234 + ui/component/common/nag.jsx | 57 + ui/component/common/paginate.jsx | 82 + ui/component/common/qr-code.jsx | 33 + ui/component/common/status-bar.jsx | 48 + ui/component/common/tabs.jsx | 130 + ui/component/common/thumbnail.jsx | 28 + ui/component/common/tooltip.jsx | 18 + ui/component/common/transaction-link.jsx | 18 + ui/component/common/truncated-text.jsx | 25 + ui/component/common/wait-until-on-page.jsx | 50 + ui/component/copyableText/index.js | 7 + ui/component/copyableText/view.jsx | 66 + ui/component/creatorAnalytics/index.js | 9 + ui/component/creatorAnalytics/view.jsx | 284 + ui/component/dateTime/index.js | 10 + ui/component/dateTime/view.jsx | 120 + ui/component/emailCollection/index.js | 20 + ui/component/emailCollection/view.jsx | 40 + ui/component/embedPlayButton/index.js | 25 + ui/component/embedPlayButton/view.jsx | 108 + ui/component/embedTextArea/index.js | 7 + ui/component/embedTextArea/view.jsx | 68 + ui/component/errorBoundary/index.js | 4 + ui/component/errorBoundary/view.jsx | 124 + ui/component/expandable/index.js | 7 + ui/component/expandable/view.jsx | 47 + ui/component/fileActions/index.js | 50 + ui/component/fileActions/view.jsx | 168 + ui/component/fileDescription/index.js | 24 + ui/component/fileDescription/view.jsx | 92 + ui/component/fileDetails/index.js | 24 + ui/component/fileDetails/view.jsx | 103 + ui/component/fileDownloadLink/index.js | 33 + ui/component/fileDownloadLink/view.jsx | 120 + ui/component/fileDrop/index.js | 20 + ui/component/fileDrop/view.jsx | 158 + ui/component/filePrice/index.js | 18 + ui/component/filePrice/view.jsx | 77 + ui/component/fileReactions/index.js | 26 + ui/component/fileReactions/view.jsx | 64 + ui/component/fileRender/index.js | 29 + ui/component/fileRender/view.jsx | 165 + ui/component/fileRenderDownload/index.js | 10 + ui/component/fileRenderDownload/view.jsx | 40 + ui/component/fileRenderFloating/index.js | 46 + ui/component/fileRenderFloating/view.jsx | 314 + ui/component/fileRenderInitiator/index.js | 50 + ui/component/fileRenderInitiator/view.jsx | 175 + ui/component/fileRenderInline/index.js | 24 + ui/component/fileRenderInline/view.jsx | 73 + ui/component/fileSubtitle/index.js | 2 + ui/component/fileSubtitle/view.jsx | 30 + .../fileThumbnail/FreezeframeLite/classes.js | 15 + .../fileThumbnail/FreezeframeLite/index.js | 172 + .../fileThumbnail/FreezeframeLite/styles.scss | 68 + .../FreezeframeLite/templates.js | 5 + .../fileThumbnail/FreezeframeLite/utils.js | 18 + .../fileThumbnail/FreezeframeWrapper.jsx | 36 + ui/component/fileThumbnail/index.js | 9 + ui/component/fileThumbnail/placeholder.png | Bin 0 -> 28818 bytes ui/component/fileThumbnail/view.jsx | 81 + ui/component/fileTitle/index.js | 9 + ui/component/fileTitle/view.jsx | 23 + ui/component/fileTitleSection/index.js | 11 + ui/component/fileTitleSection/view.jsx | 94 + ui/component/fileType/index.js | 10 + ui/component/fileType/view.jsx | 31 + ui/component/fileValues/index.js | 29 + ui/component/fileValues/view.jsx | 109 + ui/component/fileViewCount/index.js | 17 + ui/component/fileViewCount/view.jsx | 52 + ui/component/fileViewerEmbeddedTitle/index.js | 9 + ui/component/fileViewerEmbeddedTitle/view.jsx | 46 + ui/component/formFieldPrice/index.js | 3 + ui/component/formFieldPrice/view.jsx | 5 + ui/component/header/index.js | 39 + ui/component/header/odysee.png | Bin 0 -> 10258 bytes ui/component/header/odysee_logo.png | Bin 0 -> 61782 bytes ui/component/header/odysee_white.png | Bin 0 -> 29186 bytes ui/component/header/view.jsx | 467 + ui/component/hiddenNsfwClaims/index.js | 30 + ui/component/hiddenNsfwClaims/view.jsx | 34 + ui/component/homepageSelector/index.js | 14 + ui/component/homepageSelector/view.jsx | 44 + ui/component/i18nMessage/index.js | 11 + ui/component/i18nMessage/view.jsx | 35 + ui/component/inviteList/index.js | 14 + ui/component/inviteList/view.jsx | 99 + ui/component/inviteNew/index.js | 28 + ui/component/inviteNew/view.jsx | 149 + ui/component/invited/index.js | 30 + ui/component/invited/view.jsx | 218 + ui/component/lastReleaseChanges/index.js | 3 + ui/component/lastReleaseChanges/view.jsx | 83 + ui/component/livestreamComment/index.js | 10 + ui/component/livestreamComment/view.jsx | 88 + ui/component/livestreamComments/index.js | 27 + ui/component/livestreamComments/view.jsx | 209 + ui/component/livestreamLayout/index.js | 12 + ui/component/livestreamLayout/view.jsx | 62 + ui/component/livestreamLink/index.js | 9 + ui/component/livestreamLink/view.jsx | 86 + ui/component/livestreamList/index.js | 6 + ui/component/livestreamList/view.jsx | 77 + ui/component/loginGraphic/index.jsx | 39 + ui/component/markdownLink/index.js | 10 + ui/component/markdownLink/view.jsx | 133 + ui/component/nagContinueFirstRun/index.js | 11 + ui/component/nagContinueFirstRun/view.jsx | 38 + ui/component/navigationButton/index.js | 3 + ui/component/navigationButton/view.jsx | 97 + ui/component/navigationHistory/index.js | 25 + ui/component/navigationHistory/view.jsx | 121 + ui/component/navigationHistoryItem/index.js | 16 + ui/component/navigationHistoryItem/view.jsx | 66 + ui/component/navigationHistoryRecent/index.js | 12 + ui/component/navigationHistoryRecent/view.jsx | 28 + ui/component/notification/index.js | 8 + ui/component/notification/view.jsx | 211 + ui/component/notificationBubble/index.js | 11 + ui/component/notificationBubble/view.jsx | 34 + .../notificationContentChannelMenu/index.js | 14 + .../notificationContentChannelMenu/view.jsx | 42 + .../notificationHeaderButton/index.js | 20 + .../notificationHeaderButton/view.jsx | 50 + ui/component/nudgeFloating/index.js | 9 + ui/component/nudgeFloating/view.jsx | 43 + ui/component/page/index.js | 10 + ui/component/page/view.jsx | 135 + ui/component/postEditor/index.js | 23 + ui/component/postEditor/view.jsx | 114 + ui/component/postViewer/index.js | 13 + ui/component/postViewer/view.jsx | 114 + ui/component/previewLink/index.js | 31 + ui/component/previewLink/view.jsx | 66 + .../previewOverlayProperties/index.js | 23 + .../previewOverlayProperties/view.jsx | 75 + ui/component/privacyAgreement/index.js | 26 + ui/component/privacyAgreement/view.jsx | 182 + .../publishAdditionalOptions/index.js | 18 + .../publishAdditionalOptions/license-type.jsx | 108 + .../publishAdditionalOptions/view.jsx | 207 + ui/component/publishBid/bid-help-text.jsx | 38 + ui/component/publishBid/index.js | 26 + ui/component/publishBid/view.jsx | 77 + ui/component/publishDescription/index.js | 13 + ui/component/publishDescription/view.jsx | 46 + ui/component/publishFile/index.js | 36 + ui/component/publishFile/view.jsx | 674 + ui/component/publishForm/index.js | 75 + ui/component/publishForm/view.jsx | 658 + ui/component/publishFormErrors/index.js | 17 + ui/component/publishFormErrors/view.jsx | 59 + ui/component/publishName/bid-help-text.jsx | 38 + ui/component/publishName/index.js | 28 + ui/component/publishName/name-help-text.jsx | 60 + ui/component/publishName/view.jsx | 94 + ui/component/publishPending/index.js | 13 + ui/component/publishPending/view.jsx | 37 + ui/component/publishPrice/index.js | 17 + ui/component/publishPrice/view.jsx | 58 + ui/component/publishReleaseDate/index.js | 14 + ui/component/publishReleaseDate/view.jsx | 132 + ui/component/publishSettings/index.js | 15 + ui/component/publishSettings/view.jsx | 31 + ui/component/recommendedContent/index.js | 22 + ui/component/recommendedContent/view.jsx | 144 + ui/component/reportContent/index.js | 29 + ui/component/reportContent/view.jsx | 730 + ui/component/repostCreate/index.js | 50 + ui/component/repostCreate/view.jsx | 416 + ui/component/rewardAuthIntro/index.js | 9 + ui/component/rewardAuthIntro/view.jsx | 46 + ui/component/rewardLink/index.js | 17 + ui/component/rewardLink/view.jsx | 46 + ui/component/rewardListClaimed/index.js | 9 + ui/component/rewardListClaimed/view.jsx | 68 + ui/component/rewardSummary/index.js | 10 + ui/component/rewardSummary/view.jsx | 52 + ui/component/rewardTile/index.js | 15 + ui/component/rewardTile/view.jsx | 70 + ui/component/rewardTotal/index.js | 16 + ui/component/rewardTotal/total-background.png | Bin 0 -> 47186 bytes ui/component/rewardTotal/view.jsx | 26 + ui/component/router/index.js | 45 + ui/component/router/view.jsx | 314 + ui/component/searchOptions/index.js | 22 + ui/component/searchOptions/view.jsx | 242 + ui/component/searchTopClaim/index.js | 28 + ui/component/searchTopClaim/view.jsx | 143 + ui/component/selectAsset/index.js | 12 + ui/component/selectAsset/thumbnail-broken.png | Bin 0 -> 6680 bytes .../selectAsset/thumbnail-missing.png | Bin 0 -> 2791 bytes ui/component/selectAsset/view.jsx | 172 + ui/component/selectChannel/index.js | 28 + ui/component/selectChannel/view.jsx | 65 + ui/component/selectThumbnail/index.js | 28 + .../selectThumbnail/thumbnail-broken.png | Bin 0 -> 6680 bytes .../selectThumbnail/thumbnail-missing.png | Bin 0 -> 2791 bytes ui/component/selectThumbnail/view.jsx | 181 + ui/component/settingAccountPassword/index.js | 19 + ui/component/settingAccountPassword/view.jsx | 91 + ui/component/settingAutoLaunch/index.js | 18 + ui/component/settingAutoLaunch/view.jsx | 33 + ui/component/settingClosingBehavior/index.js | 15 + ui/component/settingClosingBehavior/view.jsx | 29 + ui/component/settingLanguage/index.js | 17 + ui/component/settingLanguage/view.jsx | 60 + ui/component/settingWalletServer/index.js | 29 + .../settingWalletServer/internal/inputRow.jsx | 64 + ui/component/settingWalletServer/view.jsx | 186 + ui/component/shareButton/index.js | 14 + ui/component/shareButton/view.jsx | 24 + ui/component/sideNavigation/index.js | 28 + ui/component/sideNavigation/view.jsx | 484 + ui/component/snackBar/index.js | 14 + ui/component/snackBar/view.jsx | 70 + ui/component/socialShare/index.js | 15 + ui/component/socialShare/view.jsx | 177 + ui/component/spinner/index.js | 12 + ui/component/spinner/view.jsx | 86 + ui/component/splash/index.js | 26 + ui/component/splash/view.jsx | 335 + ui/component/subscribeButton/index.js | 25 + ui/component/subscribeButton/view.jsx | 134 + ui/component/supportsLiquidate/index.js | 31 + ui/component/supportsLiquidate/view.jsx | 176 + ui/component/syncEnableFlow/index.js | 33 + ui/component/syncEnableFlow/view.jsx | 245 + ui/component/syncFatalError/index.js | 2 + ui/component/syncFatalError/view.jsx | 52 + ui/component/syncPassword/index.js | 22 + ui/component/syncPassword/view.jsx | 92 + ui/component/syncToggle/index.js | 22 + ui/component/syncToggle/view.jsx | 43 + ui/component/tag/index.js | 11 + ui/component/tag/view.jsx | 52 + ui/component/tagsSearch/index.js | 17 + ui/component/tagsSearch/view.jsx | 254 + ui/component/tagsSelect/index.js | 15 + ui/component/tagsSelect/view.jsx | 119 + ui/component/theme/index.js | 9 + ui/component/theme/view.jsx | 18 + ui/component/thumbnailPicker/index.js | 13 + .../thumbnailPicker/thumbnail-broken.png | Bin 0 -> 6680 bytes .../thumbnailPicker/thumbnail-missing.png | Bin 0 -> 2791 bytes ui/component/thumbnailPicker/view.jsx | 116 + ui/component/transactionListTable/index.js | 16 + ui/component/transactionListTable/view.jsx | 64 + .../transactionListTableItem/index.js | 17 + .../transactionListTableItem/view.jsx | 170 + ui/component/txoList/index.js | 35 + ui/component/txoList/view.jsx | 301 + ui/component/uriIndicator/index.js | 18 + ui/component/uriIndicator/view.jsx | 110 + ui/component/userChannelFollowIntro/index.js | 20 + ui/component/userChannelFollowIntro/view.jsx | 87 + ui/component/userEmail/index.js | 18 + ui/component/userEmail/view.jsx | 73 + ui/component/userEmailNew/index.js | 32 + ui/component/userEmailNew/view.jsx | 230 + ui/component/userEmailReturning/index.js | 27 + ui/component/userEmailReturning/view.jsx | 152 + ui/component/userEmailVerify/index.js | 25 + ui/component/userEmailVerify/view.jsx | 121 + ui/component/userFirstChannel/index.js | 18 + ui/component/userFirstChannel/view.jsx | 118 + ui/component/userPasswordReset/index.js | 24 + ui/component/userPasswordReset/view.jsx | 112 + ui/component/userPasswordSet/index.js | 16 + ui/component/userPasswordSet/view.jsx | 108 + ui/component/userPhoneNew/index.js | 14 + ui/component/userPhoneNew/view.jsx | 124 + ui/component/userPhoneVerify/index.js | 17 + ui/component/userPhoneVerify/view.jsx | 90 + ui/component/userSignIn/index.js | 15 + ui/component/userSignIn/view.jsx | 58 + ui/component/userSignInPassword/index.js | 23 + ui/component/userSignInPassword/view.jsx | 67 + ui/component/userSignOutButton/index.js | 12 + ui/component/userSignOutButton/view.jsx | 29 + ui/component/userSignUp/index.js | 69 + ui/component/userSignUp/view.jsx | 279 + ui/component/userTagFollowIntro/index.js | 9 + ui/component/userTagFollowIntro/view.jsx | 56 + ui/component/userVerify/index.js | 26 + ui/component/userVerify/view.jsx | 164 + ui/component/videoDuration/index.js | 12 + ui/component/videoDuration/view.jsx | 30 + ui/component/viewers/appViewer/index.js | 15 + ui/component/viewers/appViewer/view.jsx | 74 + ui/component/viewers/codeViewer.jsx | 83 + ui/component/viewers/comicBookViewer.jsx | 67 + ui/component/viewers/documentViewer.jsx | 103 + ui/component/viewers/docxViewer.jsx | 70 + ui/component/viewers/htmlViewer.jsx | 51 + ui/component/viewers/imageViewer.jsx | 32 + ui/component/viewers/pdfViewer.jsx | 24 + ui/component/viewers/threeViewer/index.jsx | 505 + .../viewers/threeViewer/internal/detector.js | 10 + .../viewers/threeViewer/internal/grid.js | 12 + .../viewers/threeViewer/internal/renderer.js | 14 + .../viewers/threeViewer/internal/scene.js | 40 + ui/component/viewers/videoViewer/index.js | 47 + .../viewers/videoViewer/internal/overlays.js | 118 + .../ConcreteButton.js | 83 + .../ConcreteMenuItem.js | 42 + .../videojs-hls-quality-selector/package.json | 109 + .../videojs-hls-quality-selector/plugin.js | 266 + .../videojs-hls-quality-selector/plugin.scss | 9 + .../plugins/videojs-mobile-ui/LICENSE | 19 + .../plugins/videojs-mobile-ui/plugin.js | 168 + .../plugins/videojs-mobile-ui/plugin.scss | 82 + .../plugins/videojs-mobile-ui/touchOverlay.js | 179 + .../plugins/videojs-overlay/plugin.js | 364 + .../plugins/videojs-overlay/plugin.scss | 84 + .../videoViewer/internal/theater-mode.js | 16 + .../viewers/videoViewer/internal/videojs.jsx | 614 + ui/component/viewers/videoViewer/view.jsx | 351 + ui/component/walletAddress/index.js | 21 + ui/component/walletAddress/view.jsx | 86 + ui/component/walletBackup/index.js | 9 + ui/component/walletBackup/view.jsx | 156 + ui/component/walletBalance/index.js | 40 + ui/component/walletBalance/view.jsx | 187 + ui/component/walletSend/index.js | 19 + ui/component/walletSend/view.jsx | 223 + ui/component/walletSendTip/index.js | 37 + ui/component/walletSendTip/view.jsx | 316 + .../walletSpendableBalanceHelp/index.js | 9 + .../walletSpendableBalanceHelp/view.jsx | 34 + ui/component/walletSwap/index.js | 26 + ui/component/walletSwap/view.jsx | 707 + ui/component/walletTipAmountSelector/index.js | 9 + ui/component/walletTipAmountSelector/view.jsx | 123 + ui/component/webUploadList/index.js | 13 + .../internal/web-upload-item.jsx | 41 + ui/component/webUploadList/view.jsx | 36 + ui/component/wunderbar/index.js | 10 + ui/component/wunderbar/view.jsx | 21 + ui/component/wunderbarSuggestion/index.js | 9 + ui/component/wunderbarSuggestion/view.jsx | 58 + ui/component/wunderbarSuggestions/index.js | 30 + ui/component/wunderbarSuggestions/view.jsx | 305 + ui/component/wunderbarTopSuggestion/index.js | 28 + ui/component/wunderbarTopSuggestion/view.jsx | 55 + ui/component/youtubeBadge/index.js | 8 + ui/component/youtubeBadge/view.jsx | 46 + ui/component/youtubeTransferStatus/index.js | 24 + ui/component/youtubeTransferStatus/view.jsx | 237 + ui/component/yrbl/index.jsx | 52 + ui/component/yrblWalletEmpty/index.js | 9 + ui/component/yrblWalletEmpty/view.jsx | 56 + ui/component/zoomableImage/index.js | 9 + ui/component/zoomableImage/view.jsx | 20 + ui/constants/action_types.js | 341 + ui/constants/claim.js | 34 + ui/constants/claim_search.js | 59 + ui/constants/collections.js | 2 + ui/constants/comment.js | 5 + ui/constants/email.js | 1 + ui/constants/file_render_modes.js | 33 + ui/constants/form-field.js | 7 + ui/constants/icons.js | 164 + ui/constants/language-migrations.js | 6 + ui/constants/languages.js | 191 + ui/constants/licenses.js | 38 + ui/constants/livestream.js | 3 + ui/constants/modal_types.js | 47 + ui/constants/moonpay.js | 62 + ui/constants/notifications.js | 17 + ui/constants/pages.js | 74 + ui/constants/publish_types.js | 3 + ui/constants/reactions.js | 3 + ui/constants/report_content.js | 71 + ui/constants/search.js | 36 + ui/constants/searchable_languages.js | 20 + ui/constants/settings.js | 28 + ui/constants/subscriptions.js | 12 + ui/constants/supported_browser_languages.js | 45 + ui/constants/supported_languages.js | 47 + ui/constants/supported_sub_languages.js | 5 + ui/constants/tags.js | 550 + ui/constants/themes.js | 4 + ui/constants/thumbnail_upload_statuses.js | 5 + ui/constants/token.js | 1 + ui/constants/transaction_types.js | 4 + ui/constants/user.js | 26 + ui/effects/use-combined-refs.js | 24 + ui/effects/use-drag-drop.js | 97 + ui/effects/use-fetched.js | 17 + ui/effects/use-get-ads.js | 55 + ui/effects/use-get-livestreams.js | 55 + ui/effects/use-get-thumbnail.js | 54 + ui/effects/use-history-nav.js | 25 + ui/effects/use-hover.js | 23 + ui/effects/use-is-mounted.js | 17 + ui/effects/use-lazy-loading.js | 57 + ui/effects/use-lighthouse.js | 39 + ui/effects/use-persisted-state.js | 67 + ui/effects/use-previous.js | 11 + ui/effects/use-screensize.js | 36 + ui/effects/use-stream-file.js | 46 + ui/effects/use-stream.js | 55 + ui/effects/use-throttle.js | 49 + ui/effects/use-tween.js | 31 + ui/effects/use-zoom.js | 51 + ui/i18n.js | 103 + ui/index.jsx | 300 + ui/logWarningConsoleMessage.js | 30 + ui/modal/modal.jsx | 115 + ui/modal/modalAffirmPurchase/index.js | 20 + ui/modal/modalAffirmPurchase/view.jsx | 120 + ui/modal/modalAutoGenerateThumbnail/index.js | 13 + ui/modal/modalAutoGenerateThumbnail/view.jsx | 87 + ui/modal/modalAutoUpdateDownloaded/index.js | 13 + ui/modal/modalAutoUpdateDownloaded/view.jsx | 45 + ui/modal/modalClaimCollectionAdd/index.js | 11 + ui/modal/modalClaimCollectionAdd/view.jsx | 19 + ui/modal/modalCommentAcknowledgement/index.js | 12 + ui/modal/modalCommentAcknowledgement/view.jsx | 41 + ui/modal/modalConfirmAge/index.js | 9 + ui/modal/modalConfirmAge/view.jsx | 52 + ui/modal/modalConfirmThumbnailUpload/index.js | 15 + ui/modal/modalConfirmThumbnailUpload/view.jsx | 42 + ui/modal/modalConfirmTransaction/index.js | 19 + ui/modal/modalConfirmTransaction/view.jsx | 92 + ui/modal/modalDownloading/index.js | 23 + ui/modal/modalDownloading/view.jsx | 52 + ui/modal/modalError/index.js | 9 + ui/modal/modalError/view.jsx | 64 + ui/modal/modalFileSelection/index.js | 12 + ui/modal/modalFileSelection/view.jsx | 78 + ui/modal/modalFileTimeout/index.js | 17 + ui/modal/modalFileTimeout/view.jsx | 32 + ui/modal/modalFirstReward/index.js | 19 + ui/modal/modalFirstReward/view.jsx | 38 + ui/modal/modalFirstSubscription/index.js | 17 + ui/modal/modalFirstSubscription/view.jsx | 73 + ui/modal/modalImageUpload/index.js | 11 + ui/modal/modalImageUpload/view.jsx | 31 + ui/modal/modalIncompatibleDaemon/index.js | 12 + ui/modal/modalIncompatibleDaemon/view.jsx | 40 + ui/modal/modalMassTipUnlock/index.js | 15 + ui/modal/modalMassTipUnlock/view.jsx | 74 + ui/modal/modalMobileSearch/index.js | 9 + ui/modal/modalMobileSearch/view.jsx | 18 + ui/modal/modalOpenExternalResource/index.js | 12 + ui/modal/modalOpenExternalResource/view.jsx | 67 + ui/modal/modalPasswordUnsave/index.js | 14 + ui/modal/modalPasswordUnsave/view.jsx | 40 + ui/modal/modalPhoneCollection/index.js | 15 + ui/modal/modalPhoneCollection/view.jsx | 50 + ui/modal/modalPublish/index.js | 17 + ui/modal/modalPublish/view.jsx | 124 + ui/modal/modalPublishPreview/index.js | 39 + ui/modal/modalPublishPreview/view.jsx | 275 + ui/modal/modalRemoveBtcSwapAddress/index.js | 13 + ui/modal/modalRemoveBtcSwapAddress/view.jsx | 43 + ui/modal/modalRemoveCollection/index.js | 29 + ui/modal/modalRemoveCollection/view.jsx | 65 + ui/modal/modalRemoveFile/index.js | 26 + ui/modal/modalRemoveFile/view.jsx | 102 + ui/modal/modalRevokeClaim/index.js | 18 + ui/modal/modalRevokeClaim/view.jsx | 115 + ui/modal/modalRewardCode/index.js | 21 + ui/modal/modalRewardCode/view.jsx | 91 + ui/modal/modalRouter/index.js | 20 + ui/modal/modalRouter/view.jsx | 157 + ui/modal/modalSendTip/index.js | 9 + ui/modal/modalSendTip/view.jsx | 25 + ui/modal/modalSetReferrer/index.js | 18 + ui/modal/modalSetReferrer/view.jsx | 101 + ui/modal/modalSignOut/index.js | 8 + ui/modal/modalSignOut/view.jsx | 47 + ui/modal/modalSocialShare/index.js | 12 + ui/modal/modalSocialShare/view.jsx | 24 + ui/modal/modalSupportsLiquidate/index.js | 14 + ui/modal/modalSupportsLiquidate/view.jsx | 19 + ui/modal/modalSyncEnable/index.js | 11 + ui/modal/modalSyncEnable/view.jsx | 21 + ui/modal/modalTransactionFailed/index.js | 14 + ui/modal/modalTransactionFailed/view.jsx | 21 + ui/modal/modalUpgrade/index.js | 18 + ui/modal/modalUpgrade/view.jsx | 36 + ui/modal/modalViewImage/index.js | 9 + ui/modal/modalViewImage/view.jsx | 21 + ui/modal/modalWalletDecrypt/index.js | 19 + ui/modal/modalWalletDecrypt/view.jsx | 63 + ui/modal/modalWalletEncrypt/index.js | 20 + ui/modal/modalWalletEncrypt/view.jsx | 181 + ui/modal/modalWalletUnlock/index.js | 19 + ui/modal/modalWalletUnlock/view.jsx | 101 + ui/modal/modalYoutubeWelcome/index.js | 14 + ui/modal/modalYoutubeWelcome/view.jsx | 47 + ui/native.js | 19 + ui/page/backup/index.js | 2 + ui/page/backup/view.jsx | 14 + ui/page/buy/index.js | 17 + ui/page/buy/view.jsx | 230 + ui/page/channel/index.js | 40 + ui/page/channel/view.jsx | 288 + ui/page/channelNew/index.js | 20 + ui/page/channelNew/view.jsx | 42 + ui/page/channels/index.js | 22 + ui/page/channels/view.jsx | 126 + ui/page/channelsFollowing/index.js | 13 + ui/page/channelsFollowing/view.jsx | 56 + ui/page/channelsFollowingDiscover/index.js | 15 + ui/page/channelsFollowingDiscover/view.jsx | 139 + ui/page/checkoutPage/credit-card-logos.png | Bin 0 -> 29706 bytes ui/page/checkoutPage/index.js | 2 + ui/page/checkoutPage/view.jsx | 32 + ui/page/collection/index.js | 57 + ui/page/collection/view.jsx | 175 + ui/page/creatorDashboard/index.js | 13 + ui/page/creatorDashboard/view.jsx | 49 + ui/page/discover/index.js | 27 + ui/page/discover/view.jsx | 161 + ui/page/embedWrapper/index.js | 36 + ui/page/embedWrapper/view.jsx | 125 + ui/page/file/index.js | 54 + ui/page/file/view.jsx | 161 + ui/page/fileListDownloaded/index.js | 32 + ui/page/fileListDownloaded/view.jsx | 136 + ui/page/fileListPublished/index.js | 40 + ui/page/fileListPublished/view.jsx | 157 + ui/page/fourOhFour/index.js | 9 + ui/page/fourOhFour/view.jsx | 16 + ui/page/help/index.js | 19 + ui/page/help/view.jsx | 321 + ui/page/home/index.js | 19 + ui/page/home/view.jsx | 112 + ui/page/invite/index.js | 25 + ui/page/invite/view.jsx | 55 + ui/page/invited/index.js | 24 + ui/page/invited/view.jsx | 18 + ui/page/library/index.js | 20 + ui/page/library/view.jsx | 61 + ui/page/listBlocked/index.js | 12 + ui/page/listBlocked/view.jsx | 154 + ui/page/lists/index.js | 31 + ui/page/lists/view.jsx | 22 + ui/page/livestream/index.js | 21 + ui/page/livestream/view.jsx | 126 + ui/page/livestreamCurrent/index.js | 9 + ui/page/livestreamCurrent/view.jsx | 34 + ui/page/livestreamSetup/index.js | 34 + ui/page/livestreamSetup/view.jsx | 321 + ui/page/navigationHistory/index.js | 3 + ui/page/navigationHistory/view.jsx | 13 + ui/page/notifications/index.js | 26 + ui/page/notifications/view.jsx | 151 + ui/page/passwordReset/index.js | 3 + ui/page/passwordReset/view.jsx | 12 + ui/page/passwordSet/index.js | 3 + ui/page/passwordSet/view.jsx | 12 + ui/page/publish/index.js | 12 + ui/page/publish/view.jsx | 48 + ui/page/receive/index.js | 6 + ui/page/receive/view.jsx | 26 + ui/page/report/index.js | 3 + ui/page/report/view.jsx | 134 + ui/page/reportContent/index.js | 8 + ui/page/reportContent/view.jsx | 19 + ui/page/repost/index.js | 15 + ui/page/repost/view.jsx | 77 + ui/page/rewards/index.js | 22 + ui/page/rewards/view.jsx | 181 + ui/page/rewardsVerify/index.js | 9 + ui/page/rewardsVerify/view.jsx | 29 + ui/page/search/index.js | 49 + ui/page/search/view.jsx | 132 + ui/page/send/index.js | 6 + ui/page/send/view.jsx | 139 + ui/page/settings/index.js | 58 + ui/page/settings/view.jsx | 531 + ui/page/settingsAdvanced/index.js | 51 + ui/page/settingsAdvanced/view.jsx | 524 + ui/page/settingsCreator/index.js | 30 + ui/page/settingsCreator/view.jsx | 242 + ui/page/settingsNotifications/index.js | 16 + ui/page/settingsNotifications/view.jsx | 183 + ui/page/show/index.js | 99 + ui/page/show/view.jsx | 197 + ui/page/signIn/index.js | 3 + ui/page/signIn/view.jsx | 12 + ui/page/signInVerify/index.js | 10 + ui/page/signInVerify/view.jsx | 139 + ui/page/signInWalletPassword/index.js | 10 + ui/page/signInWalletPassword/view.jsx | 11 + ui/page/signUp/index.js | 3 + ui/page/signUp/view.jsx | 12 + ui/page/swap/index.js | 6 + ui/page/swap/view.jsx | 21 + ui/page/tagsFollowing/index.js | 18 + ui/page/tagsFollowing/view.jsx | 44 + ui/page/tagsFollowingManage/index.js | 12 + ui/page/tagsFollowingManage/view.jsx | 14 + ui/page/top/index.js | 26 + ui/page/top/view.jsx | 82 + ui/page/wallet/index.js | 12 + ui/page/wallet/view.jsx | 45 + ui/page/welcome/index.js | 10 + ui/page/welcome/view.jsx | 12 + ui/page/youtubeSync/index.js | 12 + ui/page/youtubeSync/view.jsx | 216 + ui/reducers.js | 52 + ui/redux/actions/app.js | 750 + ui/redux/actions/blocked.js | 20 + ui/redux/actions/coinSwap.js | 44 + ui/redux/actions/comments.js | 945 ++ ui/redux/actions/content.js | 263 + ui/redux/actions/file.js | 88 + ui/redux/actions/livestream.js | 33 + ui/redux/actions/notifications.js | 186 + ui/redux/actions/publish.js | 116 + ui/redux/actions/reactions.js | 70 + ui/redux/actions/reportContent.js | 61 + ui/redux/actions/rewards.js | 177 + ui/redux/actions/search.js | 145 + ui/redux/actions/settings.js | 426 + ui/redux/actions/subscriptions.js | 69 + ui/redux/actions/sync.js | 363 + ui/redux/actions/tags.js | 42 + ui/redux/actions/user.js | 829 ++ ui/redux/actions/websocket.js | 112 + ui/redux/reducers/app.js | 342 + ui/redux/reducers/blocked.js | 40 + ui/redux/reducers/coinSwap.js | 156 + ui/redux/reducers/comments.js | 504 + ui/redux/reducers/content.js | 109 + ui/redux/reducers/livestream.js | 34 + ui/redux/reducers/notifications.js | 158 + ui/redux/reducers/reactions.js | 55 + ui/redux/reducers/reportContent.js | 29 + ui/redux/reducers/rewards.js | 112 + ui/redux/reducers/search.js | 67 + ui/redux/reducers/settings.js | 186 + ui/redux/reducers/subscriptions.js | 133 + ui/redux/reducers/sync.js | 118 + ui/redux/reducers/tags.js | 79 + ui/redux/reducers/user.js | 381 + ui/redux/selectors/app.js | 136 + ui/redux/selectors/blocked.js | 13 + ui/redux/selectors/coinSwap.js | 8 + ui/redux/selectors/comments.js | 332 + ui/redux/selectors/content.js | 245 + ui/redux/selectors/file_info.js | 85 + ui/redux/selectors/livestream.js | 38 + ui/redux/selectors/notifications.js | 55 + ui/redux/selectors/publish.js | 81 + ui/redux/selectors/reactions.js | 76 + ui/redux/selectors/reportContent.js | 13 + ui/redux/selectors/rewards.js | 63 + ui/redux/selectors/search.js | 193 + ui/redux/selectors/settings.js | 77 + ui/redux/selectors/subscriptions.js | 164 + ui/redux/selectors/sync.js | 31 + ui/redux/selectors/tags.js | 36 + ui/redux/selectors/user.js | 137 + ui/rewards.js | 126 + ui/scss/all.scss | 66 + ui/scss/component/_ads.scss | 133 + ui/scss/component/_animation.scss | 91 + ui/scss/component/_badge.scss | 39 + ui/scss/component/_button.scss | 644 + ui/scss/component/_card.scss | 409 + ui/scss/component/_channel.scss | 425 + ui/scss/component/_claim-list.scss | 777 + ui/scss/component/_claim-search.scss | 111 + ui/scss/component/_collection.scss | 133 + ui/scss/component/_comments.scss | 437 + ui/scss/component/_content.scss | 196 + ui/scss/component/_dat-gui.scss | 28 + ui/scss/component/_embed-player.scss | 62 + ui/scss/component/_empty.scss | 25 + ui/scss/component/_expandable.scss | 15 + ui/scss/component/_file-drop.scss | 39 + ui/scss/component/_file-list.scss | 6 + ui/scss/component/_file-properties.scss | 41 + ui/scss/component/_file-render.scss | 718 + ui/scss/component/_footer.scss | 68 + ui/scss/component/_form-field.scss | 713 + ui/scss/component/_form-row.scss | 51 + ui/scss/component/_header.scss | 207 + ui/scss/component/_icon.scss | 86 + ui/scss/component/_item-list.scss | 35 + ui/scss/component/_livestream.scss | 417 + ui/scss/component/_main.scss | 393 + ui/scss/component/_markdown-editor.scss | 118 + ui/scss/component/_markdown-preview.scss | 267 + ui/scss/component/_media.scss | 140 + ui/scss/component/_modal.scss | 94 + ui/scss/component/_navigation.scss | 277 + ui/scss/component/_notification.scss | 237 + ui/scss/component/_nudge.scss | 43 + ui/scss/component/_pagination.scss | 79 + ui/scss/component/_placeholder.scss | 40 + ui/scss/component/_post.scss | 112 + ui/scss/component/_progress.scss | 17 + ui/scss/component/_purchase.scss | 276 + ui/scss/component/_search.scss | 137 + ui/scss/component/_share.scss | 12 + ui/scss/component/_snack-bar.scss | 64 + ui/scss/component/_spinner.scss | 54 + ui/scss/component/_splash.scss | 51 + ui/scss/component/_status-bar.scss | 23 + ui/scss/component/_superchat.scss | 20 + ui/scss/component/_syntax-highlighter.scss | 337 + ui/scss/component/_table.scss | 277 + ui/scss/component/_tags.scss | 87 + ui/scss/component/_tooltip.scss | 8 + ui/scss/component/_txo-list.scss | 12 + ui/scss/component/_videojs.scss | 152 + ui/scss/component/_wunderbar.scss | 290 + ui/scss/component/_yrbl.scss | 92 + ui/scss/component/expanding-details.scss | 15 + ui/scss/component/menu-button.scss | 143 + ui/scss/component/nag.scss | 108 + ui/scss/component/section.scss | 205 + ui/scss/component/tabs.scss | 72 + ui/scss/init/_base-theme.scss | 199 + ui/scss/init/_color.scss | 57 + ui/scss/init/_gui.scss | 501 + ui/scss/init/_mixins.scss | 237 + ui/scss/init/_reset.scss | 245 + ui/scss/init/_vars.scss | 108 + ui/scss/themes/dark.scss | 159 + ui/scss/themes/light.scss | 159 + ui/store.js | 223 + ui/util/autoLaunch.js | 8 + ui/util/comments.js | 93 + ui/util/context-menu.js | 148 + ui/util/country.js | 18 + ui/util/debounce.js | 21 + ui/util/deep-equal.js | 117 + ui/util/default-languages.js | 30 + ui/util/detect-typing.js | 13 + ui/util/enhanced-layout.js | 156 + ui/util/fetch.js | 17 + ui/util/form-validation.js | 16 + ui/util/format-bytes.js | 12 + ui/util/full-screen.js | 49 + ui/util/generate-thumbnail-name.js | 7 + ui/util/handle-fetch.js | 4 + ui/util/hex.js | 10 + ui/util/number.js | 5 + ui/util/object.js | 3 + ui/util/parse-data.js | 61 + ui/util/publish.js | 21 + ui/util/query-params.js | 104 + ui/util/redux-utils.js | 16 + ui/util/remark-lbry.js | 150 + ui/util/remark-timestamp.js | 152 + ui/util/saved-passwords.js | 154 + ui/util/search.js | 35 + ui/util/set-operations.js | 15 + ui/util/shuffle-array.js | 3 + ui/util/string.js | 5 + ui/util/swap-json.js | 9 + ui/util/sync-settings.js | 26 + ui/util/throttle.js | 65 + ui/util/thumbnail.js | 29 + ui/util/time.js | 34 + ui/util/url.js | 133 + ui/util/web-file-system.js | 73 + ui/util/web.js | 31 + ui/util/zoomWindow.js | 54 + web/bundle-id.js | 8 + web/component/ads/index.js | 11 + web/component/ads/view.jsx | 240 + .../fileViewerEmbeddedEnded/index.js | 7 + .../fileViewerEmbeddedEnded/view.jsx | 57 + web/component/footer.jsx | 102 + web/component/nag-data-collection.jsx | 54 + web/component/nag-degraded-performance.jsx | 34 + web/component/openInAppLink/index.js | 9 + web/component/openInAppLink/view.jsx | 100 + web/component/youtubeReferralWelcome/index.js | 12 + web/component/youtubeReferralWelcome/view.jsx | 24 + web/effects/use-degraded-performance.js | 45 + web/index.js | 39 + web/middleware/cache-control.js | 33 + web/middleware/iframe-destroyer.js | 16 + web/middleware/redirect.js | 67 + web/package.json | 61 + web/page/code2257/index.js | 2 + web/page/code2257/view.jsx | 47 + web/setup/publish.js | 104 + web/src/category-metadata.js | 66 + web/src/chainquery.js | 66 + web/src/html.js | 325 + web/src/robots.js | 12 + web/src/routes.js | 57 + web/src/rss.js | 96 + web/src/xml.js | 18 + web/static/pwa/icon-180.png | Bin 0 -> 12574 bytes web/static/pwa/icon-192.png | Bin 0 -> 17186 bytes web/static/pwa/icon-512.png | Bin 0 -> 61476 bytes web/static/pwa/icon.png | Bin 0 -> 24241 bytes web/static/pwa/manifest.json | 28 + web/static/pwa/serviceWorker.js | 14 + web/stubs/electron.js | 43 + web/stubs/fs.js | 17 + web/webpack.config.js | 162 + web/yarn.lock | 5726 +++++++ webpack.base.config.js | 113 + webpack.electron.config.js | 138 + yarn.lock | 12336 ++++++++++++++++ 1163 files changed, 140572 insertions(+) create mode 100644 .env.defaults create mode 100644 .eslintignore create mode 100644 .eslintrc create mode 100644 .flowconfig create mode 100644 .gitignore create mode 100644 .lintstagedrc.json create mode 100644 .prettierrc.json create mode 100644 .sentryclirc create mode 100644 .tx/config create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 add create mode 100644 babel.config.js create mode 100644 build/afterAllArtifactBuild.js create mode 100644 build/afterSignHook.js create mode 100644 build/background.png create mode 100644 build/downloadDaemon.js create mode 100644 build/downloadLBRYFirst.js create mode 100644 build/icon.icns create mode 100644 build/icon.ico create mode 100644 build/icons/128x128.png create mode 100644 build/icons/256x256.png create mode 100644 build/icons/32x32.png create mode 100644 build/icons/48x48.png create mode 100644 build/icons/96x96.png create mode 100644 build/icons/lbry128.ico create mode 100644 build/icons/lbry16.ico create mode 100644 build/icons/lbry256.ico create mode 100644 build/icons/lbry32.ico create mode 100644 build/icons/lbry48.ico create mode 100644 build/icons/lbry96.ico create mode 100644 build/signBuildFiles.js create mode 100644 config.js create mode 100644 custom/homepage.example.js create mode 100644 custom/homepages/.gitkeep create mode 100644 custom/robots.allowall create mode 100644 custom/robots.disallowall create mode 100644 electron-builder.json create mode 100644 electron/Daemon.js create mode 100644 electron/LbryFirstInstance.js create mode 100644 electron/createTray.js create mode 100644 electron/createWindow.js create mode 100644 electron/devServer.js create mode 100644 electron/index.js create mode 100644 electron/installDevtools.js create mode 100644 electron/menu/setupBarMenu.js create mode 100644 electron/sandboxTest.js create mode 100644 electron/startSandbox.js create mode 100644 electron/unpackByOutpoint.js create mode 100644 flow-typed/18nj.js create mode 100644 flow-typed/Comment.js create mode 100644 flow-typed/bluebird.js create mode 100644 flow-typed/classnames.js create mode 100644 flow-typed/content.js create mode 100644 flow-typed/electron.js create mode 100644 flow-typed/formik.js create mode 100644 flow-typed/homepage.js create mode 100644 flow-typed/livestream.js create mode 100644 flow-typed/location.js create mode 100644 flow-typed/notification.js create mode 100644 flow-typed/npm/@babel/core_vx.x.x.js create mode 100644 flow-typed/npm/@babel/plugin-proposal-class-properties_vx.x.x.js create mode 100644 flow-typed/npm/@babel/plugin-proposal-decorators_vx.x.x.js create mode 100644 flow-typed/npm/@babel/plugin-transform-flow-strip-types_vx.x.x.js create mode 100644 flow-typed/npm/@babel/polyfill_v7.x.x.js create mode 100644 flow-typed/npm/@babel/preset-flow_vx.x.x.js create mode 100644 flow-typed/npm/@babel/preset-react_vx.x.x.js create mode 100644 flow-typed/npm/@babel/register_v7.x.x.js create mode 100644 flow-typed/npm/@hot-loader/react-dom_vx.x.x.js create mode 100644 flow-typed/npm/@lbry/color_vx.x.x.js create mode 100644 flow-typed/npm/@lbry/components_vx.x.x.js create mode 100644 flow-typed/npm/@types/three_vx.x.x.js create mode 100644 flow-typed/npm/async-exit-hook_vx.x.x.js create mode 100644 flow-typed/npm/babel-eslint_vx.x.x.js create mode 100644 flow-typed/npm/babel-loader_vx.x.x.js create mode 100644 flow-typed/npm/babel-plugin-add-module-exports_vx.x.x.js create mode 100644 flow-typed/npm/babel-plugin-transform-imports_vx.x.x.js create mode 100644 flow-typed/npm/bluebird_v3.x.x.js create mode 100644 flow-typed/npm/chalk_v2.x.x.js create mode 100644 flow-typed/npm/classnames_v2.x.x.js create mode 100644 flow-typed/npm/codemirror_vx.x.x.js create mode 100644 flow-typed/npm/copy-webpack-plugin_vx.x.x.js create mode 100644 flow-typed/npm/country-data_vx.x.x.js create mode 100644 flow-typed/npm/cross-env_vx.x.x.js create mode 100644 flow-typed/npm/css-loader_vx.x.x.js create mode 100644 flow-typed/npm/dat.gui_vx.x.x.js create mode 100644 flow-typed/npm/decompress_vx.x.x.js create mode 100644 flow-typed/npm/del_v3.x.x.js create mode 100644 flow-typed/npm/devtron_vx.x.x.js create mode 100644 flow-typed/npm/dom-scroll-into-view_vx.x.x.js create mode 100644 flow-typed/npm/electron-builder_vx.x.x.js create mode 100644 flow-typed/npm/electron-devtools-installer_vx.x.x.js create mode 100644 flow-typed/npm/electron-dl_vx.x.x.js create mode 100644 flow-typed/npm/electron-is-dev_vx.x.x.js create mode 100644 flow-typed/npm/electron-log_vx.x.x.js create mode 100644 flow-typed/npm/electron-publisher-s3_vx.x.x.js create mode 100644 flow-typed/npm/electron-updater_vx.x.x.js create mode 100644 flow-typed/npm/electron-webpack_vx.x.x.js create mode 100644 flow-typed/npm/electron-window-state_vx.x.x.js create mode 100644 flow-typed/npm/electron_vx.x.x.js create mode 100644 flow-typed/npm/eslint-config-airbnb_vx.x.x.js create mode 100644 flow-typed/npm/eslint-config-prettier_vx.x.x.js create mode 100644 flow-typed/npm/eslint-config-standard-jsx_vx.x.x.js create mode 100644 flow-typed/npm/eslint-config-standard_vx.x.x.js create mode 100644 flow-typed/npm/eslint-import-resolver-webpack_vx.x.x.js create mode 100644 flow-typed/npm/eslint-plugin-flowtype_vx.x.x.js create mode 100644 flow-typed/npm/eslint-plugin-import_vx.x.x.js create mode 100644 flow-typed/npm/eslint-plugin-jsx-a11y_vx.x.x.js create mode 100644 flow-typed/npm/eslint-plugin-node_vx.x.x.js create mode 100644 flow-typed/npm/eslint-plugin-prettier_vx.x.x.js create mode 100644 flow-typed/npm/eslint-plugin-promise_vx.x.x.js create mode 100644 flow-typed/npm/eslint-plugin-react_vx.x.x.js create mode 100644 flow-typed/npm/eslint-plugin-standard_vx.x.x.js create mode 100644 flow-typed/npm/eslint_vx.x.x.js create mode 100644 flow-typed/npm/express_v4.16.x.js create mode 100644 flow-typed/npm/flow-bin_v0.x.x.js create mode 100644 flow-typed/npm/flow-typed_vx.x.x.js create mode 100644 flow-typed/npm/formik_vx.x.x.js create mode 100644 flow-typed/npm/hast-util-sanitize_vx.x.x.js create mode 100644 flow-typed/npm/husky_vx.x.x.js create mode 100644 flow-typed/npm/json-loader_vx.x.x.js create mode 100644 flow-typed/npm/lbry-format_vx.x.x.js create mode 100644 flow-typed/npm/lbry-redux_vx.x.x.js create mode 100644 flow-typed/npm/lbryinc_vx.x.x.js create mode 100644 flow-typed/npm/lint-staged_vx.x.x.js create mode 100644 flow-typed/npm/localforage_v1.5.x.js create mode 100644 flow-typed/npm/make-runnable_vx.x.x.js create mode 100644 flow-typed/npm/mammoth_vx.x.x.js create mode 100644 flow-typed/npm/mixpanel-browser_v2.11.x.js create mode 100644 flow-typed/npm/moment_v2.x.x.js create mode 100644 flow-typed/npm/node-abi_vx.x.x.js create mode 100644 flow-typed/npm/node-fetch_vx.x.x.js create mode 100644 flow-typed/npm/node-libs-browser_vx.x.x.js create mode 100644 flow-typed/npm/node-loader_vx.x.x.js create mode 100644 flow-typed/npm/preprocess-loader_vx.x.x.js create mode 100644 flow-typed/npm/prettier_v1.x.x.js create mode 100644 flow-typed/npm/prop-types_v15.x.x.js create mode 100644 flow-typed/npm/qrcode.react_vx.x.x.js create mode 100644 flow-typed/npm/raw-loader_vx.x.x.js create mode 100644 flow-typed/npm/rc-progress_vx.x.x.js create mode 100644 flow-typed/npm/react-hot-loader_v4.6.x.js create mode 100644 flow-typed/npm/react-modal_v3.1.x.js create mode 100644 flow-typed/npm/react-paginate_vx.x.x.js create mode 100644 flow-typed/npm/react-redux_v5.x.x.js create mode 100644 flow-typed/npm/react-simplemde-editor_vx.x.x.js create mode 100644 flow-typed/npm/react-toggle_v4.0.x.js create mode 100644 flow-typed/npm/redux-persist-transform-compress_vx.x.x.js create mode 100644 flow-typed/npm/redux-persist-transform-filter_vx.x.x.js create mode 100644 flow-typed/npm/redux-thunk_vx.x.x.js create mode 100644 flow-typed/npm/remark-emoji_vx.x.x.js create mode 100644 flow-typed/npm/remark-react_vx.x.x.js create mode 100644 flow-typed/npm/remark_vx.x.x.js create mode 100644 flow-typed/npm/render-media_vx.x.x.js create mode 100644 flow-typed/npm/reselect_v3.x.x.js create mode 100644 flow-typed/npm/sass-loader_vx.x.x.js create mode 100644 flow-typed/npm/semver_v5.1.x.js create mode 100644 flow-typed/npm/stream-to-blob-url_vx.x.x.js create mode 100644 flow-typed/npm/style-loader_vx.x.x.js create mode 100644 flow-typed/npm/three-full_vx.x.x.js create mode 100644 flow-typed/npm/three_vx.x.x.js create mode 100644 flow-typed/npm/tree-kill_vx.x.x.js create mode 100644 flow-typed/npm/video.js_vx.x.x.js create mode 100644 flow-typed/npm/webpack-config-utils_vx.x.x.js create mode 100644 flow-typed/npm/webpack-dev-middleware_vx.x.x.js create mode 100644 flow-typed/npm/webpack-dev-server_vx.x.x.js create mode 100644 flow-typed/npm/webpack-hot-middleware_vx.x.x.js create mode 100644 flow-typed/npm/webpack-merge_vx.x.x.js create mode 100644 flow-typed/npm/webpack-node-externals_vx.x.x.js create mode 100644 flow-typed/npm/webpack_v4.x.x.js create mode 100644 flow-typed/npm/y18n_vx.x.x.js create mode 100644 flow-typed/npm/yarnhook_vx.x.x.js create mode 100644 flow-typed/publish.js create mode 100644 flow-typed/qrcode.react.js create mode 100644 flow-typed/react-markdown.js create mode 100644 flow-typed/react-modal.js create mode 100644 flow-typed/react-paginate.js create mode 100644 flow-typed/react-simplemde-editor.js create mode 100644 flow-typed/react-transition-group.js create mode 100644 flow-typed/redux.js create mode 100644 flow-typed/reportContent.js create mode 100644 flow-typed/reselect.js create mode 100644 flow-typed/reward.js create mode 100644 flow-typed/search.js create mode 100644 flow-typed/shapeshift.io.js create mode 100644 flow-typed/subscription.js create mode 100644 flow-typed/user.js create mode 100644 flow-typed/web-file.js create mode 100644 flow-typed/web.js create mode 100644 homepages/homepage.js create mode 100644 homepages/index.js create mode 100644 package.json create mode 100644 postcss.config.js create mode 100644 static/app-strings.json create mode 100644 static/font/v1/300.woff create mode 100644 static/font/v1/300i.woff create mode 100644 static/font/v1/400.woff create mode 100644 static/font/v1/400i.woff create mode 100644 static/font/v1/700.woff create mode 100644 static/font/v1/700i.woff create mode 100644 static/img/busy.gif create mode 100644 static/img/favicon.png create mode 100644 static/img/tray/default/tray.png create mode 100644 static/img/tray/mac/trayTemplate.png create mode 100644 static/img/tray/mac/trayTemplate@2x copy.png create mode 100644 static/img/tray/mac/trayTemplate@2x.png create mode 100644 static/img/tray/windows/tray.ico create mode 100644 static/img/unlocklbry.svg create mode 100644 static/img/v2-og.png create mode 100644 static/index-electron.html create mode 100644 static/index-web.html create mode 100644 static/opensearch.xml create mode 100644 static/robots.txt create mode 100644 static/webworkers/wasm-gen/libarchive.js create mode 100644 static/webworkers/wasm-gen/libarchive.wasm create mode 100644 static/webworkers/worker-bundle.js create mode 100644 ui/analytics.js create mode 100644 ui/app.js create mode 100644 ui/comments.js create mode 100644 ui/component/IframeReact/index.js create mode 100644 ui/component/IframeReact/view.jsx create mode 100644 ui/component/abandonedChannelPreview/index.js create mode 100644 ui/component/abandonedChannelPreview/view.jsx create mode 100644 ui/component/app/index.js create mode 100644 ui/component/app/view.jsx create mode 100644 ui/component/autoplayCountdown/index.js create mode 100644 ui/component/autoplayCountdown/view.jsx create mode 100644 ui/component/button/index.js create mode 100644 ui/component/button/view.jsx create mode 100644 ui/component/cardVerify/index.js create mode 100644 ui/component/cardVerify/view.jsx create mode 100644 ui/component/channelAbout/index.js create mode 100644 ui/component/channelAbout/view.jsx create mode 100644 ui/component/channelBlockButton/index.js create mode 100644 ui/component/channelBlockButton/view.jsx create mode 100644 ui/component/channelContent/index.js create mode 100644 ui/component/channelContent/view.jsx create mode 100644 ui/component/channelDiscussion/index.js create mode 100644 ui/component/channelDiscussion/view.jsx create mode 100644 ui/component/channelEdit/index.js create mode 100644 ui/component/channelEdit/view.jsx create mode 100644 ui/component/channelMuteButton/index.js create mode 100644 ui/component/channelMuteButton/view.jsx create mode 100644 ui/component/channelSelector/index.js create mode 100644 ui/component/channelSelector/view.jsx create mode 100644 ui/component/channelStakedIndicator/index.js create mode 100644 ui/component/channelStakedIndicator/view.jsx create mode 100644 ui/component/channelThumbnail/gerbil.png create mode 100644 ui/component/channelThumbnail/index.js create mode 100644 ui/component/channelThumbnail/transparent_1x1.png create mode 100644 ui/component/channelThumbnail/view.jsx create mode 100644 ui/component/channelTitle/index.js create mode 100644 ui/component/channelTitle/view.jsx create mode 100644 ui/component/claimAbandonButton/index.js create mode 100644 ui/component/claimAbandonButton/view.jsx create mode 100644 ui/component/claimAuthor/index.js create mode 100644 ui/component/claimAuthor/view.jsx create mode 100644 ui/component/claimCollectionAdd/index.js create mode 100644 ui/component/claimCollectionAdd/view.jsx create mode 100644 ui/component/claimCollectionAddButton/index.js create mode 100644 ui/component/claimCollectionAddButton/view.jsx create mode 100644 ui/component/claimEffectiveAmount/index.js create mode 100644 ui/component/claimEffectiveAmount/view.jsx create mode 100644 ui/component/claimInsufficientCredits/index.js create mode 100644 ui/component/claimInsufficientCredits/view.jsx create mode 100644 ui/component/claimLink/index.js create mode 100644 ui/component/claimLink/view.jsx create mode 100644 ui/component/claimList/index.js create mode 100644 ui/component/claimList/view.jsx create mode 100644 ui/component/claimListDiscover/index.js create mode 100644 ui/component/claimListDiscover/view.jsx create mode 100644 ui/component/claimListHeader/index.js create mode 100644 ui/component/claimListHeader/view.jsx create mode 100644 ui/component/claimMenuList/index.js create mode 100644 ui/component/claimMenuList/view.jsx create mode 100644 ui/component/claimPreview/claim-preview-loading.jsx create mode 100644 ui/component/claimPreview/claim-preview-no-content.jsx create mode 100644 ui/component/claimPreview/claim-preview-no-mature.jsx create mode 100644 ui/component/claimPreview/index.js create mode 100644 ui/component/claimPreview/view.jsx create mode 100644 ui/component/claimPreviewSubtitle/index.js create mode 100644 ui/component/claimPreviewSubtitle/view.jsx create mode 100644 ui/component/claimPreviewTile/index.js create mode 100644 ui/component/claimPreviewTile/view.jsx create mode 100644 ui/component/claimPreviewTitle/index.js create mode 100644 ui/component/claimPreviewTitle/view.jsx create mode 100644 ui/component/claimProperties/index.js create mode 100644 ui/component/claimProperties/view.jsx create mode 100644 ui/component/claimRepostAuthor/index.js create mode 100644 ui/component/claimRepostAuthor/view.jsx create mode 100644 ui/component/claimSupportButton/index.js create mode 100644 ui/component/claimSupportButton/view.jsx create mode 100644 ui/component/claimTags/index.js create mode 100644 ui/component/claimTags/view.jsx create mode 100644 ui/component/claimTilesDiscover/index.js create mode 100644 ui/component/claimTilesDiscover/view.jsx create mode 100644 ui/component/claimType/index.js create mode 100644 ui/component/claimType/view.jsx create mode 100644 ui/component/claimUri/index.js create mode 100644 ui/component/claimUri/view.jsx create mode 100644 ui/component/collectionActions/index.js create mode 100644 ui/component/collectionActions/view.jsx create mode 100644 ui/component/collectionContentSidebar/index.js create mode 100644 ui/component/collectionContentSidebar/view.jsx create mode 100644 ui/component/collectionEdit/index.js create mode 100644 ui/component/collectionEdit/view.jsx create mode 100644 ui/component/collectionMenuList/index.js create mode 100644 ui/component/collectionMenuList/view.jsx create mode 100644 ui/component/collectionPreviewOverlay/index.js create mode 100644 ui/component/collectionPreviewOverlay/view.jsx create mode 100644 ui/component/collectionPreviewTile/collectionCount.jsx create mode 100644 ui/component/collectionPreviewTile/collectionPrivate.jsx create mode 100644 ui/component/collectionPreviewTile/index.js create mode 100644 ui/component/collectionPreviewTile/view.jsx create mode 100644 ui/component/collectionSelectItem/index.js create mode 100644 ui/component/collectionSelectItem/view.jsx create mode 100644 ui/component/collectionsListMine/index.js create mode 100644 ui/component/collectionsListMine/view.jsx create mode 100644 ui/component/comment/index.js create mode 100644 ui/component/comment/view.jsx create mode 100644 ui/component/commentCreate/index.js create mode 100644 ui/component/commentCreate/view.jsx create mode 100644 ui/component/commentMenuList/index.js create mode 100644 ui/component/commentMenuList/view.jsx create mode 100644 ui/component/commentReactions/index.js create mode 100644 ui/component/commentReactions/view.jsx create mode 100644 ui/component/commentsList/index.js create mode 100644 ui/component/commentsList/view.jsx create mode 100644 ui/component/commentsReplies/index.js create mode 100644 ui/component/commentsReplies/view.jsx create mode 100644 ui/component/common/busy-indicator.jsx create mode 100644 ui/component/common/card.jsx create mode 100644 ui/component/common/credit-amount.jsx create mode 100644 ui/component/common/empty.jsx create mode 100644 ui/component/common/error-text.jsx create mode 100644 ui/component/common/file-exporter.jsx create mode 100644 ui/component/common/file-list.jsx create mode 100644 ui/component/common/file-selector.jsx create mode 100644 ui/component/common/form-components/form-field-price.jsx create mode 100644 ui/component/common/form-components/form-field.jsx create mode 100644 ui/component/common/form-components/form-row.jsx create mode 100644 ui/component/common/form-components/form.jsx create mode 100644 ui/component/common/form-components/submit.jsx create mode 100644 ui/component/common/form.jsx create mode 100644 ui/component/common/help-link.jsx create mode 100644 ui/component/common/hidden-nsfw.jsx create mode 100644 ui/component/common/icon-custom.jsx create mode 100644 ui/component/common/icon.jsx create mode 100644 ui/component/common/lbc-message.jsx create mode 100644 ui/component/common/lbc-symbol.jsx create mode 100644 ui/component/common/loading-screen.jsx create mode 100644 ui/component/common/markdown-preview.jsx create mode 100644 ui/component/common/nag.jsx create mode 100644 ui/component/common/paginate.jsx create mode 100644 ui/component/common/qr-code.jsx create mode 100644 ui/component/common/status-bar.jsx create mode 100644 ui/component/common/tabs.jsx create mode 100644 ui/component/common/thumbnail.jsx create mode 100644 ui/component/common/tooltip.jsx create mode 100644 ui/component/common/transaction-link.jsx create mode 100644 ui/component/common/truncated-text.jsx create mode 100644 ui/component/common/wait-until-on-page.jsx create mode 100644 ui/component/copyableText/index.js create mode 100644 ui/component/copyableText/view.jsx create mode 100644 ui/component/creatorAnalytics/index.js create mode 100644 ui/component/creatorAnalytics/view.jsx create mode 100644 ui/component/dateTime/index.js create mode 100644 ui/component/dateTime/view.jsx create mode 100644 ui/component/emailCollection/index.js create mode 100644 ui/component/emailCollection/view.jsx create mode 100644 ui/component/embedPlayButton/index.js create mode 100644 ui/component/embedPlayButton/view.jsx create mode 100644 ui/component/embedTextArea/index.js create mode 100644 ui/component/embedTextArea/view.jsx create mode 100644 ui/component/errorBoundary/index.js create mode 100644 ui/component/errorBoundary/view.jsx create mode 100644 ui/component/expandable/index.js create mode 100644 ui/component/expandable/view.jsx create mode 100644 ui/component/fileActions/index.js create mode 100644 ui/component/fileActions/view.jsx create mode 100644 ui/component/fileDescription/index.js create mode 100644 ui/component/fileDescription/view.jsx create mode 100644 ui/component/fileDetails/index.js create mode 100644 ui/component/fileDetails/view.jsx create mode 100644 ui/component/fileDownloadLink/index.js create mode 100644 ui/component/fileDownloadLink/view.jsx create mode 100644 ui/component/fileDrop/index.js create mode 100644 ui/component/fileDrop/view.jsx create mode 100644 ui/component/filePrice/index.js create mode 100644 ui/component/filePrice/view.jsx create mode 100644 ui/component/fileReactions/index.js create mode 100644 ui/component/fileReactions/view.jsx create mode 100644 ui/component/fileRender/index.js create mode 100644 ui/component/fileRender/view.jsx create mode 100644 ui/component/fileRenderDownload/index.js create mode 100644 ui/component/fileRenderDownload/view.jsx create mode 100644 ui/component/fileRenderFloating/index.js create mode 100644 ui/component/fileRenderFloating/view.jsx create mode 100644 ui/component/fileRenderInitiator/index.js create mode 100644 ui/component/fileRenderInitiator/view.jsx create mode 100644 ui/component/fileRenderInline/index.js create mode 100644 ui/component/fileRenderInline/view.jsx create mode 100644 ui/component/fileSubtitle/index.js create mode 100644 ui/component/fileSubtitle/view.jsx create mode 100644 ui/component/fileThumbnail/FreezeframeLite/classes.js create mode 100644 ui/component/fileThumbnail/FreezeframeLite/index.js create mode 100644 ui/component/fileThumbnail/FreezeframeLite/styles.scss create mode 100644 ui/component/fileThumbnail/FreezeframeLite/templates.js create mode 100644 ui/component/fileThumbnail/FreezeframeLite/utils.js create mode 100644 ui/component/fileThumbnail/FreezeframeWrapper.jsx create mode 100644 ui/component/fileThumbnail/index.js create mode 100644 ui/component/fileThumbnail/placeholder.png create mode 100644 ui/component/fileThumbnail/view.jsx create mode 100644 ui/component/fileTitle/index.js create mode 100644 ui/component/fileTitle/view.jsx create mode 100644 ui/component/fileTitleSection/index.js create mode 100644 ui/component/fileTitleSection/view.jsx create mode 100644 ui/component/fileType/index.js create mode 100644 ui/component/fileType/view.jsx create mode 100644 ui/component/fileValues/index.js create mode 100644 ui/component/fileValues/view.jsx create mode 100644 ui/component/fileViewCount/index.js create mode 100644 ui/component/fileViewCount/view.jsx create mode 100644 ui/component/fileViewerEmbeddedTitle/index.js create mode 100644 ui/component/fileViewerEmbeddedTitle/view.jsx create mode 100644 ui/component/formFieldPrice/index.js create mode 100644 ui/component/formFieldPrice/view.jsx create mode 100644 ui/component/header/index.js create mode 100644 ui/component/header/odysee.png create mode 100644 ui/component/header/odysee_logo.png create mode 100644 ui/component/header/odysee_white.png create mode 100644 ui/component/header/view.jsx create mode 100644 ui/component/hiddenNsfwClaims/index.js create mode 100644 ui/component/hiddenNsfwClaims/view.jsx create mode 100644 ui/component/homepageSelector/index.js create mode 100644 ui/component/homepageSelector/view.jsx create mode 100644 ui/component/i18nMessage/index.js create mode 100644 ui/component/i18nMessage/view.jsx create mode 100644 ui/component/inviteList/index.js create mode 100644 ui/component/inviteList/view.jsx create mode 100644 ui/component/inviteNew/index.js create mode 100644 ui/component/inviteNew/view.jsx create mode 100644 ui/component/invited/index.js create mode 100644 ui/component/invited/view.jsx create mode 100644 ui/component/lastReleaseChanges/index.js create mode 100644 ui/component/lastReleaseChanges/view.jsx create mode 100644 ui/component/livestreamComment/index.js create mode 100644 ui/component/livestreamComment/view.jsx create mode 100644 ui/component/livestreamComments/index.js create mode 100644 ui/component/livestreamComments/view.jsx create mode 100644 ui/component/livestreamLayout/index.js create mode 100644 ui/component/livestreamLayout/view.jsx create mode 100644 ui/component/livestreamLink/index.js create mode 100644 ui/component/livestreamLink/view.jsx create mode 100644 ui/component/livestreamList/index.js create mode 100644 ui/component/livestreamList/view.jsx create mode 100644 ui/component/loginGraphic/index.jsx create mode 100644 ui/component/markdownLink/index.js create mode 100644 ui/component/markdownLink/view.jsx create mode 100644 ui/component/nagContinueFirstRun/index.js create mode 100644 ui/component/nagContinueFirstRun/view.jsx create mode 100644 ui/component/navigationButton/index.js create mode 100644 ui/component/navigationButton/view.jsx create mode 100644 ui/component/navigationHistory/index.js create mode 100644 ui/component/navigationHistory/view.jsx create mode 100644 ui/component/navigationHistoryItem/index.js create mode 100644 ui/component/navigationHistoryItem/view.jsx create mode 100644 ui/component/navigationHistoryRecent/index.js create mode 100644 ui/component/navigationHistoryRecent/view.jsx create mode 100644 ui/component/notification/index.js create mode 100644 ui/component/notification/view.jsx create mode 100644 ui/component/notificationBubble/index.js create mode 100644 ui/component/notificationBubble/view.jsx create mode 100644 ui/component/notificationContentChannelMenu/index.js create mode 100644 ui/component/notificationContentChannelMenu/view.jsx create mode 100644 ui/component/notificationHeaderButton/index.js create mode 100644 ui/component/notificationHeaderButton/view.jsx create mode 100644 ui/component/nudgeFloating/index.js create mode 100644 ui/component/nudgeFloating/view.jsx create mode 100644 ui/component/page/index.js create mode 100644 ui/component/page/view.jsx create mode 100644 ui/component/postEditor/index.js create mode 100644 ui/component/postEditor/view.jsx create mode 100644 ui/component/postViewer/index.js create mode 100644 ui/component/postViewer/view.jsx create mode 100644 ui/component/previewLink/index.js create mode 100644 ui/component/previewLink/view.jsx create mode 100644 ui/component/previewOverlayProperties/index.js create mode 100644 ui/component/previewOverlayProperties/view.jsx create mode 100644 ui/component/privacyAgreement/index.js create mode 100644 ui/component/privacyAgreement/view.jsx create mode 100644 ui/component/publishAdditionalOptions/index.js create mode 100644 ui/component/publishAdditionalOptions/license-type.jsx create mode 100644 ui/component/publishAdditionalOptions/view.jsx create mode 100644 ui/component/publishBid/bid-help-text.jsx create mode 100644 ui/component/publishBid/index.js create mode 100644 ui/component/publishBid/view.jsx create mode 100644 ui/component/publishDescription/index.js create mode 100644 ui/component/publishDescription/view.jsx create mode 100644 ui/component/publishFile/index.js create mode 100644 ui/component/publishFile/view.jsx create mode 100644 ui/component/publishForm/index.js create mode 100644 ui/component/publishForm/view.jsx create mode 100644 ui/component/publishFormErrors/index.js create mode 100644 ui/component/publishFormErrors/view.jsx create mode 100644 ui/component/publishName/bid-help-text.jsx create mode 100644 ui/component/publishName/index.js create mode 100644 ui/component/publishName/name-help-text.jsx create mode 100644 ui/component/publishName/view.jsx create mode 100644 ui/component/publishPending/index.js create mode 100644 ui/component/publishPending/view.jsx create mode 100644 ui/component/publishPrice/index.js create mode 100644 ui/component/publishPrice/view.jsx create mode 100644 ui/component/publishReleaseDate/index.js create mode 100644 ui/component/publishReleaseDate/view.jsx create mode 100644 ui/component/publishSettings/index.js create mode 100644 ui/component/publishSettings/view.jsx create mode 100644 ui/component/recommendedContent/index.js create mode 100644 ui/component/recommendedContent/view.jsx create mode 100644 ui/component/reportContent/index.js create mode 100644 ui/component/reportContent/view.jsx create mode 100644 ui/component/repostCreate/index.js create mode 100644 ui/component/repostCreate/view.jsx create mode 100644 ui/component/rewardAuthIntro/index.js create mode 100644 ui/component/rewardAuthIntro/view.jsx create mode 100644 ui/component/rewardLink/index.js create mode 100644 ui/component/rewardLink/view.jsx create mode 100644 ui/component/rewardListClaimed/index.js create mode 100644 ui/component/rewardListClaimed/view.jsx create mode 100644 ui/component/rewardSummary/index.js create mode 100644 ui/component/rewardSummary/view.jsx create mode 100644 ui/component/rewardTile/index.js create mode 100644 ui/component/rewardTile/view.jsx create mode 100644 ui/component/rewardTotal/index.js create mode 100644 ui/component/rewardTotal/total-background.png create mode 100644 ui/component/rewardTotal/view.jsx create mode 100644 ui/component/router/index.js create mode 100644 ui/component/router/view.jsx create mode 100644 ui/component/searchOptions/index.js create mode 100644 ui/component/searchOptions/view.jsx create mode 100644 ui/component/searchTopClaim/index.js create mode 100644 ui/component/searchTopClaim/view.jsx create mode 100644 ui/component/selectAsset/index.js create mode 100644 ui/component/selectAsset/thumbnail-broken.png create mode 100644 ui/component/selectAsset/thumbnail-missing.png create mode 100644 ui/component/selectAsset/view.jsx create mode 100644 ui/component/selectChannel/index.js create mode 100644 ui/component/selectChannel/view.jsx create mode 100644 ui/component/selectThumbnail/index.js create mode 100644 ui/component/selectThumbnail/thumbnail-broken.png create mode 100644 ui/component/selectThumbnail/thumbnail-missing.png create mode 100644 ui/component/selectThumbnail/view.jsx create mode 100644 ui/component/settingAccountPassword/index.js create mode 100644 ui/component/settingAccountPassword/view.jsx create mode 100644 ui/component/settingAutoLaunch/index.js create mode 100644 ui/component/settingAutoLaunch/view.jsx create mode 100644 ui/component/settingClosingBehavior/index.js create mode 100644 ui/component/settingClosingBehavior/view.jsx create mode 100644 ui/component/settingLanguage/index.js create mode 100644 ui/component/settingLanguage/view.jsx create mode 100644 ui/component/settingWalletServer/index.js create mode 100644 ui/component/settingWalletServer/internal/inputRow.jsx create mode 100644 ui/component/settingWalletServer/view.jsx create mode 100644 ui/component/shareButton/index.js create mode 100644 ui/component/shareButton/view.jsx create mode 100644 ui/component/sideNavigation/index.js create mode 100644 ui/component/sideNavigation/view.jsx create mode 100644 ui/component/snackBar/index.js create mode 100644 ui/component/snackBar/view.jsx create mode 100644 ui/component/socialShare/index.js create mode 100644 ui/component/socialShare/view.jsx create mode 100644 ui/component/spinner/index.js create mode 100644 ui/component/spinner/view.jsx create mode 100644 ui/component/splash/index.js create mode 100644 ui/component/splash/view.jsx create mode 100644 ui/component/subscribeButton/index.js create mode 100644 ui/component/subscribeButton/view.jsx create mode 100644 ui/component/supportsLiquidate/index.js create mode 100644 ui/component/supportsLiquidate/view.jsx create mode 100644 ui/component/syncEnableFlow/index.js create mode 100644 ui/component/syncEnableFlow/view.jsx create mode 100644 ui/component/syncFatalError/index.js create mode 100644 ui/component/syncFatalError/view.jsx create mode 100644 ui/component/syncPassword/index.js create mode 100644 ui/component/syncPassword/view.jsx create mode 100644 ui/component/syncToggle/index.js create mode 100644 ui/component/syncToggle/view.jsx create mode 100644 ui/component/tag/index.js create mode 100644 ui/component/tag/view.jsx create mode 100644 ui/component/tagsSearch/index.js create mode 100644 ui/component/tagsSearch/view.jsx create mode 100644 ui/component/tagsSelect/index.js create mode 100644 ui/component/tagsSelect/view.jsx create mode 100644 ui/component/theme/index.js create mode 100644 ui/component/theme/view.jsx create mode 100644 ui/component/thumbnailPicker/index.js create mode 100644 ui/component/thumbnailPicker/thumbnail-broken.png create mode 100644 ui/component/thumbnailPicker/thumbnail-missing.png create mode 100644 ui/component/thumbnailPicker/view.jsx create mode 100644 ui/component/transactionListTable/index.js create mode 100644 ui/component/transactionListTable/view.jsx create mode 100644 ui/component/transactionListTableItem/index.js create mode 100644 ui/component/transactionListTableItem/view.jsx create mode 100644 ui/component/txoList/index.js create mode 100644 ui/component/txoList/view.jsx create mode 100644 ui/component/uriIndicator/index.js create mode 100644 ui/component/uriIndicator/view.jsx create mode 100644 ui/component/userChannelFollowIntro/index.js create mode 100644 ui/component/userChannelFollowIntro/view.jsx create mode 100644 ui/component/userEmail/index.js create mode 100644 ui/component/userEmail/view.jsx create mode 100644 ui/component/userEmailNew/index.js create mode 100644 ui/component/userEmailNew/view.jsx create mode 100644 ui/component/userEmailReturning/index.js create mode 100644 ui/component/userEmailReturning/view.jsx create mode 100644 ui/component/userEmailVerify/index.js create mode 100644 ui/component/userEmailVerify/view.jsx create mode 100644 ui/component/userFirstChannel/index.js create mode 100644 ui/component/userFirstChannel/view.jsx create mode 100644 ui/component/userPasswordReset/index.js create mode 100644 ui/component/userPasswordReset/view.jsx create mode 100644 ui/component/userPasswordSet/index.js create mode 100644 ui/component/userPasswordSet/view.jsx create mode 100644 ui/component/userPhoneNew/index.js create mode 100644 ui/component/userPhoneNew/view.jsx create mode 100644 ui/component/userPhoneVerify/index.js create mode 100644 ui/component/userPhoneVerify/view.jsx create mode 100644 ui/component/userSignIn/index.js create mode 100644 ui/component/userSignIn/view.jsx create mode 100644 ui/component/userSignInPassword/index.js create mode 100644 ui/component/userSignInPassword/view.jsx create mode 100644 ui/component/userSignOutButton/index.js create mode 100644 ui/component/userSignOutButton/view.jsx create mode 100644 ui/component/userSignUp/index.js create mode 100644 ui/component/userSignUp/view.jsx create mode 100644 ui/component/userTagFollowIntro/index.js create mode 100644 ui/component/userTagFollowIntro/view.jsx create mode 100644 ui/component/userVerify/index.js create mode 100644 ui/component/userVerify/view.jsx create mode 100644 ui/component/videoDuration/index.js create mode 100644 ui/component/videoDuration/view.jsx create mode 100644 ui/component/viewers/appViewer/index.js create mode 100644 ui/component/viewers/appViewer/view.jsx create mode 100644 ui/component/viewers/codeViewer.jsx create mode 100644 ui/component/viewers/comicBookViewer.jsx create mode 100644 ui/component/viewers/documentViewer.jsx create mode 100644 ui/component/viewers/docxViewer.jsx create mode 100644 ui/component/viewers/htmlViewer.jsx create mode 100644 ui/component/viewers/imageViewer.jsx create mode 100644 ui/component/viewers/pdfViewer.jsx create mode 100644 ui/component/viewers/threeViewer/index.jsx create mode 100644 ui/component/viewers/threeViewer/internal/detector.js create mode 100644 ui/component/viewers/threeViewer/internal/grid.js create mode 100644 ui/component/viewers/threeViewer/internal/renderer.js create mode 100644 ui/component/viewers/threeViewer/internal/scene.js create mode 100644 ui/component/viewers/videoViewer/index.js create mode 100644 ui/component/viewers/videoViewer/internal/overlays.js create mode 100644 ui/component/viewers/videoViewer/internal/plugins/videojs-hls-quality-selector/ConcreteButton.js create mode 100644 ui/component/viewers/videoViewer/internal/plugins/videojs-hls-quality-selector/ConcreteMenuItem.js create mode 100644 ui/component/viewers/videoViewer/internal/plugins/videojs-hls-quality-selector/package.json create mode 100644 ui/component/viewers/videoViewer/internal/plugins/videojs-hls-quality-selector/plugin.js create mode 100644 ui/component/viewers/videoViewer/internal/plugins/videojs-hls-quality-selector/plugin.scss create mode 100644 ui/component/viewers/videoViewer/internal/plugins/videojs-mobile-ui/LICENSE create mode 100644 ui/component/viewers/videoViewer/internal/plugins/videojs-mobile-ui/plugin.js create mode 100644 ui/component/viewers/videoViewer/internal/plugins/videojs-mobile-ui/plugin.scss create mode 100644 ui/component/viewers/videoViewer/internal/plugins/videojs-mobile-ui/touchOverlay.js create mode 100644 ui/component/viewers/videoViewer/internal/plugins/videojs-overlay/plugin.js create mode 100644 ui/component/viewers/videoViewer/internal/plugins/videojs-overlay/plugin.scss create mode 100644 ui/component/viewers/videoViewer/internal/theater-mode.js create mode 100644 ui/component/viewers/videoViewer/internal/videojs.jsx create mode 100644 ui/component/viewers/videoViewer/view.jsx create mode 100644 ui/component/walletAddress/index.js create mode 100644 ui/component/walletAddress/view.jsx create mode 100644 ui/component/walletBackup/index.js create mode 100644 ui/component/walletBackup/view.jsx create mode 100644 ui/component/walletBalance/index.js create mode 100644 ui/component/walletBalance/view.jsx create mode 100644 ui/component/walletSend/index.js create mode 100644 ui/component/walletSend/view.jsx create mode 100644 ui/component/walletSendTip/index.js create mode 100644 ui/component/walletSendTip/view.jsx create mode 100644 ui/component/walletSpendableBalanceHelp/index.js create mode 100644 ui/component/walletSpendableBalanceHelp/view.jsx create mode 100644 ui/component/walletSwap/index.js create mode 100644 ui/component/walletSwap/view.jsx create mode 100644 ui/component/walletTipAmountSelector/index.js create mode 100644 ui/component/walletTipAmountSelector/view.jsx create mode 100644 ui/component/webUploadList/index.js create mode 100644 ui/component/webUploadList/internal/web-upload-item.jsx create mode 100644 ui/component/webUploadList/view.jsx create mode 100644 ui/component/wunderbar/index.js create mode 100644 ui/component/wunderbar/view.jsx create mode 100644 ui/component/wunderbarSuggestion/index.js create mode 100644 ui/component/wunderbarSuggestion/view.jsx create mode 100644 ui/component/wunderbarSuggestions/index.js create mode 100644 ui/component/wunderbarSuggestions/view.jsx create mode 100644 ui/component/wunderbarTopSuggestion/index.js create mode 100644 ui/component/wunderbarTopSuggestion/view.jsx create mode 100644 ui/component/youtubeBadge/index.js create mode 100644 ui/component/youtubeBadge/view.jsx create mode 100644 ui/component/youtubeTransferStatus/index.js create mode 100644 ui/component/youtubeTransferStatus/view.jsx create mode 100644 ui/component/yrbl/index.jsx create mode 100644 ui/component/yrblWalletEmpty/index.js create mode 100644 ui/component/yrblWalletEmpty/view.jsx create mode 100644 ui/component/zoomableImage/index.js create mode 100644 ui/component/zoomableImage/view.jsx create mode 100644 ui/constants/action_types.js create mode 100644 ui/constants/claim.js create mode 100644 ui/constants/claim_search.js create mode 100644 ui/constants/collections.js create mode 100644 ui/constants/comment.js create mode 100644 ui/constants/email.js create mode 100644 ui/constants/file_render_modes.js create mode 100644 ui/constants/form-field.js create mode 100644 ui/constants/icons.js create mode 100644 ui/constants/language-migrations.js create mode 100644 ui/constants/languages.js create mode 100644 ui/constants/licenses.js create mode 100644 ui/constants/livestream.js create mode 100644 ui/constants/modal_types.js create mode 100644 ui/constants/moonpay.js create mode 100644 ui/constants/notifications.js create mode 100644 ui/constants/pages.js create mode 100644 ui/constants/publish_types.js create mode 100644 ui/constants/reactions.js create mode 100644 ui/constants/report_content.js create mode 100644 ui/constants/search.js create mode 100644 ui/constants/searchable_languages.js create mode 100644 ui/constants/settings.js create mode 100644 ui/constants/subscriptions.js create mode 100644 ui/constants/supported_browser_languages.js create mode 100644 ui/constants/supported_languages.js create mode 100644 ui/constants/supported_sub_languages.js create mode 100644 ui/constants/tags.js create mode 100644 ui/constants/themes.js create mode 100644 ui/constants/thumbnail_upload_statuses.js create mode 100644 ui/constants/token.js create mode 100644 ui/constants/transaction_types.js create mode 100644 ui/constants/user.js create mode 100644 ui/effects/use-combined-refs.js create mode 100644 ui/effects/use-drag-drop.js create mode 100644 ui/effects/use-fetched.js create mode 100644 ui/effects/use-get-ads.js create mode 100644 ui/effects/use-get-livestreams.js create mode 100644 ui/effects/use-get-thumbnail.js create mode 100644 ui/effects/use-history-nav.js create mode 100644 ui/effects/use-hover.js create mode 100644 ui/effects/use-is-mounted.js create mode 100644 ui/effects/use-lazy-loading.js create mode 100644 ui/effects/use-lighthouse.js create mode 100644 ui/effects/use-persisted-state.js create mode 100644 ui/effects/use-previous.js create mode 100644 ui/effects/use-screensize.js create mode 100644 ui/effects/use-stream-file.js create mode 100644 ui/effects/use-stream.js create mode 100644 ui/effects/use-throttle.js create mode 100644 ui/effects/use-tween.js create mode 100644 ui/effects/use-zoom.js create mode 100644 ui/i18n.js create mode 100644 ui/index.jsx create mode 100644 ui/logWarningConsoleMessage.js create mode 100644 ui/modal/modal.jsx create mode 100644 ui/modal/modalAffirmPurchase/index.js create mode 100644 ui/modal/modalAffirmPurchase/view.jsx create mode 100644 ui/modal/modalAutoGenerateThumbnail/index.js create mode 100644 ui/modal/modalAutoGenerateThumbnail/view.jsx create mode 100644 ui/modal/modalAutoUpdateDownloaded/index.js create mode 100644 ui/modal/modalAutoUpdateDownloaded/view.jsx create mode 100644 ui/modal/modalClaimCollectionAdd/index.js create mode 100644 ui/modal/modalClaimCollectionAdd/view.jsx create mode 100644 ui/modal/modalCommentAcknowledgement/index.js create mode 100644 ui/modal/modalCommentAcknowledgement/view.jsx create mode 100644 ui/modal/modalConfirmAge/index.js create mode 100644 ui/modal/modalConfirmAge/view.jsx create mode 100644 ui/modal/modalConfirmThumbnailUpload/index.js create mode 100644 ui/modal/modalConfirmThumbnailUpload/view.jsx create mode 100644 ui/modal/modalConfirmTransaction/index.js create mode 100644 ui/modal/modalConfirmTransaction/view.jsx create mode 100644 ui/modal/modalDownloading/index.js create mode 100644 ui/modal/modalDownloading/view.jsx create mode 100644 ui/modal/modalError/index.js create mode 100644 ui/modal/modalError/view.jsx create mode 100644 ui/modal/modalFileSelection/index.js create mode 100644 ui/modal/modalFileSelection/view.jsx create mode 100644 ui/modal/modalFileTimeout/index.js create mode 100644 ui/modal/modalFileTimeout/view.jsx create mode 100644 ui/modal/modalFirstReward/index.js create mode 100644 ui/modal/modalFirstReward/view.jsx create mode 100644 ui/modal/modalFirstSubscription/index.js create mode 100644 ui/modal/modalFirstSubscription/view.jsx create mode 100644 ui/modal/modalImageUpload/index.js create mode 100644 ui/modal/modalImageUpload/view.jsx create mode 100644 ui/modal/modalIncompatibleDaemon/index.js create mode 100644 ui/modal/modalIncompatibleDaemon/view.jsx create mode 100644 ui/modal/modalMassTipUnlock/index.js create mode 100644 ui/modal/modalMassTipUnlock/view.jsx create mode 100644 ui/modal/modalMobileSearch/index.js create mode 100644 ui/modal/modalMobileSearch/view.jsx create mode 100644 ui/modal/modalOpenExternalResource/index.js create mode 100644 ui/modal/modalOpenExternalResource/view.jsx create mode 100644 ui/modal/modalPasswordUnsave/index.js create mode 100644 ui/modal/modalPasswordUnsave/view.jsx create mode 100644 ui/modal/modalPhoneCollection/index.js create mode 100644 ui/modal/modalPhoneCollection/view.jsx create mode 100644 ui/modal/modalPublish/index.js create mode 100644 ui/modal/modalPublish/view.jsx create mode 100644 ui/modal/modalPublishPreview/index.js create mode 100644 ui/modal/modalPublishPreview/view.jsx create mode 100644 ui/modal/modalRemoveBtcSwapAddress/index.js create mode 100644 ui/modal/modalRemoveBtcSwapAddress/view.jsx create mode 100644 ui/modal/modalRemoveCollection/index.js create mode 100644 ui/modal/modalRemoveCollection/view.jsx create mode 100644 ui/modal/modalRemoveFile/index.js create mode 100644 ui/modal/modalRemoveFile/view.jsx create mode 100644 ui/modal/modalRevokeClaim/index.js create mode 100644 ui/modal/modalRevokeClaim/view.jsx create mode 100644 ui/modal/modalRewardCode/index.js create mode 100644 ui/modal/modalRewardCode/view.jsx create mode 100644 ui/modal/modalRouter/index.js create mode 100644 ui/modal/modalRouter/view.jsx create mode 100644 ui/modal/modalSendTip/index.js create mode 100644 ui/modal/modalSendTip/view.jsx create mode 100644 ui/modal/modalSetReferrer/index.js create mode 100644 ui/modal/modalSetReferrer/view.jsx create mode 100644 ui/modal/modalSignOut/index.js create mode 100644 ui/modal/modalSignOut/view.jsx create mode 100644 ui/modal/modalSocialShare/index.js create mode 100644 ui/modal/modalSocialShare/view.jsx create mode 100644 ui/modal/modalSupportsLiquidate/index.js create mode 100644 ui/modal/modalSupportsLiquidate/view.jsx create mode 100644 ui/modal/modalSyncEnable/index.js create mode 100644 ui/modal/modalSyncEnable/view.jsx create mode 100644 ui/modal/modalTransactionFailed/index.js create mode 100644 ui/modal/modalTransactionFailed/view.jsx create mode 100644 ui/modal/modalUpgrade/index.js create mode 100644 ui/modal/modalUpgrade/view.jsx create mode 100644 ui/modal/modalViewImage/index.js create mode 100644 ui/modal/modalViewImage/view.jsx create mode 100644 ui/modal/modalWalletDecrypt/index.js create mode 100644 ui/modal/modalWalletDecrypt/view.jsx create mode 100644 ui/modal/modalWalletEncrypt/index.js create mode 100644 ui/modal/modalWalletEncrypt/view.jsx create mode 100644 ui/modal/modalWalletUnlock/index.js create mode 100644 ui/modal/modalWalletUnlock/view.jsx create mode 100644 ui/modal/modalYoutubeWelcome/index.js create mode 100644 ui/modal/modalYoutubeWelcome/view.jsx create mode 100644 ui/native.js create mode 100644 ui/page/backup/index.js create mode 100644 ui/page/backup/view.jsx create mode 100644 ui/page/buy/index.js create mode 100644 ui/page/buy/view.jsx create mode 100644 ui/page/channel/index.js create mode 100644 ui/page/channel/view.jsx create mode 100644 ui/page/channelNew/index.js create mode 100644 ui/page/channelNew/view.jsx create mode 100644 ui/page/channels/index.js create mode 100644 ui/page/channels/view.jsx create mode 100644 ui/page/channelsFollowing/index.js create mode 100644 ui/page/channelsFollowing/view.jsx create mode 100644 ui/page/channelsFollowingDiscover/index.js create mode 100644 ui/page/channelsFollowingDiscover/view.jsx create mode 100644 ui/page/checkoutPage/credit-card-logos.png create mode 100644 ui/page/checkoutPage/index.js create mode 100644 ui/page/checkoutPage/view.jsx create mode 100644 ui/page/collection/index.js create mode 100644 ui/page/collection/view.jsx create mode 100644 ui/page/creatorDashboard/index.js create mode 100644 ui/page/creatorDashboard/view.jsx create mode 100644 ui/page/discover/index.js create mode 100644 ui/page/discover/view.jsx create mode 100644 ui/page/embedWrapper/index.js create mode 100644 ui/page/embedWrapper/view.jsx create mode 100644 ui/page/file/index.js create mode 100644 ui/page/file/view.jsx create mode 100644 ui/page/fileListDownloaded/index.js create mode 100644 ui/page/fileListDownloaded/view.jsx create mode 100644 ui/page/fileListPublished/index.js create mode 100644 ui/page/fileListPublished/view.jsx create mode 100644 ui/page/fourOhFour/index.js create mode 100644 ui/page/fourOhFour/view.jsx create mode 100644 ui/page/help/index.js create mode 100644 ui/page/help/view.jsx create mode 100644 ui/page/home/index.js create mode 100644 ui/page/home/view.jsx create mode 100644 ui/page/invite/index.js create mode 100644 ui/page/invite/view.jsx create mode 100644 ui/page/invited/index.js create mode 100644 ui/page/invited/view.jsx create mode 100644 ui/page/library/index.js create mode 100644 ui/page/library/view.jsx create mode 100644 ui/page/listBlocked/index.js create mode 100644 ui/page/listBlocked/view.jsx create mode 100644 ui/page/lists/index.js create mode 100644 ui/page/lists/view.jsx create mode 100644 ui/page/livestream/index.js create mode 100644 ui/page/livestream/view.jsx create mode 100644 ui/page/livestreamCurrent/index.js create mode 100644 ui/page/livestreamCurrent/view.jsx create mode 100644 ui/page/livestreamSetup/index.js create mode 100644 ui/page/livestreamSetup/view.jsx create mode 100644 ui/page/navigationHistory/index.js create mode 100644 ui/page/navigationHistory/view.jsx create mode 100644 ui/page/notifications/index.js create mode 100644 ui/page/notifications/view.jsx create mode 100644 ui/page/passwordReset/index.js create mode 100644 ui/page/passwordReset/view.jsx create mode 100644 ui/page/passwordSet/index.js create mode 100644 ui/page/passwordSet/view.jsx create mode 100644 ui/page/publish/index.js create mode 100644 ui/page/publish/view.jsx create mode 100644 ui/page/receive/index.js create mode 100644 ui/page/receive/view.jsx create mode 100644 ui/page/report/index.js create mode 100644 ui/page/report/view.jsx create mode 100644 ui/page/reportContent/index.js create mode 100644 ui/page/reportContent/view.jsx create mode 100644 ui/page/repost/index.js create mode 100644 ui/page/repost/view.jsx create mode 100644 ui/page/rewards/index.js create mode 100644 ui/page/rewards/view.jsx create mode 100644 ui/page/rewardsVerify/index.js create mode 100644 ui/page/rewardsVerify/view.jsx create mode 100644 ui/page/search/index.js create mode 100644 ui/page/search/view.jsx create mode 100644 ui/page/send/index.js create mode 100644 ui/page/send/view.jsx create mode 100644 ui/page/settings/index.js create mode 100644 ui/page/settings/view.jsx create mode 100644 ui/page/settingsAdvanced/index.js create mode 100644 ui/page/settingsAdvanced/view.jsx create mode 100644 ui/page/settingsCreator/index.js create mode 100644 ui/page/settingsCreator/view.jsx create mode 100644 ui/page/settingsNotifications/index.js create mode 100644 ui/page/settingsNotifications/view.jsx create mode 100644 ui/page/show/index.js create mode 100644 ui/page/show/view.jsx create mode 100644 ui/page/signIn/index.js create mode 100644 ui/page/signIn/view.jsx create mode 100644 ui/page/signInVerify/index.js create mode 100644 ui/page/signInVerify/view.jsx create mode 100644 ui/page/signInWalletPassword/index.js create mode 100644 ui/page/signInWalletPassword/view.jsx create mode 100644 ui/page/signUp/index.js create mode 100644 ui/page/signUp/view.jsx create mode 100644 ui/page/swap/index.js create mode 100644 ui/page/swap/view.jsx create mode 100644 ui/page/tagsFollowing/index.js create mode 100644 ui/page/tagsFollowing/view.jsx create mode 100644 ui/page/tagsFollowingManage/index.js create mode 100644 ui/page/tagsFollowingManage/view.jsx create mode 100644 ui/page/top/index.js create mode 100644 ui/page/top/view.jsx create mode 100644 ui/page/wallet/index.js create mode 100644 ui/page/wallet/view.jsx create mode 100644 ui/page/welcome/index.js create mode 100644 ui/page/welcome/view.jsx create mode 100644 ui/page/youtubeSync/index.js create mode 100644 ui/page/youtubeSync/view.jsx create mode 100644 ui/reducers.js create mode 100644 ui/redux/actions/app.js create mode 100644 ui/redux/actions/blocked.js create mode 100644 ui/redux/actions/coinSwap.js create mode 100644 ui/redux/actions/comments.js create mode 100644 ui/redux/actions/content.js create mode 100644 ui/redux/actions/file.js create mode 100644 ui/redux/actions/livestream.js create mode 100644 ui/redux/actions/notifications.js create mode 100644 ui/redux/actions/publish.js create mode 100644 ui/redux/actions/reactions.js create mode 100644 ui/redux/actions/reportContent.js create mode 100644 ui/redux/actions/rewards.js create mode 100644 ui/redux/actions/search.js create mode 100644 ui/redux/actions/settings.js create mode 100644 ui/redux/actions/subscriptions.js create mode 100644 ui/redux/actions/sync.js create mode 100644 ui/redux/actions/tags.js create mode 100644 ui/redux/actions/user.js create mode 100644 ui/redux/actions/websocket.js create mode 100644 ui/redux/reducers/app.js create mode 100644 ui/redux/reducers/blocked.js create mode 100644 ui/redux/reducers/coinSwap.js create mode 100644 ui/redux/reducers/comments.js create mode 100644 ui/redux/reducers/content.js create mode 100644 ui/redux/reducers/livestream.js create mode 100644 ui/redux/reducers/notifications.js create mode 100644 ui/redux/reducers/reactions.js create mode 100644 ui/redux/reducers/reportContent.js create mode 100644 ui/redux/reducers/rewards.js create mode 100644 ui/redux/reducers/search.js create mode 100644 ui/redux/reducers/settings.js create mode 100644 ui/redux/reducers/subscriptions.js create mode 100644 ui/redux/reducers/sync.js create mode 100644 ui/redux/reducers/tags.js create mode 100644 ui/redux/reducers/user.js create mode 100644 ui/redux/selectors/app.js create mode 100644 ui/redux/selectors/blocked.js create mode 100644 ui/redux/selectors/coinSwap.js create mode 100644 ui/redux/selectors/comments.js create mode 100644 ui/redux/selectors/content.js create mode 100644 ui/redux/selectors/file_info.js create mode 100644 ui/redux/selectors/livestream.js create mode 100644 ui/redux/selectors/notifications.js create mode 100644 ui/redux/selectors/publish.js create mode 100644 ui/redux/selectors/reactions.js create mode 100644 ui/redux/selectors/reportContent.js create mode 100644 ui/redux/selectors/rewards.js create mode 100644 ui/redux/selectors/search.js create mode 100644 ui/redux/selectors/settings.js create mode 100644 ui/redux/selectors/subscriptions.js create mode 100644 ui/redux/selectors/sync.js create mode 100644 ui/redux/selectors/tags.js create mode 100644 ui/redux/selectors/user.js create mode 100644 ui/rewards.js create mode 100644 ui/scss/all.scss create mode 100644 ui/scss/component/_ads.scss create mode 100644 ui/scss/component/_animation.scss create mode 100644 ui/scss/component/_badge.scss create mode 100644 ui/scss/component/_button.scss create mode 100644 ui/scss/component/_card.scss create mode 100644 ui/scss/component/_channel.scss create mode 100644 ui/scss/component/_claim-list.scss create mode 100644 ui/scss/component/_claim-search.scss create mode 100644 ui/scss/component/_collection.scss create mode 100644 ui/scss/component/_comments.scss create mode 100644 ui/scss/component/_content.scss create mode 100644 ui/scss/component/_dat-gui.scss create mode 100644 ui/scss/component/_embed-player.scss create mode 100644 ui/scss/component/_empty.scss create mode 100644 ui/scss/component/_expandable.scss create mode 100644 ui/scss/component/_file-drop.scss create mode 100644 ui/scss/component/_file-list.scss create mode 100644 ui/scss/component/_file-properties.scss create mode 100644 ui/scss/component/_file-render.scss create mode 100644 ui/scss/component/_footer.scss create mode 100644 ui/scss/component/_form-field.scss create mode 100644 ui/scss/component/_form-row.scss create mode 100644 ui/scss/component/_header.scss create mode 100644 ui/scss/component/_icon.scss create mode 100644 ui/scss/component/_item-list.scss create mode 100644 ui/scss/component/_livestream.scss create mode 100644 ui/scss/component/_main.scss create mode 100644 ui/scss/component/_markdown-editor.scss create mode 100644 ui/scss/component/_markdown-preview.scss create mode 100644 ui/scss/component/_media.scss create mode 100644 ui/scss/component/_modal.scss create mode 100644 ui/scss/component/_navigation.scss create mode 100644 ui/scss/component/_notification.scss create mode 100644 ui/scss/component/_nudge.scss create mode 100644 ui/scss/component/_pagination.scss create mode 100644 ui/scss/component/_placeholder.scss create mode 100644 ui/scss/component/_post.scss create mode 100644 ui/scss/component/_progress.scss create mode 100644 ui/scss/component/_purchase.scss create mode 100644 ui/scss/component/_search.scss create mode 100644 ui/scss/component/_share.scss create mode 100644 ui/scss/component/_snack-bar.scss create mode 100644 ui/scss/component/_spinner.scss create mode 100644 ui/scss/component/_splash.scss create mode 100644 ui/scss/component/_status-bar.scss create mode 100644 ui/scss/component/_superchat.scss create mode 100644 ui/scss/component/_syntax-highlighter.scss create mode 100644 ui/scss/component/_table.scss create mode 100644 ui/scss/component/_tags.scss create mode 100644 ui/scss/component/_tooltip.scss create mode 100644 ui/scss/component/_txo-list.scss create mode 100644 ui/scss/component/_videojs.scss create mode 100644 ui/scss/component/_wunderbar.scss create mode 100644 ui/scss/component/_yrbl.scss create mode 100644 ui/scss/component/expanding-details.scss create mode 100644 ui/scss/component/menu-button.scss create mode 100644 ui/scss/component/nag.scss create mode 100644 ui/scss/component/section.scss create mode 100644 ui/scss/component/tabs.scss create mode 100644 ui/scss/init/_base-theme.scss create mode 100644 ui/scss/init/_color.scss create mode 100644 ui/scss/init/_gui.scss create mode 100644 ui/scss/init/_mixins.scss create mode 100644 ui/scss/init/_reset.scss create mode 100644 ui/scss/init/_vars.scss create mode 100644 ui/scss/themes/dark.scss create mode 100644 ui/scss/themes/light.scss create mode 100644 ui/store.js create mode 100644 ui/util/autoLaunch.js create mode 100644 ui/util/comments.js create mode 100644 ui/util/context-menu.js create mode 100644 ui/util/country.js create mode 100644 ui/util/debounce.js create mode 100644 ui/util/deep-equal.js create mode 100644 ui/util/default-languages.js create mode 100644 ui/util/detect-typing.js create mode 100644 ui/util/enhanced-layout.js create mode 100644 ui/util/fetch.js create mode 100644 ui/util/form-validation.js create mode 100644 ui/util/format-bytes.js create mode 100644 ui/util/full-screen.js create mode 100644 ui/util/generate-thumbnail-name.js create mode 100644 ui/util/handle-fetch.js create mode 100644 ui/util/hex.js create mode 100644 ui/util/number.js create mode 100644 ui/util/object.js create mode 100644 ui/util/parse-data.js create mode 100644 ui/util/publish.js create mode 100644 ui/util/query-params.js create mode 100644 ui/util/redux-utils.js create mode 100644 ui/util/remark-lbry.js create mode 100644 ui/util/remark-timestamp.js create mode 100644 ui/util/saved-passwords.js create mode 100644 ui/util/search.js create mode 100644 ui/util/set-operations.js create mode 100644 ui/util/shuffle-array.js create mode 100644 ui/util/string.js create mode 100644 ui/util/swap-json.js create mode 100644 ui/util/sync-settings.js create mode 100644 ui/util/throttle.js create mode 100644 ui/util/thumbnail.js create mode 100644 ui/util/time.js create mode 100644 ui/util/url.js create mode 100644 ui/util/web-file-system.js create mode 100644 ui/util/web.js create mode 100644 ui/util/zoomWindow.js create mode 100644 web/bundle-id.js create mode 100644 web/component/ads/index.js create mode 100644 web/component/ads/view.jsx create mode 100644 web/component/fileViewerEmbeddedEnded/index.js create mode 100644 web/component/fileViewerEmbeddedEnded/view.jsx create mode 100644 web/component/footer.jsx create mode 100644 web/component/nag-data-collection.jsx create mode 100644 web/component/nag-degraded-performance.jsx create mode 100644 web/component/openInAppLink/index.js create mode 100644 web/component/openInAppLink/view.jsx create mode 100644 web/component/youtubeReferralWelcome/index.js create mode 100644 web/component/youtubeReferralWelcome/view.jsx create mode 100644 web/effects/use-degraded-performance.js create mode 100644 web/index.js create mode 100644 web/middleware/cache-control.js create mode 100644 web/middleware/iframe-destroyer.js create mode 100644 web/middleware/redirect.js create mode 100644 web/package.json create mode 100644 web/page/code2257/index.js create mode 100644 web/page/code2257/view.jsx create mode 100644 web/setup/publish.js create mode 100644 web/src/category-metadata.js create mode 100644 web/src/chainquery.js create mode 100644 web/src/html.js create mode 100644 web/src/robots.js create mode 100644 web/src/routes.js create mode 100644 web/src/rss.js create mode 100644 web/src/xml.js create mode 100644 web/static/pwa/icon-180.png create mode 100644 web/static/pwa/icon-192.png create mode 100644 web/static/pwa/icon-512.png create mode 100644 web/static/pwa/icon.png create mode 100644 web/static/pwa/manifest.json create mode 100644 web/static/pwa/serviceWorker.js create mode 100644 web/stubs/electron.js create mode 100644 web/stubs/fs.js create mode 100644 web/webpack.config.js create mode 100644 web/yarn.lock create mode 100644 webpack.base.config.js create mode 100644 webpack.electron.config.js create mode 100644 yarn.lock diff --git a/.env.defaults b/.env.defaults new file mode 100644 index 0000000..c7f381e --- /dev/null +++ b/.env.defaults @@ -0,0 +1,64 @@ +# Copy this file to .env to make modifications + +# Base config +MATOMO_URL=https://analytics.lbry.com/ +MATOMO_ID=4 +WEBPACK_WEB_PORT=9090 +WEBPACK_ELECTRON_PORT=9091 +WEB_SERVER_PORT=1337 +LBRY_WEB_API=https://api.lbry.tv +LBRY_WEB_STREAMING_API=https://cdn.lbryplayer.xyz +LBRY_WEB_BUFFER_API=https://collector-service.api.lbry.tv/api/v1/events/video +COMMENT_SERVER_API=https://comments.lbry.com/api/v2 +WELCOME_VERSION=1.0 + +# Custom Site info +DOMAIN=lbry.tv +URL=https://lbry.tv +THUMBNAIL_CDN_URL=https://image-optimizer.vanwanet.com/?address= + +# UI +SITE_TITLE=lbry.tv +SITE_NAME=lbry.tv +SITE_DESCRIPTION=Meet LBRY, an open, free, and community-controlled content wonderland. +SITE_HELP_EMAIL=help@lbry.com +LOGO_TITLE=lbry.tv +SIMPLE_SITE=false +SHOW_ADS=true +YRBL_HAPPY_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a +YRBL_SAD_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd +ENABLE_COMMENT_REACTIONS=true +ENABLE_FILE_REACTIONS=false +ENABLE_CREATOR_REACTIONS=false +ENABLE_NO_SOURCE_CLAIMS=false +ENABLE_PREROLL_ADS=false +CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS=4 +CHANNEL_STAKED_LEVEL_LIVESTREAM=5 +WEB_PUBLISH_SIZE_LIMIT_GB=4 + +# OG +OG_TITLE_SUFFIX=| lbry.tv +OG_HOMEPAGE_TITLE=lbry.tv +OG_IMAGE_URL= +SITE_CANONICAL_URL=https://lbry.tv + +# LOCALE +DEFAULT_LANGUAGE=en + +# Custom Settings +# Additional settings for below are found in ui/constants/settings and are for +# preventing user settings from applying to custom sites without overwriting them. +# UNSYNCED_SETTINGS='theme dark_mode_times automatic_dark_mode_enabled' +KNOWN_APP_DOMAINS=lbry.tv,lbry.lat,odysee.com + +# Custom Content +# If the following is true, copy custom/homepage.example.js to custom/homepage.js and modify +CUSTOM_HOMEPAGE=false +# Add channels to auto-follow on first run +AUTO_FOLLOW_CHANNELS=lbry://@lbry#3fda836a92faaceedfe398225fb9b2ee2ed1f01a +# Add up to 2 sidebar links: +# PINNED_URI_1=@Lbrylatam#2/Integracionesporseguridad#4 +# PINNED_LABEL_1=LBRY LATAM +# PINNED_URI_2=$/discover?t=lbrytvpaidbeta&fee_amount=>0&claim_type=stream&channel_ids=5af39f818f668d8c00943c9326c5201c4fe3c423,cda9c4e92f19d6fe0764524a2012056e06ca2055,760da3ba3dd85830a843beaaed543a89b7a367e7,40c36948f0da072dcba3e4833e90f71e16de78be,e8f68563d242f6ac9784dcbc41dd86c28a9391d6,7236fc5d2783ea7314d9076ae6c8a250e3992d1a,cf7792c2a37d0d76aaaff84aff0b99a8c791429d,8316ac90764fedf3147799b7b81a6575a9cc398e,8627af93c1a1219150f06b698f4b33e6ed2f1c1e,8972a1bd06de5186e5e89292b05aac8aaa817791,c5b0b17838df2f6c31162f64d55f60f34ae8bfc6,f576d5dba905fc179de880c3fe3eb3281ea74f59,97dd77c93c9603cbb2583f3589f7f5a6c92baa43,f399d873e0c37cf24de9569b5f22bbb30a5c6709,dba870d0620d41b2b9a152c961e0c06cf875ccfc,ca1fd651c9d14bf2e5088bb2aa0146ee7aeb2ae0,50ad846a4b1543b847bf3fdafb7b45f6b2f5844c,e09ff5abe9fb44dd0dd0576894a6db60a6211603,7b6f7517f6b816827d076fa0eaad550aa315a4e7,2068452c41d8da3bd68961335da0072a99258a1a,5da63df97c8255ae94a88940695b8471657dd5a1,3645cf2f5d0bdac0523f945be1c3ff60758f7845,4da85b12244839d6368b9290f1619ff9514ab2a8,4ad942982e43326c7700b1b6443049b3cfd82161,55304f219244abf82f684f759cc0c7769242f3b4,8f42e5b592bb7f7a03f4a94a86a41b1236bb099f,e2a014d885a48f5be2dc6409610996337312facb,c18996ca488753f714d36d4654715927c1d7f9c2,ebc4214424cfa683a7046e1f794fea1e44788d84,06b6d6d6a893fb589ec2ded948f5122856921ed5,07e4546674268fc0222b2ca22d31d0549dc217ee,060940e41973d4f7f16d72a2733138e931c35f41,f8d6eccd887c9cebd36b1d42aa349279b7f5c3ed,68098b8426f967b8d04cc566348b5c128823219e,2bfe6cdb24a21bdc1b76fb7c416edd50e9e85945,1f9bb08bfa2259629f4aaa9ed40f97e9a41b6fa1,2f20148495612946675fe1c8ea99171e4d950b81,bc6938fa1e09e840056c2e831abf9664f397c472,2a6194792beac5130641e932b5ac6e5a99b5ca4f,185ba2bd547a5e4a77d29fe6c1484f47db5e058f,29cc7f6081268eaa5b3f2946e0cd0b952a94812c,49389450b1241f5d8f4c8c4271a3eb56bba33965,ffdc62ac2f7549398d3aca9d2119e83d80d588d5,d7a4d2808074b0c55d6b239f69d90e7a4930f943,d58aa4a0b2f6c2504c3abce8de3f1afb71800acc,77ae23dc7eb8a75609881d4548a79e4935a89d37,f79bce8a60fbece671f6265adc39f6469f3b9b8c,051995fdf0af634e4911704057a551e9392e62b1 +# PINNED_LABEL_2=Paid Beta + diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..a540930 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +node_modules/* +./node_modules/** +**/node_modules/** +web/dist/** diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..71fae41 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,62 @@ +{ + "parser": "babel-eslint", + "extends": ["standard", "standard-jsx", "plugin:react/recommended", "plugin:flowtype/recommended"], + "plugins": ["flowtype", "import", "react-hooks"], + "env": { + "browser": true, + "node": true + }, + "globals": { + "__static": true, + "i18n": true, + "__": true, + "app": true, + "IS_WEB": true, + "WEBPACK_PORT": true + }, + "settings": { + "react": { + "version": "detect" + } + }, + "rules": { + "brace-style": 0, + "camelcase": 0, + "comma-dangle": ["error", "always-multiline"], + "handle-callback-err": 0, + "indent": 0, + "jsx-quotes": ["error", "prefer-double"], + "new-cap": 0, + "no-console": 1, + "no-control-regex": 0, + "no-multi-spaces": 0, + "no-redeclare": 0, + "no-return-await": 0, + "object-curly-spacing": 0, + "one-var": 0, + "prefer-promise-reject-errors": 0, + "react/jsx-indent": 0, + "react/jsx-no-comment-textnodes": 0, + "react-hooks/exhaustive-deps": "warn", + "react-hooks/rules-of-hooks": "error", + "react/no-unescaped-entities": 0, + "space-before-function-paren": [ + "error", + { + "anonymous": "never", + "named": "never", + "asyncArrow": "always" + } + ], + "standard/object-curly-even-spacing": 0, + "standard/no-callback-literal": 0, + "react/display-name": 0, + "semi": [ + "error", + "always", + { + "omitLastInOneLineBlock": true + } + ] + } +} diff --git a/.flowconfig b/.flowconfig new file mode 100644 index 0000000..4fe2681 --- /dev/null +++ b/.flowconfig @@ -0,0 +1,43 @@ +[ignore] +.*\.typeface\.json +.*/node_modules/findup/.* + + +[include] + +[libs] +./flow-typed +node_modules/lbry-redux/flow-typed/ +node_modules/lbryinc/flow-typed/ + +[untyped] +.*/node_modules/lbry-redux +.*/node_modules/lbryinc + +[lints] + +[options] +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue +module.name_mapper='^constants\(.*\)$' -> '/ui/constants\1' +module.name_mapper='^util\(.*\)$' -> '/ui/util\1' +module.name_mapper='^redux\(.*\)$' -> '/ui/redux\1' +module.name_mapper='^types\(.*\)$' -> '/ui/types\1' +module.name_mapper='^component\(.*\)$' -> '/ui/component\1' +module.name_mapper='^page\(.*\)$' -> '/ui/page\1' +module.name_mapper='^lbry\(.*\)$' -> '/ui/lbry\1' +module.name_mapper='^modal\(.*\)$' -> '/ui/modal\1' +module.name_mapper='^app\(.*\)$' -> '/ui/app\1' +module.name_mapper='^native\(.*\)$' -> '/ui/native\1' +module.name_mapper='^analytics\(.*\)$' -> '/ui/analytics\1' +module.name_mapper='^rewards\(.*\)$' -> '/ui/rewards\1' +module.name_mapper='^i18n\(.*\)$' -> '/ui/i18n\1' +module.name_mapper='^effects\(.*\)$' -> '/ui/effects\1' +module.name_mapper='^comments\(.*\)$' -> '/ui/comments\1' +module.name_mapper='^config\(.*\)$' -> '/config\1' +module.name_mapper='^web\/component\(.*\)$' -> '/web/component\1' +module.name_mapper='^web\/effects\(.*\)$' -> '/web/effects\1' +module.name_mapper='^web\/page\(.*\)$' -> '/web/page\1' +module.name_mapper='^homepage\(.*\)$' -> '/ui/util/homepage\1' + +[strict] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e4fc361 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride +node_modules +dist +/static/lbrynet* +/static/daemon +/static/locales +yarn-error.log +package-lock.json +.transifexrc +.idea/ +/build/daemon* +/lbrytv/dist/ +/lbrytv/node_modules +/static/lbry-first/ +/build/lbryFirst* +/web/dist/* +/web/node_modules/* +/web/.env +/web/.env.defaults +/custom/* +/custom/homepages/* +/custom/content/* +!/custom/content/default.json +!/custom/content/test.json +!/custom/homepages/.gitkeep +!/custom/homepages +!/custom/content +!/custom/homepage.example.js +!/custom/robots.disallowall +!/custom/robots.allowall +.env +diff diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000..f1722f8 --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,9 @@ +{ + "linters": { + "ui/**/*.{js,jsx,scss,json}": ["prettier --write", "git add"], + "web/**/*.{js,jsx,scss,json}": ["prettier --write", "git add"], + "ui/**/*.{js,jsx}": ["eslint", "flow focus-check --color always", "git add"], + "web/**/*.{js,jsx,scss}": ["eslint", "git add"] + }, + "ignore": ["node_modules", "web/dist/**/*", "dist/**/*", "package-lock.json"] +} diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..c1c72e8 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "trailingComma": "es5", + "printWidth": 120, + "singleQuote": true +} diff --git a/.sentryclirc b/.sentryclirc new file mode 100644 index 0000000..84164da --- /dev/null +++ b/.sentryclirc @@ -0,0 +1,4 @@ +[defaults] +url = https://sentry.lbry.tech/ +org = lbry +project = lbry-desktop-web \ No newline at end of file diff --git a/.tx/config b/.tx/config new file mode 100644 index 0000000..c1a4319 --- /dev/null +++ b/.tx/config @@ -0,0 +1,7 @@ +[main] +host = https://www.transifex.com + +[lbry-desktop.app-strings] +source_file = static/app-strings.json +source_lang = en +type = KEYVALUEJSON diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c9af77a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1873 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [Unreleased for Desktop] + +### Added + +- Send a tip with your comment ([#5920](https://github.com/lbryio/lbry-desktop/issues/5920)) +- Search for tags in search dropdown ([#5876](https://github.com/lbryio/lbry-desktop/issues/5876)) +- Japanese, Afrikaans, Filipino, Thai and Vietnamese language support ([#5684](https://github.com/lbryio/lbry-desktop/issues/5684)) +- Highlight comments made by content owner _community pr!_ ([#5744](https://github.com/lbryio/lbry-desktop/pull/5744)) +- Ability to report infringing content directly from the application ([#5808](https://github.com/lbryio/lbry-desktop/pull/5808)) +- Re-added ability to export wallet transactions ([#5899](https://github.com/lbryio/lbry-desktop/pull/5899)) + +### Changed + +- Keyboard shortcut additions and changes _community pr!_ ([#5717](https://github.com/lbryio/lbry-desktop/pull/5717)) +- Removed the 10k character-limit when editing _Posts_ ([#5719](https://github.com/lbryio/lbry-desktop/pull/5719)) + +### Fixed + +- Lazy-load claim images to improve app responsiveness ([#5795](https://github.com/lbryio/lbry-desktop/issues/5795)) +- Fix display of upload date and view count on smaller screens ([#5822](https://github.com/lbryio/lbry-desktop/issues/5822)) +- Autoplay looping to a previous video or itself ([#5711](https://github.com/lbryio/lbry-desktop/pull/5711)) +- Autoplay not working in mini-player mode ([#5716](https://github.com/lbryio/lbry-desktop/pull/5716)) +- Edited claim accidentally moved to 'Anonymous' ([#5767](https://github.com/lbryio/lbry-desktop/pull/5767)) + +## [0.50.2] - [2021-04-2] + +### Changed + +- Disable PDFs until security issue is fixed + +## [0.50.1] - [2021-03-18] + +### Fixed + +- Upgrade modal extended beyond the height of the app ([#5709](https://github.com/lbryio/lbry-desktop/pull/5709)) + +## [0.50.0] - [2021-03-18] + +### Added + +- New moderation tools: block & mute ([#5572](https://github.com/lbryio/lbry-desktop/pull/5572)) +- Improved markdown file styling ([#5659](https://github.com/lbryio/lbry-desktop/pull/5659)) +- Mass tip unlock ([#5409](https://github.com/lbryio/lbry-desktop/pull/5387)) +- Zoomable image viewer in Markdown (posts and comments) _community pr!_ ([#5387](https://github.com/lbryio/lbry-desktop/pull/5387)) +- Enable PDF Viewer in App _community pr!_ ([#2903](https://github.com/lbryio/lbry-desktop/issues/2903)) +- The search bar now handles both lbry.tv and Odysee links regardless of which site the user is in ([#5604](https://github.com/lbryio/lbry-desktop/issues/5604)) +- The video/audio player's control tooltip is now localized and includes hints for keyboard shortcuts ([#5584](https://github.com/lbryio/lbry-desktop/issues/5584)) +- Finnish and Norwegian language support ([#5532](https://github.com/lbryio/lbry-desktop/issues/5532)) + +### Changed + +- Updated lbry-sdk to [0.92.0](https://github.com/lbryio/lbry-sdk/releases/tag/v0.92.0) +- Re-enable PDF Viewer in desktop app _community pr!_ ([#5420](https://github.com/lbryio/lbry-desktop/issues/5420)) + +### Fixed + +- Player doesn't stop playing when editing a comment that includes a video url _community pr!_ ([#5384](https://github.com/lbryio/lbry-desktop/pull/5384)) +- Main video/audio playback stopped every time a comment is edited or deleted ([#5606](https://github.com/lbryio/lbry-desktop/pull/5606)) +- Winning search result not working correctly with mature content enabled _community pr!_ ([#5388](https://github.com/lbryio/lbry-desktop/pull/5388)) +- Home/End key not working as expected in Search Bar ([#5642](https://github.com/lbryio/lbry-desktop/pull/5642)) +- Fixes to inline videos in comments _community pr!_ ([#5389](https://github.com/lbryio/lbry-desktop/pull/5389)) +- Search page crashing on some results ([#5428](https://github.com/lbryio/lbry-desktop/pull/5428)) +- Long channel names caused comments to extend underneath related content _community pr!_ ([#5431](https://github.com/lbryio/lbry-desktop/pull/5431)) +- Keep floating player always visible _community pr!_ ([#5448](https://github.com/lbryio/lbry-desktop/pull/5448)) +- LBRY Desktop incorrectly setting itself as the default HTML-file application in Linux ([#5617](https://github.com/lbryio/lbry-desktop/pull/5617)) +- All notifications being cleared when only 1 is clicked ([#5619](https://github.com/lbryio/lbry-desktop/pull/5619)) +- Markdown editor's "Create Link (Ctrl-K)" action now directly highlights the URL stub when the label is present ([#5585](https://github.com/lbryio/lbry-desktop/issues/5585)) + +## [0.49.4] - [2021-01-26] + +### Added + +- Theater mode ([#5255](https://github.com/lbryio/lbry-desktop/pull/5255)) +- Repost flow improvements ([#5293](https://github.com/lbryio/lbry-desktop/pull/5293)) +- Desktop: Enable 'Alt+Left/Right' for history navigation _community pr!_ ([#5203](https://github.com/lbryio/lbry-desktop/pull/5203)) +- Make playback rate setting persistent _community pr!_ ([#5310](https://github.com/lbryio/lbry-desktop/pull/5310)) +- Make UI zoom setting persistent _community pr!_ ([#5385](https://github.com/lbryio/lbry-desktop/pull/5385)) + +### Changed + +- No longer supporting 32 bit windows +- Updated lbry-sdk to [0.88.0](https://github.com/lbryio/lbry-sdk/releases/tag/v0.88.0) +- Improve how spendable balance is displayed ([#5409](https://github.com/lbryio/lbry-desktop/pull/5276)) + +### Fixed + +- Lots of bug fixes +- Fix bug where subscriptions could be lost ([#5302](https://github.com/lbryio/lbry-desktop/pull/5302)) + +## [0.49.3] - [2020-12-30] + +### Added + +- Turn timestamps in a video's description and comments into links _community pr!_ ([#5156](https://github.com/lbryio/lbry-desktop/pull/5156)) +- Mobile video player enhancements and the ability to tap on the left and right edges to seek _community pr!_ ([#5119](https://github.com/lbryio/lbry-desktop/pull/5119)) +- Added tile layout for tags page [a0ec5](https://github.com/lbryio/lbry-desktop/commit/a0ec5097d93496b92736e1682f9fb2d20dadf425). + +### Changed + +- Repost option now has a full page and can be triggered from search results (click "View competing uploads for ..."). + +### Fixed + +- [Upgrade SDK to 0.87.0](https://github.com/lbryio/lbry-sdk/releases/tag/v0.87.0). Forces wallet resync which fixes balance issues for some users and improves memory usage. + +## [0.49.1] - [2020-12-15] + +### Fixed + +- Sidenav unable to open when on the file page +- Fix "open external" button to open files on your OS + +## [0.49.0] - [2020-12-10] + +### Added + +- Better search suggestions ([#5124](https://github.com/lbryio/lbry-desktop/pull/5124)) +- Inline video player in comments/markdown posts ([#4894](https://github.com/lbryio/lbry-desktop/pull/4894)) +- Better handling of winning claim + top page improvements ([#4944](https://github.com/lbryio/lbry-desktop/pull/4944)) +- Comment pinning ([#4895](https://github.com/lbryio/lbry-desktop/pull/4895)) +- Comment reactions ([#4895](https://github.com/lbryio/lbry-desktop/pull/4895)) +- Language search ([#4907](https://github.com/lbryio/lbry-desktop/pull/4907)) +- Content notifications ([#4981](https://github.com/lbryio/lbry-desktop/pull/4981)) +- Customize scrollbar to fit the dark theme _community pr!_ ([#5056](https://github.com/lbryio/lbry-desktop/pull/5056)) +- Keyboard shortcut: adjust video playback-rate using ">" and "<" _community pr!_ ([#5075](https://github.com/lbryio/lbry-desktop/pull/5075)) + +### Changed + +- Updated lbry-sdk to [0.86.1](https://github.com/lbryio/lbry-sdk/releases/tag/v0.86.1) +- Refactored file/lbc details UI ([#4937](https://github.com/lbryio/lbry-desktop/pull/4937)) + +### Fixed + +- Loss of subscriptions on startup ([#4882](https://github.com/lbryio/lbry-desktop/pull/4882)) +- Fix lost search results when a timeout occurs _community pr!_ ([#4996](https://github.com/lbryio/lbry-desktop/pull/4996)) +- Can't slide volume slider in pop-sout mode _community pr!_ ([#4913](https://github.com/lbryio/lbry-desktop/pull/4913)) +- Hide mouse cursor when video is playing _community pr!_ ([#5046](https://github.com/lbryio/lbry-desktop/pull/5046)) + +## [0.48.2] - [2020-10-16] + +### Changed + +- Disable snapshot thumbnail upload on desktop until Electron issue is fixed ([#4905](https://github.com/lbryio/lbry-desktop/pull/4905)) + +### Fixed + +- Files not opening externally properly ([#4908](https://github.com/lbryio/lbry-desktop/pull/4908)) + +## [0.48.1] - [2020-10-14] + +### Added + +- Add Publish Preview dialog _community pr!_ ([#4620](https://github.com/lbryio/lbry-desktop/pull/4620)) +- "ctrl/cmd+enter" can now be used to directly submit a comment ([#4809](https://github.com/lbryio/lbry-desktop/pull/4809)) +- Deeper comment thread depth ([#4868](https://github.com/lbryio/lbry-desktop/pull/4868)) + +### Changed + +- Updated lbry-sdk to [0.83.0](https://github.com/lbryio/lbry-sdk/releases/tag/v0.83.0) +- Upgrade electron to v9 ([#4824](https://github.com/lbryio/lbry-desktop/pull/4824)) +- Fade out expandable areas (e.g. comments, file description) when collapsed _community pr!_ ([#4818](https://github.com/lbryio/lbry-desktop/pull/4818)) + +### Fixed + +- Videos started as muted on initial desktop session _community pr!_ ([#4864](https://github.com/lbryio/lbry-desktop/pull/4864)) + +## [0.48.0] - [2020-09-23] + +### Added + +- New File Page layout + make sidebar collapsable ([#4648](https://github.com/lbryio/lbry-desktop/pull/4648)) +- Block mature content when accessed directly from URL _community pr!_ ([#4560](https://github.com/lbryio/lbry-desktop/pull/4560)) +- You can now add LBRY as a search engine in your browser (via OpenSearch) _community pr!_ ([#4640](https://github.com/lbryio/lbry-desktop/pull/4640)) +- In-app text and markdown publishing and editing _community pr!_ ([#4591](https://github.com/lbryio/lbry-desktop/pull/4591)) +- New comment stats on creator analytics page _jiggytom certified_ ([#4715](https://github.com/lbryio/lbry-desktop/pull/4715)) + +### Changed + +- Move file properties over thumbnails for more space-saving ([#4632](https://github.com/lbryio/lbry-desktop/pull/4632)) + +### Fixed + +- Fix sluggish Back button when navigation back to channels with lots of comments _community pr!_ ([#4576](https://github.com/lbryio/lbry-desktop/pull/4576)) +- Fix 'Related' and 'Comments' section lazy-load not working in some scenarios _community pr!_ ([#4586](https://github.com/lbryio/lbry-desktop/pull/4586)) +- Fix comment-creation failure if you have recently deleted a channel _community pr!_ ([#4630](https://github.com/lbryio/lbry-desktop/pull/4630)) +- Tip Modal: Don't do final submit when the intention is to create New Channel _community pr!_ ([#4629](https://github.com/lbryio/lbry-desktop/pull/4629)) +- Fix related + search results loading slowly ([#4657](https://github.com/lbryio/lbry-desktop/pull/4657)) +- Fix partially untranslated text in the Upgrade Modal _community pr!_ ([#4722](https://github.com/lbryio/lbry-desktop/pull/4722)) +- Fix floating player being paused after dragging _community pr!_ ([#4710](https://github.com/lbryio/lbry-desktop/pull/4710)) +- Web: Fix 'Download' not triggering until second attempt _community pr!_ ([#4721](https://github.com/lbryio/lbry-desktop/pull/4721)) +- Floating player: Stay within screen when window is resized _community pr!_([#4750](https://github.com/lbryio/lbry-desktop/pull/4750)) +- App crash when including % sign in search _community pr!_([#4753](https://github.com/lbryio/lbry-desktop/pull/4753)) +- Fix markdown editor "preview" not working when ``; + + function copyToClipboard() { + const topRef = input.current; + if (topRef && topRef.input && topRef.input.current) { + topRef.input.current.select(); + document.execCommand('copy'); + doToast({ message: snackMessage || 'Embed link copied' }); + } + } + + function onFocus() { + // We have to go a layer deep since the input is inside the form component + const topRef = input && input.current; + if (topRef && topRef.input && topRef.input.current) { + topRef.input.current.select(); + } + } + + return ( +
+ + +
+
+
+ ); +} diff --git a/ui/component/errorBoundary/index.js b/ui/component/errorBoundary/index.js new file mode 100644 index 0000000..40c167c --- /dev/null +++ b/ui/component/errorBoundary/index.js @@ -0,0 +1,4 @@ +import ErrorBoundary from './view'; + +// TODO: bring in device/user(?) info in the future +export default ErrorBoundary; diff --git a/ui/component/errorBoundary/view.jsx b/ui/component/errorBoundary/view.jsx new file mode 100644 index 0000000..6c064d7 --- /dev/null +++ b/ui/component/errorBoundary/view.jsx @@ -0,0 +1,124 @@ +// @flow +import type { Node } from 'react'; +import React from 'react'; +import Yrbl from 'component/yrbl'; +import Button from 'component/button'; +import { withRouter } from 'react-router'; +import analytics from 'analytics'; +import I18nMessage from 'component/i18nMessage'; +import Native from 'native'; +import { Lbry } from 'lbry-redux'; + +type Props = { + children: Node, + history: { + replace: string => void, + }, +}; + +type State = { + hasError: boolean, + sentryEventId: ?string, + desktopErrorReported: boolean, +}; + +class ErrorBoundary extends React.Component { + constructor() { + super(); + this.state = { hasError: false, sentryEventId: undefined, desktopErrorReported: false }; + + (this: any).refresh = this.refresh.bind(this); + } + + static getDerivedStateFromError() { + return { hasError: true }; + } + + componentDidCatch(error, errorInfo) { + // @if TARGET='web' + analytics.sentryError(error, errorInfo).then(sentryEventId => { + this.setState({ sentryEventId }); + }); + // @endif + + // @if TARGET='app' + let errorMessage = 'Uncaught error\n'; + Native.getAppVersionInfo().then(({ localVersion }) => { + Lbry.version().then(({ lbrynet_version: sdkVersion }) => { + errorMessage += `app version: ${localVersion}\n`; + errorMessage += `sdk version: ${sdkVersion}\n`; + errorMessage += `page: ${window.location.href.split('.html')[1]}\n`; + errorMessage += `${error.stack}`; + analytics.error(errorMessage).then(isSharingData => { + this.setState({ desktopErrorReported: isSharingData }); + }); + }); + }); + // @endif + } + + refresh() { + const { history } = this.props; + + // use history.replace instead of history.push so the user can't click back to the errored page + history.replace(''); + this.setState({ hasError: false }); + } + + render() { + const { hasError } = this.state; + const { sentryEventId, desktopErrorReported } = this.state; + + const errorWasReported = IS_WEB ? sentryEventId !== null : desktopErrorReported; + + if (hasError) { + return ( +
+ + ), + }} + > + There was an error. Try %refreshing_the_app_link% to fix it. If that doesn't work, try pressing + Ctrl+R/Cmd+R. + + } + /> + {!errorWasReported && ( +
+ + {__('You are not currently sharing diagnostic data so this error was not reported.')} + +
+ )} + + {errorWasReported && ( +
+ {/* @if TARGET='web' */} + {__('Error ID: %sentryEventId%', { sentryEventId })} + {/* @endif */} + {/* @if TARGET='app' */} + {__('This error was reported and will be fixed.')} + {/* @endif */} +
+ )} +
+ ); + } + + return this.props.children; + } +} + +export default withRouter(ErrorBoundary); diff --git a/ui/component/expandable/index.js b/ui/component/expandable/index.js new file mode 100644 index 0000000..6dc708a --- /dev/null +++ b/ui/component/expandable/index.js @@ -0,0 +1,7 @@ +import { connect } from 'react-redux'; +import Expandable from './view'; + +export default connect( + null, + null +)(Expandable); diff --git a/ui/component/expandable/view.jsx b/ui/component/expandable/view.jsx new file mode 100644 index 0000000..c082f4c --- /dev/null +++ b/ui/component/expandable/view.jsx @@ -0,0 +1,47 @@ +// @flow +import React, { useRef, useState } from 'react'; +import classnames from 'classnames'; +import Button from 'component/button'; +import { useRect } from '@reach/rect'; + +const COLLAPSED_HEIGHT = 120; + +type Props = { + children: React$Node | Array, +}; + +export default function Expandable(props: Props) { + const [expanded, setExpanded] = useState(false); + const { children } = props; + const ref = useRef(); + const rect = useRect(ref); + + function handleClick() { + setExpanded(!expanded); + } + + return ( +
+ {rect && rect.height > COLLAPSED_HEIGHT ? ( +
+
+ {children} +
+
+ ) : ( +
{children}
+ )} +
+ ); +} diff --git a/ui/component/fileActions/index.js b/ui/component/fileActions/index.js new file mode 100644 index 0000000..a47576d --- /dev/null +++ b/ui/component/fileActions/index.js @@ -0,0 +1,50 @@ +import { connect } from 'react-redux'; +import { + makeSelectClaimIsMine, + makeSelectFileInfoForUri, + makeSelectClaimForUri, + doPrepareEdit, + selectMyChannelClaims, + makeSelectClaimIsStreamPlaceholder, + makeSelectTagInClaimOrChannelForUri, +} from 'lbry-redux'; +import { DISABLE_COMMENTS_TAG } from 'constants/tags'; +import { makeSelectUserPropForProp } from 'redux/selectors/user'; +import { makeSelectCostInfoForUri } from 'lbryinc'; +import { doSetPlayingUri } from 'redux/actions/content'; +import { doToast } from 'redux/actions/notifications'; +import { doOpenModal, doSetActiveChannel, doSetIncognito } from 'redux/actions/app'; +import fs from 'fs'; +import FileActions from './view'; +import * as USER from 'constants/user'; +import { makeSelectFileRenderModeForUri } from 'redux/selectors/content'; + +const select = (state, props) => ({ + claim: makeSelectClaimForUri(props.uri)(state), + claimIsMine: makeSelectClaimIsMine(props.uri)(state), + fileInfo: makeSelectFileInfoForUri(props.uri)(state), + renderMode: makeSelectFileRenderModeForUri(props.uri)(state), + costInfo: makeSelectCostInfoForUri(props.uri)(state), + myChannels: selectMyChannelClaims(state), + isLivestreamClaim: makeSelectClaimIsStreamPlaceholder(props.uri)(state), + reactionsDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state), + hasExperimentalUi: makeSelectUserPropForProp(USER.EXPERIMENTAL_UI)(state), +}); + +const perform = (dispatch) => ({ + openModal: (modal, props) => dispatch(doOpenModal(modal, props)), + prepareEdit: (publishData, uri, fileInfo) => { + if (publishData.signing_channel) { + dispatch(doSetIncognito(false)); + dispatch(doSetActiveChannel(publishData.signing_channel.claim_id)); + } else { + dispatch(doSetIncognito(true)); + } + + dispatch(doPrepareEdit(publishData, uri, fileInfo, fs)); + }, + clearPlayingUri: () => dispatch(doSetPlayingUri({ uri: null })), + doToast: (options) => dispatch(doToast(options)), +}); + +export default connect(select, perform)(FileActions); diff --git a/ui/component/fileActions/view.jsx b/ui/component/fileActions/view.jsx new file mode 100644 index 0000000..b2c7394 --- /dev/null +++ b/ui/component/fileActions/view.jsx @@ -0,0 +1,168 @@ +// @flow +import { SITE_NAME, ENABLE_FILE_REACTIONS } from 'config'; +import * as PAGES from 'constants/pages'; +import * as MODALS from 'constants/modal_types'; +import * as ICONS from 'constants/icons'; +import React from 'react'; +import Button from 'component/button'; +import FileDownloadLink from 'component/fileDownloadLink'; +import { buildURI } from 'lbry-redux'; +import * as RENDER_MODES from 'constants/file_render_modes'; +import { useIsMobile } from 'effects/use-screensize'; +import ClaimSupportButton from 'component/claimSupportButton'; +import ClaimCollectionAddButton from 'component/claimCollectionAddButton'; +import { useHistory } from 'react-router'; +import FileReactions from 'component/fileReactions'; + +type Props = { + uri: string, + claim: StreamClaim, + openModal: (id: string, { uri: string, claimIsMine?: boolean, isSupport?: boolean }) => void, + prepareEdit: ({}, string, {}) => void, + claimIsMine: boolean, + fileInfo: FileListItem, + costInfo: ?{ cost: number }, + renderMode: string, + myChannels: ?Array, + doToast: ({ message: string }) => void, + clearPlayingUri: () => void, + isLivestreamClaim: boolean, + reactionsDisabled: boolean, + hasExperimentalUi: boolean, +}; + +function FileActions(props: Props) { + const { + fileInfo, + uri, + openModal, + claimIsMine, + claim, + costInfo, + renderMode, + prepareEdit, + myChannels, + clearPlayingUri, + doToast, + isLivestreamClaim, + reactionsDisabled, + hasExperimentalUi, + } = props; + const { + push, + location: { pathname }, + } = useHistory(); + const isMobile = useIsMobile(); + const webShareable = costInfo && costInfo.cost === 0 && RENDER_MODES.WEB_SHAREABLE_MODES.includes(renderMode); + const showDelete = claimIsMine || (fileInfo && (fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0)); + const hasChannels = myChannels && myChannels.length > 0; + const claimId = claim && claim.claim_id; + const { signing_channel: signingChannel } = claim; + const channelName = signingChannel && signingChannel.name; + // We want to use the short form uri for editing + // This is what the user is used to seeing, they don't care about the claim id + // We will select the claim id before they publish + let editUri; + if (claimIsMine) { + const uriObject: { streamName: string, streamClaimId: string, channelName?: string } = { + streamName: claim.name, + streamClaimId: claim.claim_id, + }; + if (channelName) { + uriObject.channelName = channelName; + } + + editUri = buildURI(uriObject); + } + + function handleRepostClick() { + if (!hasChannels) { + clearPlayingUri(); + push(`/$/${PAGES.CHANNEL_NEW}?redirect=${pathname}`); + doToast({ message: __('A channel is required to repost on %SITE_NAME%', { SITE_NAME }) }); + } else { + push(`/$/${PAGES.REPOST_NEW}?from=${encodeURIComponent(uri)}&redirect=${pathname}`); + } + } + + const lhsSection = ( + <> + {ENABLE_FILE_REACTIONS && !reactionsDisabled && } + + {hasExperimentalUi && } + + + + + {showCreditDetails && ( +
+ +
+ )} + + ); +} + +export default FileDescription; diff --git a/ui/component/fileDetails/index.js b/ui/component/fileDetails/index.js new file mode 100644 index 0000000..c0d15cb --- /dev/null +++ b/ui/component/fileDetails/index.js @@ -0,0 +1,24 @@ +import { connect } from 'react-redux'; +import { + makeSelectClaimForUri, + makeSelectContentTypeForUri, + makeSelectMetadataForUri, + makeSelectFileInfoForUri, +} from 'lbry-redux'; +import { selectUser } from 'redux/selectors/user'; +import { doOpenFileInFolder } from 'redux/actions/file'; +import FileDetails from './view'; + +const select = (state, props) => ({ + claim: makeSelectClaimForUri(props.uri)(state), + contentType: makeSelectContentTypeForUri(props.uri)(state), + fileInfo: makeSelectFileInfoForUri(props.uri)(state), + metadata: makeSelectMetadataForUri(props.uri)(state), + user: selectUser(state), +}); + +const perform = dispatch => ({ + openFolder: path => dispatch(doOpenFileInFolder(path)), +}); + +export default connect(select, perform)(FileDetails); diff --git a/ui/component/fileDetails/view.jsx b/ui/component/fileDetails/view.jsx new file mode 100644 index 0000000..dd806f1 --- /dev/null +++ b/ui/component/fileDetails/view.jsx @@ -0,0 +1,103 @@ +// @flow +import { SIMPLE_SITE } from 'config'; +import React, { PureComponent } from 'react'; +import Button from 'component/button'; +import path from 'path'; +import { formatBytes } from 'util/format-bytes'; + +type Props = { + claim: StreamClaim, + fileInfo: FileListItem, + metadata: StreamMetadata, + openFolder: (string) => void, + contentType: string, + user: ?any, +}; + +class FileDetails extends PureComponent { + render() { + const { claim, contentType, fileInfo, metadata, openFolder } = this.props; + + if (!claim || !metadata) { + return {__('Empty claim or metadata info.')}; + } + + const { languages, license } = metadata; + + const mediaType = contentType || 'unknown'; + const fileSize = + metadata.source && metadata.source.size + ? formatBytes(metadata.source.size) + : fileInfo && fileInfo.download_path && formatBytes(fileInfo.written_bytes); + let downloadPath = fileInfo && fileInfo.download_path ? path.normalize(fileInfo.download_path) : null; + let downloadNote; + // If the path is blank, file is not available. Streamed files won't have any blobs saved + // Create path from name so the folder opens on click. + if (fileInfo && fileInfo.blobs_completed >= 1 && fileInfo.download_path === null) { + downloadPath = `${fileInfo.download_directory}/${fileInfo.file_name}`; + downloadNote = __('This file may have been streamed, moved or deleted'); + } + + return ( + <> +
+ {__('LBRY URL')} + {claim.canonical_url} +
+
+ {__('Claim ID')} + {claim.claim_id} +
+ + {!SIMPLE_SITE && ( + <> + {languages && ( +
+ {__('Languages')} + {languages.join(' ')} +
+ )} + + {mediaType && ( +
+ {__('Media Type')} + {mediaType} +
+ )} + +
+ {__('License')} + {license} +
+ + {downloadPath && ( +
+ {__('Downloaded to')} + +
+ )} + + )} + + {fileSize && ( +
+ {fileSize} +
+ )} + + ); + } +} + +export default FileDetails; diff --git a/ui/component/fileDownloadLink/index.js b/ui/component/fileDownloadLink/index.js new file mode 100644 index 0000000..7f635b5 --- /dev/null +++ b/ui/component/fileDownloadLink/index.js @@ -0,0 +1,33 @@ +import { connect } from 'react-redux'; +import { + makeSelectFileInfoForUri, + makeSelectDownloadingForUri, + makeSelectLoadingForUri, + makeSelectClaimIsMine, + makeSelectClaimForUri, + makeSelectClaimWasPurchased, + makeSelectStreamingUrlForUri, +} from 'lbry-redux'; +import { makeSelectCostInfoForUri } from 'lbryinc'; +import { doOpenModal, doAnalyticsView } from 'redux/actions/app'; +import { doSetPlayingUri, doPlayUri } from 'redux/actions/content'; +import FileDownloadLink from './view'; + +const select = (state, props) => ({ + fileInfo: makeSelectFileInfoForUri(props.uri)(state), + downloading: makeSelectDownloadingForUri(props.uri)(state), + loading: makeSelectLoadingForUri(props.uri)(state), + claimIsMine: makeSelectClaimIsMine(props.uri)(state), + claim: makeSelectClaimForUri(props.uri)(state), + costInfo: makeSelectCostInfoForUri(props.uri)(state), + claimWasPurchased: makeSelectClaimWasPurchased(props.uri)(state), + streamingUrl: makeSelectStreamingUrlForUri(props.uri)(state), +}); + +const perform = dispatch => ({ + openModal: (modal, props) => dispatch(doOpenModal(modal, props)), + pause: () => dispatch(doSetPlayingUri({ uri: null })), + download: uri => dispatch(doPlayUri(uri, false, true, () => dispatch(doAnalyticsView(uri)))), +}); + +export default connect(select, perform)(FileDownloadLink); diff --git a/ui/component/fileDownloadLink/view.jsx b/ui/component/fileDownloadLink/view.jsx new file mode 100644 index 0000000..670048d --- /dev/null +++ b/ui/component/fileDownloadLink/view.jsx @@ -0,0 +1,120 @@ +// @flow +import * as ICONS from 'constants/icons'; +import * as MODALS from 'constants/modal_types'; +import React, { useState } from 'react'; +import Button from 'component/button'; + +type Props = { + uri: string, + claim: StreamClaim, + claimIsMine: boolean, + downloading: boolean, + loading: boolean, + fileInfo: ?FileListItem, + openModal: (id: string, { path: string }) => void, + pause: () => void, + download: (string) => void, + costInfo: ?{ cost: string }, + buttonType: ?string, + showLabel: ?boolean, + hideOpenButton: boolean, + hideDownloadStatus: boolean, + streamingUrl: ?string, +}; + +function FileDownloadLink(props: Props) { + const { + fileInfo, + downloading, + loading, + openModal, + pause, + claimIsMine, + download, + uri, + claim, + buttonType, + showLabel = false, + hideOpenButton = false, + hideDownloadStatus = false, + streamingUrl, + } = props; + + const [didClickDownloadButton, setDidClickDownloadButton] = useState(false); + const fileName = claim && claim.value && claim.value.source && claim.value.source.name; + + // @if TARGET='web' + React.useEffect(() => { + if (didClickDownloadButton && streamingUrl) { + let element = document.createElement('a'); + element.setAttribute('href', `${streamingUrl}?download=true`); + element.setAttribute('download', fileName); + element.style.display = 'none'; + // $FlowFixMe + document.body.appendChild(element); + element.click(); + // $FlowFixMe + document.body.removeChild(element); + + setDidClickDownloadButton(false); + } + }, [streamingUrl, didClickDownloadButton, fileName]); + // @endif + + function handleDownload(e) { + setDidClickDownloadButton(true); + e.preventDefault(); + download(uri); + } + + if (!claim) { + return null; + } + + // @if TARGET='app' + if (downloading || loading) { + if (hideDownloadStatus) { + return null; + } + + if (fileInfo && fileInfo.written_bytes > 0) { + const progress = (fileInfo.written_bytes / fileInfo.total_bytes) * 100; + return {__('%percent%% downloaded', { percent: progress.toFixed(0) })}; + } else { + return {__('Connecting...')}; + } + } + // @endif + + if (fileInfo && fileInfo.download_path && fileInfo.completed) { + const openLabel = __('Open file'); + return hideOpenButton ? null : ( + + + )} + + +
+ +
+ + + +
+ + + + + 0} + /> + +
+ + ); +} + +export default Comment; diff --git a/ui/component/livestreamComments/index.js b/ui/component/livestreamComments/index.js new file mode 100644 index 0000000..071e9aa --- /dev/null +++ b/ui/component/livestreamComments/index.js @@ -0,0 +1,27 @@ +import { connect } from 'react-redux'; +import { makeSelectClaimForUri, selectMyChannelClaims } from 'lbry-redux'; +import { doCommentSocketConnect, doCommentSocketDisconnect } from 'redux/actions/websocket'; +import { doCommentList, doSuperChatList } from 'redux/actions/comments'; +import { + makeSelectTopLevelCommentsForUri, + selectIsFetchingComments, + makeSelectSuperChatsForUri, + makeSelectSuperChatTotalAmountForUri, +} from 'redux/selectors/comments'; +import LivestreamFeed from './view'; + +const select = (state, props) => ({ + claim: makeSelectClaimForUri(props.uri)(state), + comments: makeSelectTopLevelCommentsForUri(props.uri)(state).slice(0, 75), + fetchingComments: selectIsFetchingComments(state), + superChats: makeSelectSuperChatsForUri(props.uri)(state), + superChatsTotalAmount: makeSelectSuperChatTotalAmountForUri(props.uri)(state), + myChannels: selectMyChannelClaims(state), +}); + +export default connect(select, { + doCommentSocketConnect, + doCommentSocketDisconnect, + doCommentList, + doSuperChatList, +})(LivestreamFeed); diff --git a/ui/component/livestreamComments/view.jsx b/ui/component/livestreamComments/view.jsx new file mode 100644 index 0000000..a9e65da --- /dev/null +++ b/ui/component/livestreamComments/view.jsx @@ -0,0 +1,209 @@ +// @flow +import React from 'react'; +import classnames from 'classnames'; +import Spinner from 'component/spinner'; +import CommentCreate from 'component/commentCreate'; +import LivestreamComment from 'component/livestreamComment'; +import Button from 'component/button'; +import UriIndicator from 'component/uriIndicator'; +import CreditAmount from 'component/common/credit-amount'; +import ChannelThumbnail from 'component/channelThumbnail'; +import Tooltip from 'component/common/tooltip'; + +type Props = { + uri: string, + claim: ?StreamClaim, + activeViewers: number, + embed?: boolean, + doCommentSocketConnect: (string, string) => void, + doCommentSocketDisconnect: (string) => void, + doCommentList: (string, number, number) => void, + comments: Array, + fetchingComments: boolean, + doSuperChatList: (string) => void, + superChats: Array, + superChatsTotalAmount: number, + myChannels: ?Array, +}; + +const VIEW_MODE_CHAT = 'view_chat'; +const VIEW_MODE_SUPER_CHAT = 'view_superchat'; + +export default function LivestreamComments(props: Props) { + const { + claim, + uri, + embed, + doCommentSocketConnect, + doCommentSocketDisconnect, + comments, + doCommentList, + fetchingComments, + doSuperChatList, + superChats, + superChatsTotalAmount, + myChannels, + } = props; + const commentsRef = React.createRef(); + const hasScrolledComments = React.useRef(); + const [viewMode, setViewMode] = React.useState(VIEW_MODE_CHAT); + const [performedInitialScroll, setPerformedInitialScroll] = React.useState(false); + const claimId = claim && claim.claim_id; + const commentsLength = comments && comments.length; + const commentsToDisplay = viewMode === VIEW_MODE_CHAT ? comments : superChats; + + // todo: implement comment_list --mine in SDK so redux can grab with selectCommentIsMine + function isMyComment(channelId: string) { + if (myChannels != null && channelId != null) { + for (let i = 0; i < myChannels.length; i++) { + if (myChannels[i].claim_id === channelId) { + return true; + } + } + } + return false; + } + + React.useEffect(() => { + if (claimId) { + doCommentList(uri, 1, 75); + doSuperChatList(uri); + doCommentSocketConnect(uri, claimId); + } + + return () => { + if (claimId) { + doCommentSocketDisconnect(claimId); + } + }; + }, [claimId, uri, doCommentList, doSuperChatList, doCommentSocketConnect, doCommentSocketDisconnect]); + + React.useEffect(() => { + const element = commentsRef.current; + + function handleScroll() { + if (element) { + const scrollHeight = element.scrollHeight - element.offsetHeight; + const isAtBottom = scrollHeight <= element.scrollTop + 100; + + if (!isAtBottom) { + hasScrolledComments.current = true; + } else { + hasScrolledComments.current = false; + } + } + } + + if (element) { + element.addEventListener('scroll', handleScroll); + + if (commentsLength > 0) { + // Only update comment scroll if the user hasn't scrolled up to view old comments + // If they have, do nothing + if (!hasScrolledComments.current || !performedInitialScroll) { + setTimeout(() => (element.scrollTop = element.scrollHeight - element.offsetHeight + 100), 20); + + if (!performedInitialScroll) { + setPerformedInitialScroll(true); + } + } + } + } + + return () => { + if (element) { + element.removeEventListener('scroll', handleScroll); + } + }; + }, [commentsRef, commentsLength, performedInitialScroll]); + + if (!claim) { + return null; + } + + return ( +
+
+
{__('Live discussion')}
+ {superChatsTotalAmount > 0 && ( +
+
+ )} +
+ <> + {fetchingComments && !comments && ( +
+ +
+ )} +
+ {viewMode === VIEW_MODE_CHAT && superChatsTotalAmount > 0 && ( +
+
+ {superChats.map((superChat: Comment) => ( + +
+
+ +
+ +
+ + +
+
+
+ ))} +
+
+ )} + + {!fetchingComments && comments.length > 0 ? ( +
+ {commentsToDisplay.map((comment) => ( + + ))} +
+ ) : ( +
+ )} + +
+ +
+
+ +
+ ); +} diff --git a/ui/component/livestreamLayout/index.js b/ui/component/livestreamLayout/index.js new file mode 100644 index 0000000..30063aa --- /dev/null +++ b/ui/component/livestreamLayout/index.js @@ -0,0 +1,12 @@ +import { connect } from 'react-redux'; +import { makeSelectClaimForUri, makeSelectTagInClaimOrChannelForUri, makeSelectThumbnailForUri } from 'lbry-redux'; +import LivestreamLayout from './view'; +import { DISABLE_COMMENTS_TAG } from 'constants/tags'; + +const select = (state, props) => ({ + claim: makeSelectClaimForUri(props.uri)(state), + thumbnail: makeSelectThumbnailForUri(props.uri)(state), + chatDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state), +}); + +export default connect(select)(LivestreamLayout); diff --git a/ui/component/livestreamLayout/view.jsx b/ui/component/livestreamLayout/view.jsx new file mode 100644 index 0000000..ff18ddd --- /dev/null +++ b/ui/component/livestreamLayout/view.jsx @@ -0,0 +1,62 @@ +// @flow +import { BITWAVE_EMBED_URL } from 'constants/livestream'; +import React from 'react'; +import FileTitleSection from 'component/fileTitleSection'; +import LivestreamComments from 'component/livestreamComments'; +import { useIsMobile } from 'effects/use-screensize'; + +type Props = { + uri: string, + claim: ?StreamClaim, + isLive: boolean, + activeViewers: number, + chatDisabled: boolean, +}; + +export default function LivestreamLayout(props: Props) { + const { claim, uri, isLive, activeViewers, chatDisabled } = props; + const isMobile = useIsMobile(); + + if (!claim || !claim.signing_channel) { + return null; + } + + const channelName = claim.signing_channel.name; + const channelClaimId = claim.signing_channel.claim_id; + + return ( + <> +
+
+
+ + ) : ( +
+ +
+ ) + } + /> + ) : ( + + } + actions={ +
+
+ setCountry(e.target.value)} + > + + {COUNTRIES.map((country, index) => ( + + ))} + +
+ {country && ( +
+ {isValid ? ( +
+
+ ) : ( +
+
+ )} +
+ )} +
+ } + /> + )} + + )} + + )} +
+ + ); +} diff --git a/ui/page/channel/index.js b/ui/page/channel/index.js new file mode 100644 index 0000000..3b92172 --- /dev/null +++ b/ui/page/channel/index.js @@ -0,0 +1,40 @@ +import { connect } from 'react-redux'; +import { + makeSelectClaimIsMine, + makeSelectTitleForUri, + makeSelectThumbnailForUri, + makeSelectCoverForUri, + selectCurrentChannelPage, + makeSelectClaimForUri, + makeSelectClaimIsPending, +} from 'lbry-redux'; +import { selectBlackListedOutpoints, doFetchSubCount, makeSelectSubCountForUri } from 'lbryinc'; +import { selectYoutubeChannels } from 'redux/selectors/user'; +import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; +import { selectModerationBlockList } from 'redux/selectors/comments'; +import { selectMutedChannels } from 'redux/selectors/blocked'; +import { doOpenModal } from 'redux/actions/app'; +import ChannelPage from './view'; + +const select = (state, props) => ({ + title: makeSelectTitleForUri(props.uri)(state), + thumbnail: makeSelectThumbnailForUri(props.uri)(state), + cover: makeSelectCoverForUri(props.uri)(state), + channelIsMine: makeSelectClaimIsMine(props.uri)(state), + page: selectCurrentChannelPage(state), + claim: makeSelectClaimForUri(props.uri)(state), + isSubscribed: makeSelectIsSubscribed(props.uri, true)(state), + blackListedOutpoints: selectBlackListedOutpoints(state), + subCount: makeSelectSubCountForUri(props.uri)(state), + pending: makeSelectClaimIsPending(props.uri)(state), + youtubeChannels: selectYoutubeChannels(state), + blockedChannels: selectModerationBlockList(state), + mutedChannels: selectMutedChannels(state), +}); + +const perform = (dispatch) => ({ + openModal: (modal, props) => dispatch(doOpenModal(modal, props)), + fetchSubCount: (claimId) => dispatch(doFetchSubCount(claimId)), +}); + +export default connect(select, perform)(ChannelPage); diff --git a/ui/page/channel/view.jsx b/ui/page/channel/view.jsx new file mode 100644 index 0000000..6e69308 --- /dev/null +++ b/ui/page/channel/view.jsx @@ -0,0 +1,288 @@ +// @flow +import * as ICONS from 'constants/icons'; +import * as PAGES from 'constants/pages'; +import React from 'react'; +import { parseURI } from 'lbry-redux'; +import { YOUTUBE_STATUSES } from 'lbryinc'; +import Page from 'component/page'; +import SubscribeButton from 'component/subscribeButton'; +import ShareButton from 'component/shareButton'; +import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'component/common/tabs'; +import { useHistory } from 'react-router'; +import Button from 'component/button'; +import { formatLbryUrlForWeb } from 'util/url'; +import ChannelContent from 'component/channelContent'; +import ChannelAbout from 'component/channelAbout'; +import ChannelDiscussion from 'component/channelDiscussion'; +import ChannelThumbnail from 'component/channelThumbnail'; +import ChannelEdit from 'component/channelEdit'; +import classnames from 'classnames'; +import HelpLink from 'component/common/help-link'; +import ClaimSupportButton from 'component/claimSupportButton'; +import ChannelStakedIndicator from 'component/channelStakedIndicator'; +import ClaimMenuList from 'component/claimMenuList'; +import Yrbl from 'component/yrbl'; + +export const PAGE_VIEW_QUERY = `view`; +const CONTENT_PAGE = 'content'; +const LISTS_PAGE = 'lists'; +const ABOUT_PAGE = `about`; +export const DISCUSSION_PAGE = `discussion`; +const EDIT_PAGE = 'edit'; + +type Props = { + uri: string, + claim: ChannelClaim, + title: ?string, + cover: ?string, + thumbnail: ?string, + page: number, + match: { params: { attribute: ?string } }, + channelIsMine: boolean, + isSubscribed: boolean, + channelIsBlocked: boolean, + blackListedOutpoints: Array<{ + txid: string, + nout: number, + }>, + fetchSubCount: (string) => void, + subCount: number, + pending: boolean, + youtubeChannels: ?Array<{ channel_claim_id: string, sync_status: string, transfer_state: string }>, + blockedChannels: Array, + mutedChannels: Array, +}; + +function ChannelPage(props: Props) { + const { + uri, + claim, + title, + cover, + // page, ?page= may come back some day? + channelIsMine, + isSubscribed, + blackListedOutpoints, + fetchSubCount, + subCount, + pending, + youtubeChannels, + blockedChannels, + mutedChannels, + } = props; + const { + push, + goBack, + location: { search }, + } = useHistory(); + const [viewBlockedChannel, setViewBlockedChannel] = React.useState(false); + const urlParams = new URLSearchParams(search); + const currentView = urlParams.get(PAGE_VIEW_QUERY) || undefined; + const [discussionWasMounted, setDiscussionWasMounted] = React.useState(false); + const editing = urlParams.get(PAGE_VIEW_QUERY) === EDIT_PAGE; + const { channelName } = parseURI(uri); + const { permanent_url: permanentUrl } = claim; + const claimId = claim.claim_id; + const formattedSubCount = Number(subCount).toLocaleString(); + const isBlocked = claim && blockedChannels.includes(claim.permanent_url); + const isMuted = claim && mutedChannels.includes(claim.permanent_url); + const isMyYouTubeChannel = + claim && + youtubeChannels && + youtubeChannels.some(({ channel_claim_id, sync_status, transfer_state }) => { + if ( + channel_claim_id === claim.claim_id && + sync_status !== YOUTUBE_STATUSES.YOUTUBE_SYNC_ABANDONDED && + transfer_state !== YOUTUBE_STATUSES.YOUTUBE_SYNC_COMPLETED_TRANSFER + ) { + return true; + } + }); + let channelIsBlackListed = false; + + if (claim && blackListedOutpoints) { + channelIsBlackListed = blackListedOutpoints.some( + (outpoint) => outpoint.txid === claim.txid && outpoint.nout === claim.nout + ); + } + + // If a user changes tabs, update the url so it stays on the same page if they refresh. + // We don't want to use links here because we can't animate the tab change and using links + // would alter the Tab label's role attribute, which should stay role="tab" to work with keyboards/screen readers. + let tabIndex; + switch (currentView) { + case CONTENT_PAGE: + tabIndex = 0; + break; + case LISTS_PAGE: + tabIndex = 1; + break; + case ABOUT_PAGE: + tabIndex = 2; + break; + case DISCUSSION_PAGE: + tabIndex = 3; + break; + default: + tabIndex = 0; + break; + } + + function onTabChange(newTabIndex) { + let url = formatLbryUrlForWeb(uri); + let search = '?'; + + if (newTabIndex === 0) { + search += `${PAGE_VIEW_QUERY}=${CONTENT_PAGE}`; + } else if (newTabIndex === 1) { + search += `${PAGE_VIEW_QUERY}=${LISTS_PAGE}`; + } else if (newTabIndex === 2) { + search += `${PAGE_VIEW_QUERY}=${ABOUT_PAGE}`; + } else { + search += `${PAGE_VIEW_QUERY}=${DISCUSSION_PAGE}`; + } + + push(`${url}${search}`); + } + + React.useEffect(() => { + if (currentView === DISCUSSION_PAGE) { + setDiscussionWasMounted(true); + } + }, [currentView]); + + React.useEffect(() => { + fetchSubCount(claimId); + }, [uri, fetchSubCount, claimId]); + + if (editing) { + return ( + + goBack()} /> + + ); + } + + return ( + +
+
+ {isMyYouTubeChannel && ( +
+ {cover && } +
+ +

+ {title || '@' + channelName} + +

+
+ + {formattedSubCount} {subCount !== 1 ? __('Followers') : __('Follower')} + + + {channelIsMine && ( + <> + {pending ? ( + {__('Your changes will be live in a few minutes')} + ) : ( +
+
+
+
+ + {(isBlocked || isMuted) && !viewBlockedChannel ? ( +
+ +
+ } + /> +
+ ) : ( + + + {__('Publishes')} + {__('Playlists')} + {editing ? __('Editing Your Channel') : __('About --[tab title in Channel Page]--')} + {__('Community')} + + + + + + + + + + + + + {(discussionWasMounted || currentView === DISCUSSION_PAGE) && } + + + + )} + + ); +} + +export default ChannelPage; diff --git a/ui/page/channelNew/index.js b/ui/page/channelNew/index.js new file mode 100644 index 0000000..87c54d5 --- /dev/null +++ b/ui/page/channelNew/index.js @@ -0,0 +1,20 @@ +import REWARD_TYPES from 'rewards'; +import { connect } from 'react-redux'; +import { selectBalance } from 'lbry-redux'; +import { selectUserVerifiedEmail } from 'redux/selectors/user'; +import { doClaimRewardType } from 'redux/actions/rewards'; +import ChannelNew from './view'; + +const select = (state) => ({ + balance: selectBalance(state), + isAuthenticated: selectUserVerifiedEmail(state), +}); + +export default connect(select, (dispatch) => ({ + claimConfirmEmailReward: () => + dispatch( + doClaimRewardType(REWARD_TYPES.TYPE_CONFIRM_EMAIL, { + notifyError: false, + }) + ), +}))(ChannelNew); diff --git a/ui/page/channelNew/view.jsx b/ui/page/channelNew/view.jsx new file mode 100644 index 0000000..d291844 --- /dev/null +++ b/ui/page/channelNew/view.jsx @@ -0,0 +1,42 @@ +// @flow +import * as PAGES from 'constants/pages'; +import React from 'react'; +import ChannelEdit from 'component/channelEdit'; +import Page from 'component/page'; +import { useHistory } from 'react-router'; +import YrblWalletEmpty from 'component/yrblWalletEmpty'; + +type Props = { + balance: number, + claimConfirmEmailReward: () => void, + isAuthenticated: boolean, +}; + +function ChannelNew(props: Props) { + const { balance, claimConfirmEmailReward, isAuthenticated } = props; + const { push, location } = useHistory(); + const urlSearchParams = new URLSearchParams(location.search); + const redirectUrl = urlSearchParams.get('redirect'); + const emptyBalance = balance === 0; + + React.useEffect(() => { + if (isAuthenticated && emptyBalance) { + claimConfirmEmailReward(); + } + }, [isAuthenticated, claimConfirmEmailReward, emptyBalance]); + + return ( + + {emptyBalance && } + + { + push(redirectUrl || `/$/${PAGES.CHANNELS}`); + }} + /> + + ); +} + +export default ChannelNew; diff --git a/ui/page/channels/index.js b/ui/page/channels/index.js new file mode 100644 index 0000000..edd3cb1 --- /dev/null +++ b/ui/page/channels/index.js @@ -0,0 +1,22 @@ +import { connect } from 'react-redux'; +import { + selectMyChannelClaims, + selectMyChannelUrls, + doFetchChannelListMine, + selectFetchingMyChannels, +} from 'lbry-redux'; +import { selectYoutubeChannels } from 'redux/selectors/user'; +import ChannelsPage from './view'; + +const select = state => ({ + channelUrls: selectMyChannelUrls(state), + channels: selectMyChannelClaims(state), + fetchingChannels: selectFetchingMyChannels(state), + youtubeChannels: selectYoutubeChannels(state), +}); + +const perform = dispatch => ({ + fetchChannelListMine: () => dispatch(doFetchChannelListMine()), +}); + +export default connect(select, perform)(ChannelsPage); diff --git a/ui/page/channels/view.jsx b/ui/page/channels/view.jsx new file mode 100644 index 0000000..fbe1f47 --- /dev/null +++ b/ui/page/channels/view.jsx @@ -0,0 +1,126 @@ +// @flow +import * as ICONS from 'constants/icons'; +import React, { useEffect } from 'react'; +import { Lbryio } from 'lbryinc'; +import ClaimList from 'component/claimList'; +import Page from 'component/page'; +import Button from 'component/button'; +import YoutubeTransferStatus from 'component/youtubeTransferStatus'; +import Spinner from 'component/spinner'; +import Yrbl from 'component/yrbl'; +import LbcSymbol from 'component/common/lbc-symbol'; +import * as PAGES from 'constants/pages'; +import HelpLink from 'component/common/help-link'; + +type Props = { + channels: Array, + channelUrls: Array, + fetchChannelListMine: () => void, + fetchingChannels: boolean, + youtubeChannels: ?Array, +}; + +export default function ChannelsPage(props: Props) { + const { channels, channelUrls, fetchChannelListMine, fetchingChannels, youtubeChannels } = props; + const [rewardData, setRewardData] = React.useState(); + const hasYoutubeChannels = youtubeChannels && Boolean(youtubeChannels.length); + const hasPendingChannels = channels && channels.some((channel) => channel.confirmations < 0); + + useEffect(() => { + fetchChannelListMine(); + }, [fetchChannelListMine, hasPendingChannels]); + + useEffect(() => { + Lbryio.call('user_rewards', 'view_rate').then((data) => setRewardData(data)); + }, [setRewardData]); + + return ( + +
+ {hasYoutubeChannels && } + + {channelUrls && Boolean(channelUrls.length) && ( + {__('Your channels')}} + headerAltControls={ +
+ ); + }} + renderProperties={(claim) => { + const claimsInChannel = claim.meta.claims_in_channel; + if (!claim || claimsInChannel === 0) { + return null; + } + + const channelRewardData = + rewardData && + rewardData.rates && + rewardData.rates.find((data) => { + return data.channel_claim_id === claim.claim_id; + }); + + if (channelRewardData) { + return ( + + + {__('Earnings per view')} + + + + + + + ); + } else { + return null; + } + }} + /> + )} +
+ + {!(channelUrls && channelUrls.length) && ( + + {!fetchingChannels ? ( +
+ +
+ } + /> + + ) : ( +
+ +
+ )} + + )} + + ); +} diff --git a/ui/page/channelsFollowing/index.js b/ui/page/channelsFollowing/index.js new file mode 100644 index 0000000..599cbf8 --- /dev/null +++ b/ui/page/channelsFollowing/index.js @@ -0,0 +1,13 @@ +import { connect } from 'react-redux'; +import { SETTINGS } from 'lbry-redux'; +import { selectSubscriptions } from 'redux/selectors/subscriptions'; +import { makeSelectClientSetting } from 'redux/selectors/settings'; + +import ChannelsFollowingPage from './view'; + +const select = state => ({ + subscribedChannels: selectSubscriptions(state), + tileLayout: makeSelectClientSetting(SETTINGS.TILE_LAYOUT)(state), +}); + +export default connect(select)(ChannelsFollowingPage); diff --git a/ui/page/channelsFollowing/view.jsx b/ui/page/channelsFollowing/view.jsx new file mode 100644 index 0000000..dfd270f --- /dev/null +++ b/ui/page/channelsFollowing/view.jsx @@ -0,0 +1,56 @@ +// @flow +import * as PAGES from 'constants/pages'; +import * as ICONS from 'constants/icons'; +import * as CS from 'constants/claim_search'; +import { SIMPLE_SITE } from 'config'; +import React from 'react'; +import ChannelsFollowingDiscoverPage from 'page/channelsFollowingDiscover'; +import ClaimListDiscover from 'component/claimListDiscover'; +import Page from 'component/page'; +import Button from 'component/button'; +import Icon from 'component/common/icon'; +import useGetLivestreams from 'effects/use-get-livestreams'; + +type Props = { + subscribedChannels: Array, + tileLayout: boolean, +}; + +function ChannelsFollowingPage(props: Props) { + const { subscribedChannels, tileLayout } = props; + const hasSubsribedChannels = subscribedChannels.length > 0; + const { livestreamMap } = useGetLivestreams(); + + return !hasSubsribedChannels ? ( + + ) : ( + + + + {__('Following')} + + } + defaultOrderBy={CS.ORDER_BY_NEW} + channelIds={subscribedChannels.map((sub) => sub.uri.split('#')[1])} + meta={ +
+ + )} + + + {(route || link) && ( + + + + } + /> + + +
+

{__('You can also:')}

+
    +
  • +
  • +
  • + + ), + }} + > + Explore our %technical_resources% + + . +
  • +
  • + , + }} + > + Join our %tech_forum% + + . +
  • +
+
+ + } + /> + + + ); + } +} + +export default ReportPage; diff --git a/ui/page/reportContent/index.js b/ui/page/reportContent/index.js new file mode 100644 index 0000000..44f4834 --- /dev/null +++ b/ui/page/reportContent/index.js @@ -0,0 +1,8 @@ +import { connect } from 'react-redux'; +import ReportContentPage from './view'; + +const select = (state) => ({}); + +const perform = (dispatch) => ({}); + +export default connect(select, perform)(ReportContentPage); diff --git a/ui/page/reportContent/view.jsx b/ui/page/reportContent/view.jsx new file mode 100644 index 0000000..f2e36f0 --- /dev/null +++ b/ui/page/reportContent/view.jsx @@ -0,0 +1,19 @@ +// @flow +import React from 'react'; +import Page from 'component/page'; +import ReportContent from 'component/reportContent'; + +export default function ReportContentPage(props: any) { + return ( + + + + ); +} diff --git a/ui/page/repost/index.js b/ui/page/repost/index.js new file mode 100644 index 0000000..30aae74 --- /dev/null +++ b/ui/page/repost/index.js @@ -0,0 +1,15 @@ +import { connect } from 'react-redux'; + +import { doResolveUri, selectBalance } from 'lbry-redux'; + +import RepostPage from './view'; + +const select = (state, props) => ({ + balance: selectBalance(state), +}); + +const perform = dispatch => ({ + resolveUri: uri => dispatch(doResolveUri(uri)), +}); + +export default connect(select, perform)(RepostPage); diff --git a/ui/page/repost/view.jsx b/ui/page/repost/view.jsx new file mode 100644 index 0000000..b1e2e10 --- /dev/null +++ b/ui/page/repost/view.jsx @@ -0,0 +1,77 @@ +// @flow +import React from 'react'; +import Page from 'component/page'; +import { useHistory } from 'react-router'; +import RepostCreate from 'component/repostCreate'; +import YrblWalletEmpty from 'component/yrblWalletEmpty'; +import useThrottle from 'effects/use-throttle'; +import classnames from 'classnames'; + +type Props = { + balance: number, + resolveUri: string => void, +}; +function RepostPage(props: Props) { + const { balance, resolveUri } = props; + + const REPOST_FROM = 'from'; + const REPOST_TO = 'to'; + const REDIRECT = 'redirect'; + const { + location: { search }, + } = useHistory(); + + const urlParams = new URLSearchParams(search); + const repostFrom = urlParams.get(REPOST_FROM); + const redirectUri = urlParams.get(REDIRECT); + const repostTo = urlParams.get(REPOST_TO); + const [contentUri, setContentUri] = React.useState(''); + const [repostUri, setRepostUri] = React.useState(''); + const throttledContentValue = useThrottle(contentUri, 500); + const throttledRepostValue = useThrottle(repostUri, 500); + + React.useEffect(() => { + if (throttledContentValue) { + resolveUri(throttledContentValue); + } + }, [throttledContentValue, resolveUri]); + + React.useEffect(() => { + if (throttledRepostValue) { + resolveUri(throttledRepostValue); + } + }, [throttledRepostValue, resolveUri]); + + React.useEffect(() => { + if (repostTo) { + resolveUri(repostTo); + } + }, [repostTo, resolveUri]); + + const decodedFrom = repostFrom && decodeURIComponent(repostFrom); + return ( + + {balance === 0 && } +
+ +
+
+ ); +} + +export default RepostPage; diff --git a/ui/page/rewards/index.js b/ui/page/rewards/index.js new file mode 100644 index 0000000..9c13ece --- /dev/null +++ b/ui/page/rewards/index.js @@ -0,0 +1,22 @@ +import { connect } from 'react-redux'; +import { selectUser } from 'redux/selectors/user'; +import { selectFetchingRewards, selectUnclaimedRewards, selectClaimedRewards } from 'redux/selectors/rewards'; +import { doUserFetch } from 'redux/actions/user'; +import { doRewardList } from 'redux/actions/rewards'; +import { selectDaemonSettings } from 'redux/selectors/settings'; +import RewardsPage from './view'; + +const select = state => ({ + daemonSettings: selectDaemonSettings(state), + fetching: selectFetchingRewards(state), + rewards: selectUnclaimedRewards(state), + claimed: selectClaimedRewards(state), + user: selectUser(state), +}); + +const perform = dispatch => ({ + fetchRewards: () => dispatch(doRewardList()), + fetchUser: () => dispatch(doUserFetch()), +}); + +export default connect(select, perform)(RewardsPage); diff --git a/ui/page/rewards/view.jsx b/ui/page/rewards/view.jsx new file mode 100644 index 0000000..0519b07 --- /dev/null +++ b/ui/page/rewards/view.jsx @@ -0,0 +1,181 @@ +// @flow +import * as PAGES from 'constants/pages'; +import React, { PureComponent } from 'react'; +import BusyIndicator from 'component/common/busy-indicator'; +import RewardListClaimed from 'component/rewardListClaimed'; +import RewardTile from 'component/rewardTile'; +import Button from 'component/button'; +import Page from 'component/page'; +import classnames from 'classnames'; +import REWARD_TYPES from 'rewards'; +import RewardAuthIntro from 'component/rewardAuthIntro'; +import Card from 'component/common/card'; +import I18nMessage from 'component/i18nMessage'; +import { SITE_HELP_EMAIL, SITE_NAME } from 'config'; + +type Props = { + doAuth: () => void, + fetchRewards: () => void, + fetchUser: () => void, + fetching: boolean, + rewards: Array, + claimed: Array, + user: ?{ + is_identity_verified: boolean, + is_reward_approved: boolean, + primary_email: string, + has_verified_email: boolean, + }, + daemonSettings: { + share_usage_data: boolean, + }, +}; + +class RewardsPage extends PureComponent { + componentDidMount() { + const { user, fetchUser, fetchRewards } = this.props; + const rewardsApproved = user && user.is_reward_approved; + + fetchRewards(); + if (!rewardsApproved) { + fetchUser(); + } + } + + renderPageHeader() { + const { user, daemonSettings, fetchUser } = this.props; + const rewardsEnabled = IS_WEB || (daemonSettings && daemonSettings.share_usage_data); + + if (user && !user.is_reward_approved && rewardsEnabled) { + if (!user.primary_email || !user.has_verified_email || !user.is_identity_verified) { + return ( +
+ +
+ ); + } + + return ( + +

+ {__( + 'This account must undergo review before you can participate in the rewards program. Not all users and regions may qualify.' + )}{' '} + {__('This can take anywhere from a few hours to several days. Please be patient.')} +

+ +

+ {__( + 'We apologize for this inconvenience, but have added this additional step to prevent abuse. Users on VPN or shared connections will continue to see this message and are not eligible for Rewards.' + )} +

+

+ , + help_email: SITE_HELP_EMAIL, + site_name: SITE_NAME, + }} + > + Please review the %rewards_faq% for eligibility, and send us an email to %help_email% if you continue + to see this message. You can continue to use %site_name% without this feature. + + {`${__('Enjoy all the awesome free content in the meantime!')}`} +

+ + } + actions={ +
+
+ } + /> + ); + } + + return null; + } + + renderCustomRewardCode() { + return ( + + ); + } + + renderUnclaimedRewards() { + const { fetching, rewards, user, daemonSettings, claimed } = this.props; + + if (!IS_WEB && daemonSettings && !daemonSettings.share_usage_data) { + return ( +
+

{__('Rewards Disabled')}

+

+ }}> + Rewards are currently disabled for your account. Turn on diagnostic data sharing, in %settings%, to + re-enable them. + +

+
+ ); + } else if (fetching) { + return ; + } else if (user === null) { + return ( +

{__('This application is unable to earn rewards due to an authentication failure.')}

+ ); + } else if (!rewards || rewards.length <= 0) { + return ( + } + /> + ); + } + + const isNotEligible = !user || !user.primary_email || !user.has_verified_email || !user.is_reward_approved; + + return ( +
+ {rewards.map((reward) => ( + + ))} + {this.renderCustomRewardCode()} +
+ ); + } + + render() { + return ( + + {this.renderPageHeader()} +
{this.renderUnclaimedRewards()}
+ +
+ ); + } +} + +export default RewardsPage; diff --git a/ui/page/rewardsVerify/index.js b/ui/page/rewardsVerify/index.js new file mode 100644 index 0000000..132b260 --- /dev/null +++ b/ui/page/rewardsVerify/index.js @@ -0,0 +1,9 @@ +import { connect } from 'react-redux'; +import { selectUser } from 'redux/selectors/user'; +import RewardsVerifyPage from './view'; + +const select = state => ({ + user: selectUser(state), +}); + +export default connect(select, null)(RewardsVerifyPage); diff --git a/ui/page/rewardsVerify/view.jsx b/ui/page/rewardsVerify/view.jsx new file mode 100644 index 0000000..7720961 --- /dev/null +++ b/ui/page/rewardsVerify/view.jsx @@ -0,0 +1,29 @@ +// @flow +import React from 'react'; +import UserVerify from 'component/userVerify'; +import Page from 'component/page'; +import { useHistory } from 'react-router-dom'; + +type Props = { + user: ?User, +}; + +function RewardsVerifyPage(props: Props) { + const { user } = props; + const { goBack } = useHistory(); + const rewardsApproved = user && user.is_reward_approved; + + React.useEffect(() => { + if (rewardsApproved) { + goBack(); + } + }, [rewardsApproved]); + + return ( + + goBack()} /> + + ); +} + +export default RewardsVerifyPage; diff --git a/ui/page/search/index.js b/ui/page/search/index.js new file mode 100644 index 0000000..7be30b4 --- /dev/null +++ b/ui/page/search/index.js @@ -0,0 +1,49 @@ +import { connect } from 'react-redux'; +import { withRouter } from 'react-router'; +import { doSearch } from 'redux/actions/search'; +import { SIMPLE_SITE } from 'config'; +import { + selectIsSearching, + makeSelectSearchUris, + makeSelectQueryWithOptions, + selectSearchOptions, + makeSelectHasReachedMaxResultsLength, +} from 'redux/selectors/search'; +import { selectShowMatureContent } from 'redux/selectors/settings'; +import { selectUserVerifiedEmail } from 'redux/selectors/user'; +import SearchPage from './view'; + +const select = (state, props) => { + const showMature = selectShowMatureContent(state); + const urlParams = new URLSearchParams(props.location.search); + let urlQuery = urlParams.get('q') || null; + if (urlQuery) { + urlQuery = urlQuery.replace(/^lbry:\/\//i, '').replace(/\//, ' '); + } + const query = makeSelectQueryWithOptions( + urlQuery, + SIMPLE_SITE + ? { nsfw: false, isBackgroundSearch: false } + : showMature === false + ? { nsfw: false, isBackgroundSearch: false } + : { isBackgroundSearch: false } + )(state); + + const uris = makeSelectSearchUris(query)(state); + const hasReachedMaxResultsLength = makeSelectHasReachedMaxResultsLength(query)(state); + + return { + isSearching: selectIsSearching(state), + showNsfw: showMature, + uris: uris, + isAuthenticated: selectUserVerifiedEmail(state), + searchOptions: selectSearchOptions(state), + hasReachedMaxResultsLength: hasReachedMaxResultsLength, + }; +}; + +const perform = (dispatch) => ({ + search: (query, options) => dispatch(doSearch(query, options)), +}); + +export default withRouter(connect(select, perform)(SearchPage)); diff --git a/ui/page/search/view.jsx b/ui/page/search/view.jsx new file mode 100644 index 0000000..87731f2 --- /dev/null +++ b/ui/page/search/view.jsx @@ -0,0 +1,132 @@ +// @flow +import { SIMPLE_SITE, SHOW_ADS } from 'config'; +import React, { useEffect } from 'react'; +import { Lbry, parseURI, isNameValid } from 'lbry-redux'; +import ClaimList from 'component/claimList'; +import Page from 'component/page'; +import SearchOptions from 'component/searchOptions'; +import Ads from 'web/component/ads'; +import SearchTopClaim from 'component/searchTopClaim'; +import { formatLbryUrlForWeb } from 'util/url'; +import { useHistory } from 'react-router'; +import { SEARCH_PAGE_SIZE } from 'constants/search'; + +type AdditionalOptions = { + isBackgroundSearch: boolean, + nsfw?: boolean, + from?: number, +}; + +type Props = { + search: (string, AdditionalOptions) => void, + searchOptions: {}, + isSearching: boolean, + location: UrlLocation, + uris: Array, + showNsfw: boolean, + isAuthenticated: boolean, + hasReachedMaxResultsLength: boolean, +}; + +export default function SearchPage(props: Props) { + const { + search, + uris, + location, + isSearching, + showNsfw, + isAuthenticated, + searchOptions, + hasReachedMaxResultsLength, + } = props; + const { push } = useHistory(); + const urlParams = new URLSearchParams(location.search); + const urlQuery = urlParams.get('q') || ''; + const additionalOptions: AdditionalOptions = { isBackgroundSearch: false }; + const [from, setFrom] = React.useState(0); + + additionalOptions['nsfw'] = SIMPLE_SITE ? false : showNsfw; + additionalOptions['from'] = from; + + const modifiedUrlQuery = urlQuery.trim().replace(/\s+/g, '').replace(/:/g, '#'); + const uriFromQuery = `lbry://${modifiedUrlQuery}`; + + let streamName; + let isValid = true; + try { + ({ streamName } = parseURI(uriFromQuery)); + if (!isNameValid(streamName)) { + isValid = false; + } + } catch (e) { + isValid = false; + } + + let claimId; + // Navigate directly to a claim if a claim_id is pasted into the search bar + if (!/\s/.test(urlQuery) && urlQuery.length === 40) { + try { + const dummyUrlForClaimId = `x#${urlQuery}`; + ({ claimId } = parseURI(dummyUrlForClaimId)); + Lbry.claim_search({ claim_id: claimId }).then((res) => { + if (res.items && res.items.length) { + const claim = res.items[0]; + const url = formatLbryUrlForWeb(claim.canonical_url); + push(url); + } + }); + } catch (e) {} + } + + const stringifiedOptions = JSON.stringify(additionalOptions); + const stringifiedSearchOptions = JSON.stringify(searchOptions); + useEffect(() => { + if (urlQuery) { + const jsonOptions = JSON.parse(stringifiedOptions); + search(urlQuery, jsonOptions); + } + }, [search, urlQuery, stringifiedOptions, stringifiedSearchOptions]); + + function loadMore() { + if (!isSearching && !hasReachedMaxResultsLength) { + setFrom(from + SEARCH_PAGE_SIZE); + } + } + + function resetPage() { + setFrom(0); + } + + return ( + +
+ {urlQuery && ( + <> + {isValid && } + + } + injectedItem={ + SHOW_ADS && IS_WEB ? (SIMPLE_SITE ? false : !isAuthenticated && ) : false + } + /> + +
{__('These search results are provided by LBRY, Inc.')}
+ + )} +
+
+ ); +} diff --git a/ui/page/send/index.js b/ui/page/send/index.js new file mode 100644 index 0000000..80835d5 --- /dev/null +++ b/ui/page/send/index.js @@ -0,0 +1,6 @@ +import { connect } from 'react-redux'; +import SendPage from './view'; + +const select = (state) => ({}); + +export default connect(select, null)(SendPage); diff --git a/ui/page/send/view.jsx b/ui/page/send/view.jsx new file mode 100644 index 0000000..dbab048 --- /dev/null +++ b/ui/page/send/view.jsx @@ -0,0 +1,139 @@ +// @flow +import React from 'react'; +import Page from 'component/page'; +import LbcSymbol from 'component/common/lbc-symbol'; +import WalletSend from 'component/walletSend'; +import { URL as SITE_URL, URL_LOCAL, URL_DEV } from 'config'; +import { parseURI, isNameValid, isURIValid, normalizeURI } from 'lbry-redux'; + +type Props = {}; + +export default function SendPage(props: Props) { + const [isAddress, setIsAddress] = React.useState(true); + const [contentUri, setContentUri] = React.useState(''); + const [draftTransaction, setDraftTransaction] = React.useState({ address: '', amount: '' }); + const [enteredContent, setEnteredContentUri] = React.useState(undefined); + const contentFirstRender = React.useRef(true); + const [contentError, setContentError] = React.useState(''); + const [confirmed, setConfirmed] = React.useState(false); + const [sendLabel, setSendLabel] = React.useState('Send'); + + function getSearchUri(value) { + const WEB_DEV_PREFIX = `${URL_DEV}/`; + const WEB_LOCAL_PREFIX = `${URL_LOCAL}/`; + const WEB_PROD_PREFIX = `${SITE_URL}/`; + const ODYSEE_PREFIX = `https://odysee.com/`; + const includesLbryTvProd = value.includes(WEB_PROD_PREFIX); + const includesOdysee = value.includes(ODYSEE_PREFIX); + const includesLbryTvLocal = value.includes(WEB_LOCAL_PREFIX); + const includesLbryTvDev = value.includes(WEB_DEV_PREFIX); + const wasCopiedFromWeb = includesLbryTvDev || includesLbryTvLocal || includesLbryTvProd || includesOdysee; + const isLbryUrl = value.startsWith('lbry://') && value !== 'lbry://'; + const error = ''; + + const addLbryIfNot = term => { + return term.startsWith('lbry://') ? term : `lbry://${term}`; + }; + if (wasCopiedFromWeb) { + let prefix = WEB_PROD_PREFIX; + if (includesLbryTvLocal) prefix = WEB_LOCAL_PREFIX; + if (includesLbryTvDev) prefix = WEB_DEV_PREFIX; + if (includesOdysee) prefix = ODYSEE_PREFIX; + + let query = (value && value.slice(prefix.length).replace(/:/g, '#')) || ''; + try { + const lbryUrl = `lbry://${query}`; + parseURI(lbryUrl); + return [lbryUrl, null]; + } catch (e) { + return [query, 'error']; + } + } + + if (!isLbryUrl) { + if (value.startsWith('@')) { + if (isNameValid(value.slice(1))) { + return [value, null]; + } else { + return [value, error]; + } + } + return [addLbryIfNot(value), null]; + } else { + try { + const isValid = isURIValid(value); + if (isValid) { + let uri; + try { + uri = normalizeURI(value); + } catch (e) { + return [value, null]; + } + return [uri, null]; + } else { + return [value, null]; + } + } catch (e) { + return [value, 'error']; + } + } + } + + // setContentUri given enteredUri + React.useEffect(() => { + if (!enteredContent && !contentFirstRender.current) { + setContentError(__('A name is required')); + } + if (enteredContent) { + contentFirstRender.current = false; + const [searchContent, error] = getSearchUri(enteredContent); + if (error) { + setContentError(__('Something not quite right..')); + } else { + setContentError(''); + } + try { + const { streamName, channelName, isChannel } = parseURI(searchContent); + if (!isChannel && streamName && isNameValid(streamName)) { + // contentNameValid = true; + setContentUri(searchContent); + } else if (isChannel && channelName && isNameValid(channelName)) { + // contentNameValid = true; + setContentUri(searchContent); + } + } catch (e) { + if (enteredContent !== '@') setContentError(''); + setContentUri(``); + } + } + }, [enteredContent, setContentUri, setContentError, parseURI, isNameValid]); + + return ( + + + + ), + }} + > + + + ); +} diff --git a/ui/page/settings/index.js b/ui/page/settings/index.js new file mode 100644 index 0000000..c30d53f --- /dev/null +++ b/ui/page/settings/index.js @@ -0,0 +1,58 @@ +import { connect } from 'react-redux'; +import { doClearCache, doNotifyForgetPassword, doToggle3PAnalytics, doOpenModal } from 'redux/actions/app'; +import { selectAllowAnalytics } from 'redux/selectors/app'; +import { + doSetDaemonSetting, + doClearDaemonSetting, + doSetClientSetting, + doSetDarkTime, + doEnterSettingsPage, + doExitSettingsPage, +} from 'redux/actions/settings'; +import { doSetPlayingUri } from 'redux/actions/content'; +import { + makeSelectClientSetting, + selectDaemonSettings, + selectLanguage, + selectShowMatureContent, +} from 'redux/selectors/settings'; +import { doWalletStatus, selectMyChannelUrls, selectWalletIsEncrypted, SETTINGS } from 'lbry-redux'; +import SettingsPage from './view'; +import { selectUserVerifiedEmail } from 'redux/selectors/user'; + +const select = (state) => ({ + daemonSettings: selectDaemonSettings(state), + allowAnalytics: selectAllowAnalytics(state), + isAuthenticated: selectUserVerifiedEmail(state), + showNsfw: selectShowMatureContent(state), + currentTheme: makeSelectClientSetting(SETTINGS.THEME)(state), + themes: makeSelectClientSetting(SETTINGS.THEMES)(state), + automaticDarkModeEnabled: makeSelectClientSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED)(state), + clock24h: makeSelectClientSetting(SETTINGS.CLOCK_24H)(state), + autoplay: makeSelectClientSetting(SETTINGS.AUTOPLAY)(state), + walletEncrypted: selectWalletIsEncrypted(state), + autoDownload: makeSelectClientSetting(SETTINGS.AUTO_DOWNLOAD)(state), + hideBalance: makeSelectClientSetting(SETTINGS.HIDE_BALANCE)(state), + floatingPlayer: makeSelectClientSetting(SETTINGS.FLOATING_PLAYER)(state), + hideReposts: makeSelectClientSetting(SETTINGS.HIDE_REPOSTS)(state), + darkModeTimes: makeSelectClientSetting(SETTINGS.DARK_MODE_TIMES)(state), + language: selectLanguage(state), + myChannelUrls: selectMyChannelUrls(state), +}); + +const perform = (dispatch) => ({ + setDaemonSetting: (key, value) => dispatch(doSetDaemonSetting(key, value)), + clearDaemonSetting: (key) => dispatch(doClearDaemonSetting(key)), + toggle3PAnalytics: (allow) => dispatch(doToggle3PAnalytics(allow)), + clearCache: () => dispatch(doClearCache()), + setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)), + updateWalletStatus: () => dispatch(doWalletStatus()), + confirmForgetPassword: (modalProps) => dispatch(doNotifyForgetPassword(modalProps)), + clearPlayingUri: () => dispatch(doSetPlayingUri({ uri: null })), + setDarkTime: (time, options) => dispatch(doSetDarkTime(time, options)), + openModal: (id, params) => dispatch(doOpenModal(id, params)), + enterSettings: () => dispatch(doEnterSettingsPage()), + exitSettings: () => dispatch(doExitSettingsPage()), +}); + +export default connect(select, perform)(SettingsPage); diff --git a/ui/page/settings/view.jsx b/ui/page/settings/view.jsx new file mode 100644 index 0000000..cb7e86a --- /dev/null +++ b/ui/page/settings/view.jsx @@ -0,0 +1,531 @@ +// @flow +import * as PAGES from 'constants/pages'; +import * as MODALS from 'constants/modal_types'; +import * as ICONS from 'constants/icons'; +import * as React from 'react'; +import { SETTINGS } from 'lbry-redux'; +import { FormField } from 'component/common/form'; +import Button from 'component/button'; +import Page from 'component/page'; +import SettingLanguage from 'component/settingLanguage'; +import FileSelector from 'component/common/file-selector'; +import SyncToggle from 'component/syncToggle'; +import HomepageSelector from 'component/homepageSelector'; +import Card from 'component/common/card'; +import SettingAccountPassword from 'component/settingAccountPassword'; +import classnames from 'classnames'; +import { getPasswordFromCookie } from 'util/saved-passwords'; +// $FlowFixMe +import homepages from 'homepages'; +import { Lbryio } from 'lbryinc'; +import Yrbl from 'component/yrbl'; + +type Price = { + currency: string, + amount: number, +}; + +type SetDaemonSettingArg = boolean | string | number; + +type DarkModeTimes = { + from: { hour: string, min: string, formattedTime: string }, + to: { hour: string, min: string, formattedTime: string }, +}; + +type OptionTimes = { + fromTo: string, + time: string, +}; + +type DaemonSettings = { + download_dir: string, + share_usage_data: boolean, +}; + +type Props = { + setDaemonSetting: (string, ?SetDaemonSettingArg) => void, + clearDaemonSetting: (string) => void, + setClientSetting: (string, SetDaemonSettingArg) => void, + toggle3PAnalytics: (boolean) => void, + clearCache: () => Promise, + daemonSettings: DaemonSettings, + allowAnalytics: boolean, + showNsfw: boolean, + isAuthenticated: boolean, + instantPurchaseEnabled: boolean, + instantPurchaseMax: Price, + currentTheme: string, + themes: Array, + automaticDarkModeEnabled: boolean, + clock24h: boolean, + autoplay: boolean, + updateWalletStatus: () => void, + walletEncrypted: boolean, + confirmForgetPassword: ({}) => void, + floatingPlayer: boolean, + hideReposts: ?boolean, + clearPlayingUri: () => void, + darkModeTimes: DarkModeTimes, + setDarkTime: (string, {}) => void, + openModal: (string) => void, + language?: string, + enterSettings: () => void, + exitSettings: () => void, + myChannelUrls: ?Array, +}; + +type State = { + clearingCache: boolean, + storedPassword: boolean, +}; + +class SettingsPage extends React.PureComponent { + constructor(props: Props) { + super(props); + + this.state = { + clearingCache: false, + storedPassword: false, + }; + + (this: any).onThemeChange = this.onThemeChange.bind(this); + (this: any).onAutomaticDarkModeChange = this.onAutomaticDarkModeChange.bind(this); + (this: any).onChangeTime = this.onChangeTime.bind(this); + (this: any).onConfirmForgetPassword = this.onConfirmForgetPassword.bind(this); + } + + componentDidMount() { + const { isAuthenticated, enterSettings } = this.props; + + if (isAuthenticated || !IS_WEB) { + this.props.updateWalletStatus(); + getPasswordFromCookie().then((p) => { + if (typeof p === 'string') { + this.setState({ storedPassword: true }); + } + }); + } + enterSettings(); + } + + componentWillUnmount() { + const { exitSettings } = this.props; + exitSettings(); + } + + onThemeChange(event: SyntheticInputEvent<*>) { + const { value } = event.target; + + if (value === 'dark') { + this.onAutomaticDarkModeChange(false); + } + + this.props.setClientSetting(SETTINGS.THEME, value); + } + + onAutomaticDarkModeChange(value: boolean) { + this.props.setClientSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED, value); + } + + onClock24hChange(value: boolean) { + this.props.setClientSetting(SETTINGS.CLOCK_24H, value); + } + + onConfirmForgetPassword() { + const { confirmForgetPassword } = this.props; + confirmForgetPassword({ + callback: () => { + this.setState({ storedPassword: false }); + }, + }); + } + + onChangeTime(event: SyntheticInputEvent<*>, options: OptionTimes) { + const { value } = event.target; + + this.props.setDarkTime(value, options); + } + + formatHour(time: string, clock24h: boolean) { + if (clock24h) { + return `${time}:00`; + } + + const now = new Date(0, 0, 0, Number(time)); + + const hour = now.toLocaleTimeString('en-US', { hour12: true, hour: '2-digit' }); + + return hour; + } + + setDaemonSetting(name: string, value: ?SetDaemonSettingArg): void { + this.props.setDaemonSetting(name, value); + } + + clearDaemonSetting(name: string): void { + this.props.clearDaemonSetting(name); + } + + render() { + const { + daemonSettings, + allowAnalytics, + showNsfw, + isAuthenticated, + currentTheme, + themes, + automaticDarkModeEnabled, + clock24h, + autoplay, + walletEncrypted, + // autoDownload, + setDaemonSetting, + setClientSetting, + toggle3PAnalytics, + floatingPlayer, + hideReposts, + clearPlayingUri, + darkModeTimes, + clearCache, + openModal, + myChannelUrls, + } = this.props; + const { storedPassword } = this.state; + const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0; + const startHours = ['18', '19', '20', '21']; + const endHours = ['5', '6', '7', '8']; + + return ( + + } /> + {homepages && Object.keys(homepages).length > 1 && ( + } /> + )} + + {!isAuthenticated && IS_WEB && ( +
+ +
+ } + /> + + )} + + {!IS_WEB && noDaemonSettings ? ( +
+
{__('Failed to load settings.')}
+
+ ) : ( +
+ {isAuthenticated && } + {/* @if TARGET='app' */} + + { + setDaemonSetting('download_dir', newDirectory.path); + }} + /> +

{__('LBRY downloads will be saved here.')}

+ + } + /> + } + /> + {/* @endif */} + + + + + {themes.map((theme) => ( + + ))} + + + + this.onAutomaticDarkModeChange(!automaticDarkModeEnabled)} + checked={automaticDarkModeEnabled} + label={__('Automatic dark mode')} + /> + {automaticDarkModeEnabled && ( + + this.onChangeTime(value, { fromTo: 'from', time: 'hour' })} + value={darkModeTimes.from.hour} + label={__('From --[initial time]--')} + > + {startHours.map((time) => ( + + ))} + + this.onChangeTime(value, { fromTo: 'to', time: 'hour' })} + value={darkModeTimes.to.hour} + > + {endHours.map((time) => ( + + ))} + + + )} + + + this.onClock24hChange(!clock24h)} + checked={clock24h} + label={__('24-hour clock')} + /> + + + } + /> + + + { + setClientSetting(SETTINGS.FLOATING_PLAYER, !floatingPlayer); + clearPlayingUri(); + }} + checked={floatingPlayer} + label={__('Floating video player')} + helper={__('Keep content playing in the corner when navigating to a different page.')} + /> + + setClientSetting(SETTINGS.AUTOPLAY, !autoplay)} + checked={autoplay} + label={__('Autoplay media files')} + helper={__( + 'Autoplay video and audio files when navigating to a file, as well as the next related item when a file finishes playing.' + )} + /> + + { + if (isAuthenticated) { + let param = e.target.checked ? { add: 'noreposts' } : { remove: 'noreposts' }; + Lbryio.call('user_tag', 'edit', param); + } + + setClientSetting(SETTINGS.HIDE_REPOSTS, !hideReposts); + }} + checked={hideReposts} + label={__('Hide reposts')} + helper={__('You will not see reposts by people you follow or receive email notifying about them.')} + /> + + {/* setClientSetting(SETTINGS.SHOW_ANONYMOUS, !showAnonymous)} + checked={showAnonymous} + label={__('Show anonymous content')} + helper={__('Anonymous content is published without a channel.')} + /> */} + + + !IS_WEB || showNsfw + ? setClientSetting(SETTINGS.SHOW_MATURE, !showNsfw) + : openModal(MODALS.CONFIRM_AGE) + } + checked={showNsfw} + label={__('Show mature content')} + helper={__( + 'Mature content may include nudity, intense sexuality, profanity, or other adult content. By displaying mature content, you are affirming you are of legal age to view mature content in your country or jurisdiction. ' + )} + /> + + } + /> + + {/* @if TARGET='app' */} + + {__( + `This is information like error logging, performance tracking, and usage statistics. It includes your IP address and basic system details, but no other identifying information (unless you sign in to lbry.tv)` + )}{' '} +
+ } + /> + + +