diff --git a/.env.defaults b/.env.defaults index 6cf3b315682..7dcfcfcce17 100644 --- a/.env.defaults +++ b/.env.defaults @@ -18,6 +18,7 @@ SITE_TITLE=lbry.tv SITE_NAME=LBRY SITE_DESCRIPTION=Meet LBRY, an open, free, and community-controlled content wonderland. LOGO_TITLE=lbry.tv +SIMPLE_SITE=false # OG OG_TITLE_SUFFIX=| lbry.tv @@ -30,6 +31,8 @@ DEFAULT_LANGUAGE=en # 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://@lbrycast#4c29f8b013adea4d5cca1861fb2161d5089613ea lbry://@lbry#3fda836a92faaceedfe398225fb9b2ee2ed1f01a # Add up to 2 sidebar links: # PINNED_URI_1=@Lbrylatam#2/Integracionesporseguridad#4 # PINNED_LABEL_1=LBRY LATAM diff --git a/.flowconfig b/.flowconfig index 0d771cc940b..a399c31e834 100644 --- a/.flowconfig +++ b/.flowconfig @@ -8,6 +8,10 @@ node_modules/lbry-redux/flow-typed/ node_modules/lbryinc/flow-typed/ +[untyped] +.*/node_modules/lbry-redux +.*/node_modules/lbryinc + [lints] [options] diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f2fbb54793..89a4a3376bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,38 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased on desktop] ### Added +- Block mature content when accessed directly from URL _community pr!_ ([#4560](https://github.com/lbryio/lbry-desktop/pull/4560)) -- Upload your files published via the desktop app to youtube ([#4491](https://github.com/lbryio/lbry-desktop/pull/4491)) +### Changed + +### 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)) + +## [0.47.1] - [2020-07-23] + +### Added + +- Allow zooming on Desktop _community pr!_ ([#4513](https://github.com/lbryio/lbry-desktop/pull/4513)) +- Show "YT Creator" label in File Page as well _community pr!_ ([#4523](https://github.com/lbryio/lbry-desktop/pull/4523)) +- Add option to retry video stream on failure _community pr!_ ([#4541](https://github.com/lbryio/lbry-desktop/pull/4541)) +- Allow blocking channels from comments ([#4557](https://github.com/lbryio/lbry-desktop/pull/4557)) + +### Changed + +- Updated lbry-sdk to [0.79.1](https://github.com/lbryio/lbry-sdk/releases/tag/v0.79.1) + +### Fixed + +- Fix 'transcoding' checkbox state when switching file types _community pr!_ ([#4529](https://github.com/lbryio/lbry-desktop/pull/4529)) +- Fix channel file-search not available in mobile _community pr!_ ([#4527](https://github.com/lbryio/lbry-desktop/pull/4527)) +- New Channel: Fix incorrect GUI configuration at entry _community pr!_ ([#4545](https://github.com/lbryio/lbry-desktop/pull/4545)) +- Hide blocked channels in comments ([#4557](https://github.com/lbryio/lbry-desktop/pull/4557)) + +## [0.47.0] - [2020-07-13] + +### Added + +- Add ability to sign supports ([#4382](https://github.com/lbryio/lbry-desktop/pull/4382)) - Add "tap to unmute" button for videos that start with audio muted _community pr!_ ([#4365](https://github.com/lbryio/lbry-desktop/pull/4365)) - Allow upgrade bar to be dismissed per session _community pr!_ ([#4413](https://github.com/lbryio/lbry-desktop/pull/4413)) - Pause the "autoplay next" timer when performing long operations such as Tipping, Supporting or commenting _community pr!_ ([4419](https://github.com/lbryio/lbry-desktop/pull/4419)) @@ -35,6 +65,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix "Refresh" on Publish page not showing the loading indicator when pressed _community pr!_ ([#4451](https://github.com/lbryio/lbry-desktop/pull/4451)) - Fix video duration not appearing on Mobile with enough width _community pr!_ ([#4452](https://github.com/lbryio/lbry-desktop/pull/4452)) - Fix video transcode setting not reflected correctly (MP3 incorrectly transcoded to MP4) _community pr!_ ([#4458](https://github.com/lbryio/lbry-desktop/pull/4458)) +- Fix scrolling glitch when results are exactly the page size _community pr!_ ([#4521](https://github.com/lbryio/lbry-desktop/pull/4521)) - Fix search results not appearing when scrolling due to long Tags or Following list in the navigation bar _community pr!_ ([#4465](https://github.com/lbryio/lbry-desktop/pull/4465)) - Fix unmuted state lost or reverted when playing a new video _community pr!_ ([#4483](https://github.com/lbryio/lbry-desktop/pull/4483)) diff --git a/README.md b/README.md index b6919388332..328c04bf000 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,9 @@ nano .env - To specify your own OG-IMAGE You can either place a png named v2-og.png in the /custom folder or specify the OG_IMAGE_URL in .env +- To specify your own channels to be followed on first run +`AUTO_FOLLOW_URLS=lbry://@chan#123...a lbry://@chan2#456...a` + - If you want to customize the homepage content 1. add `CUSTOM_HOMEPAGE=true` to the '.env' file diff --git a/build/signBuildFiles.js b/build/signBuildFiles.js index daf9b97a524..2bebc371a4d 100644 --- a/build/signBuildFiles.js +++ b/build/signBuildFiles.js @@ -126,16 +126,17 @@ function downloadAssets() { .then(({ data }) => { const release_id = data.id; - return octokit.repos.listAssetsForRelease({ + return octokit.repos.listReleases({ owner: 'lbryio', repo: 'lbry-desktop', release_id, }); }) .then(({ data }) => { - fileCountToDownload = data.length; - - data + const releaseToDownload = data.filter(releaseData => releaseData.tag_name === versionToSign)[0]; + const assets = releaseToDownload.assets; + fileCountToDownload = assets.length; + assets .map(({ browser_download_url, name }) => ({ download_url: browser_download_url, name })) .forEach(({ name, download_url }) => { const fileName = path.resolve(__dirname, `../dist/releaseDownloads/${name}`); diff --git a/config.js b/config.js index 30296682757..4e832532c2d 100644 --- a/config.js +++ b/config.js @@ -1,6 +1,6 @@ // On Web, this will find .env.defaults and optional .env in web/ // On Desktop App, this will find .env.defaults and optional .env in root dir -require('dotenv-defaults').config({silent: false}); +require('dotenv-defaults').config({ silent: false }); const config = { MATOMO_URL: process.env.MATOMO_URL, MATOMO_ID: process.env.MATOMO_ID, @@ -21,7 +21,8 @@ const config = { OG_IMAGE_URL: process.env.OG_IMAGE_URL, SITE_CANONICAL_URL: process.env.SITE_CANONICAL_URL, DEFAULT_LANGUAGE: process.env.DEFAULT_LANGUAGE, - + AUTO_FOLLOW_CHANNELS: process.env.AUTO_FOLLOW_CHANNELS, + SIMPLE_SITE: process.env.SIMPLE_SITE === 'true', PINNED_URI_1: process.env.PINNED_URI_1, PINNED_LABEL_1: process.env.PINNED_LABEL_1, PINNED_URI_2: process.env.PINNED_URI_2, diff --git a/electron/menu/setupBarMenu.js b/electron/menu/setupBarMenu.js index 794430a0c36..26f9bd602b3 100644 --- a/electron/menu/setupBarMenu.js +++ b/electron/menu/setupBarMenu.js @@ -1,4 +1,5 @@ import { app, Menu, shell } from 'electron'; +import { changeZoomFactor, ZOOM } from 'util/zoomWindow'; export default () => { const template = [ @@ -22,6 +23,38 @@ export default () => { label: 'View', submenu: [ { role: 'reload' }, + { + label: 'Zoom', + submenu: [ + { + label: 'Zoom In', + accelerator: 'CmdOrCtrl+=', + click: (menuItem, browserWindow) => { + if (browserWindow) { + browserWindow.webContents.send('zoom-window', ZOOM.INCREMENT); + } + }, + }, + { + label: 'Zoom Out', + accelerator: 'CmdOrCtrl+-', + click: (menuItem, browserWindow) => { + if (browserWindow) { + browserWindow.webContents.send('zoom-window', ZOOM.DECREMENT); + } + }, + }, + { + label: 'Reset Zoom', + accelerator: 'CmdOrCtrl+0', + click: (menuItem, browserWindow) => { + if (browserWindow) { + browserWindow.webContents.send('zoom-window', ZOOM.RESET); + } + }, + }, + ], + }, { label: 'Developer', submenu: [{ role: 'forcereload' }, { role: 'toggledevtools' }], diff --git a/flow-typed/notification.js b/flow-typed/notification.js new file mode 100644 index 00000000000..5d1f3f2bafd --- /dev/null +++ b/flow-typed/notification.js @@ -0,0 +1,31 @@ +// @flow +declare type WebNotification = { + active_at: string, + created_at: string, + id: number, + is_app_readable: boolean, + is_device_notified: boolean, + is_emailed: boolean, + is_read: boolean, + notification_parameters: { + device: { + analytics_label: string, + image_url: string, + is_data_only: boolean, + name: string, + placeholders: ?string, + target: string, + text: string, + title: string, + type: string, + }, + dynamic: { + comment_author: string, + }, + email: {}, + }, + notification_rule: string, + type: string, + updated_at: string, + user_id: number, +}; diff --git a/flow-typed/user.js b/flow-typed/user.js index bfb3142a3e3..b77bc64eee2 100644 --- a/flow-typed/user.js +++ b/flow-typed/user.js @@ -27,4 +27,5 @@ declare type User = { youtube_channels: ?Array, device_types: Array, lbry_first_approved: boolean, + experimental_ui: boolean, }; diff --git a/package.json b/package.json index 2823779042b..2ec8bdd6c91 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lbry", - "version": "0.47.0-rc.3", + "version": "0.47.1", "description": "A browser for the LBRY network, a digital marketplace controlled by its users.", "keywords": [ "lbry" @@ -71,7 +71,6 @@ "@datapunt/matomo-tracker-js": "^0.1.4", "@exponent/electron-cookies": "^2.0.0", "@hot-loader/react-dom": "^16.8", - "@lbry/components": "^4.2.5", "@reach/menu-button": "0.7.4", "@reach/rect": "^0.2.1", "@reach/tabs": "^0.1.5", @@ -136,7 +135,7 @@ "imagesloaded": "^4.1.4", "json-loader": "^0.5.4", "lbry-format": "https://github.com/lbryio/lbry-format.git", - "lbry-redux": "lbryio/lbry-redux#e6d89b06909b7f3a280e25625669f64ce06f340d", + "lbry-redux": "lbryio/lbry-redux#a1d5ce7e7e854c1c11e630609ef06a98e3b100c1", "lbryinc": "lbryio/lbryinc#cff5dd60934c4c6080e135f47ebbece1548c658c", "lint-staged": "^7.0.2", "localforage": "^1.7.1", @@ -193,7 +192,7 @@ "tiny-relative-date": "^1.3.0", "tree-kill": "^1.1.0", "unist-util-visit": "^1.4.1", - "video.js": "7.6.6", + "video.js": "7.8.4", "videojs-event-tracking": "^1.0.1", "villain-react": "^1.0.9", "wavesurfer.js": "^2.2.1", @@ -214,11 +213,11 @@ "yarn": "^1.3" }, "lbrySettings": { - "lbrynetDaemonVersion": "0.77.0", + "lbrynetDaemonVersion": "0.79.1", "lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip", "lbrynetDaemonDir": "static/daemon", "lbrynetDaemonFileName": "lbrynet", - "LBRYFirstVersion": "0.0.19", + "LBRYFirstVersion": "0.0.20", "LBRYFirstUrlTemplate": "https://github.com/lbryio/lbry-first/releases/download/vLBRYFIRSTVER/lbry-first_OSNAME_amd64.zip", "LBRYFirstDir": "static/lbry-first", "LBRYFirstFileName": "lbry-first" diff --git a/static/app-strings.json b/static/app-strings.json index 27447726ce1..6e7c03c5b72 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -17,7 +17,6 @@ "No results": "No results", "Home": "Home", "Subscriptions": "Subscriptions", - "Publishes": "Publishes", "Library": "Library", "Following": "Following", "The tags you follow will change what's trending for you.": "The tags you follow will change what's trending for you.", @@ -41,7 +40,6 @@ "Content": "Content", "FAQ": "FAQ", "Title": "Title", - "Titular Title": "Titular Title", "Description": "Description", "Description of your content": "Description of your content", "Price": "Price", @@ -69,7 +67,6 @@ "Malay": "Malay", "By continuing, you accept the %lbry_terms_of_service%.": "By continuing, you accept the %lbry_terms_of_service%.", "LBRY Terms of Service": "LBRY Terms of Service", - "Choose File": "Choose File", "No File Chosen": "No File Chosen", "Choose Thumbnail": "Choose Thumbnail", "Enter a thumbnail URL": "Enter a thumbnail URL", @@ -173,7 +170,6 @@ "Autoplay video and audio files when navigating to a file, as well as the next related item when a file finishes playing.": "Autoplay video and audio files when navigating to a file, as well as the next related item when a file finishes playing.", "Application Cache": "Application Cache", "Clear Cache": "Clear Cache", - "Choose Directory": "Choose Directory", "Currency": "Currency", "LBRY Credits (LBC)": "LBRY Credits (LBC)", "US Dollars": "US Dollars", @@ -282,7 +278,7 @@ "Facebook": "Facebook", "Twitter": "Twitter", "Done": "Done", - "You can't publish things quite yet": "You can't publish things quite yet", + "You can't upload things quite yet": "You can't upload things quite yet", "LBRY uses a blockchain, which is a fancy way of saying that users (you) are in control of your data.": "LBRY uses a blockchain, which is a fancy way of saying that users (you) are in control of your data.", "Because of the blockchain, some actions require LBRY credits": "Because of the blockchain, some actions require LBRY credits", "allows you to do some neat things, like paying your favorite creators for their content. And no company can stop you.": "allows you to do some neat things, like paying your favorite creators for their content. And no company can stop you.", @@ -295,15 +291,13 @@ "Checking the winning claim amount...": "Checking the winning claim amount...", "The better the tags, the easier your content is to find.": "The better the tags, the easier your content is to find.", "You aren't following any tags, try searching for one.": "You aren't following any tags, try searching for one.", - "Publishing...": "Publishing...", "Success": "Success", "File published": "File published", "You are currently editing a claim.": "You are currently editing a claim.", "You are currently editing this claim. If you change the URL, you will need to reselect a file.": "You are currently editing this claim. If you change the URL, you will need to reselect a file.", "However, you can get a longer version of this URL for any bid": "However, you can get a longer version of this URL for any bid", "It looks like you haven't published anything to LBRY yet.": "It looks like you haven't published anything to LBRY yet.", - "Publish something new": "Publish something new", - "View it on spee.ch": "View it on spee.ch", + "Upload something new": "Upload something new", "New thumbnail": "New thumbnail", "Follow": "Follow", "Claim sequence must be a number.": "Claim sequence must be a number.", @@ -315,7 +309,6 @@ "Upload Thumbnail": "Upload Thumbnail", "Confirm Thumbnail Upload": "Confirm Thumbnail Upload", "Upload": "Upload", - "Are you sure you want to upload this thumbnail to spee.ch": "Are you sure you want to upload this thumbnail to spee.ch", "Uploading thumbnail": "Uploading thumbnail", "Please wait for thumbnail to finish uploading": "Please wait for thumbnail to finish uploading", "API connection string": "API connection string", @@ -340,18 +333,15 @@ "Remove tag": "Remove tag", "Add tag": "Add tag", "No tags added": "No tags added", - "My description for this and that": "My description for this and that", "Choose a thumbnail": "Choose a thumbnail", "Take a snapshot from your video": "Take a snapshot from your video", "Upload your thumbnail to": "Upload your thumbnail to", "Add a price to this file": "Add a price to this file", + "All content fees are charged in LBC. For non-LBC payment methods, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase.": "All content fees are charged in LBC. For non-LBC payment methods, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase.", "Additional Options": "Additional Options", "A URL is required": "A URL is required", "A name is required": "A name is required", "The updates will take a few minutes to appear for other LBRY users. Until then they will be listed as \"pending\" under your published files.": "The updates will take a few minutes to appear for other LBRY users. Until then it will be listed as \"pending\" under your published files.", - "Your Publishes": "Your Publishes", - "New Publish": "New Publish", - "Your Library": "Your Library", "LBRY names cannot contain that symbol ($, #, @)": "LBRY names cannot contain that symbol ($, #, @)", "Path copied.": "Path copied.", "Open Folder": "Open Folder", @@ -361,15 +351,11 @@ "aprettygoodsite.com": "aprettygoodsite.com", "yourstruly@example.com": "yourstruly@example.com", "Editing": "Editing", - "Edit Your Channel": "Edit Your Channel", "Editing Your Channel": "Editing Your Channel", - "We can explain...": "We can explain...", - "Got it!": "Got it!", "Filter": "Filter", "Rendering document.": "Rendering document.", "Sorry, looks like we can't load the document.": "Sorry, looks like we can't load the document.", "Tag Search": "Tag Search", - "Rewards ": "Rewards ", "Fetching rewards": "Fetching rewards", "This application is unable to earn rewards due to an authentication failure.": "This application is unable to earn rewards due to an authentication failure.", "If you have a valid credit or debit card, you can use it to instantly prove your humanity.": "If you have a valid credit or debit card, you can use it to instantly prove your humanity.", @@ -377,19 +363,12 @@ "Perform Card Verification": "Perform Card Verification", "A $1 authorization may temporarily appear with your provider.": "A $1 authorization may temporarily appear with your provider.", "Read more about why we do this.": "Read more about why we do this.", - "You will receive an SMS text message confirming that your phone number is correct.": "You will receive an SMS text message confirming that your phone number is correct.", "Submit Phone Number": "Submit Phone Number", "Standard messaging rates apply. Having trouble?": "Standard messaging rates apply. Having trouble?", "A moderator capable of approving you is typically available in the discord server. Check out the #rewards-approval channel for more information.": "A moderator capable of approving you is typically available in the discord server. Check out the #rewards-approval channel for more information.", "This process will likely involve providing proof of a stable and established online or real-life identity.": "This process will likely involve providing proof of a stable and established online or real-life identity.", "Join LBRY Chat": "Join LBRY Chat", - "Or, Skip It Entirely": "Or, Skip It Entirely", - "You can continue without this step, but you will not be eligible to earn rewards.": "You can continue without this step, but you will not be eligible to earn rewards.", - "Skip Rewards": "Skip Rewards", - "Waiting For Verification": "Waiting For Verification", - "Follow the link and you will be good to go. This will update automatically.": "Follow the link and you will be good to go. This will update automatically.", "Blockchain Sync": "Blockchain Sync", - "Catching up with the blockchain": "Catching up with the blockchain", "No Rewards Available": "No Rewards Available", "You have claimed all available rewards! We're regularly adding more so be sure to check back later.": "You have claimed all available rewards! We're regularly adding more so be sure to check back later.", "There are no rewards available at this time, please check back later.": "There are no rewards available at this time, please check back later.", @@ -400,8 +379,6 @@ "This LBC remains yours. It is a deposit to reserve the name and can be undone at any time.": "This LBC remains yours. It is a deposit to reserve the name and can be undone at any time.", "Create channel": "Create channel", "Uh oh. The flux in our Retro Encabulator must be out of whack. Try refreshing to fix it.": "Uh oh. The flux in our Retro Encabulator must be out of whack. Try refreshing to fix it.", - "A few things to know before participating in the comment alpha:": "A few things to know before participating in the comment alpha:", - "During the alpha, all comments are sent to a LBRY, Inc. server, not the LBRY network itself.": "During the alpha, all comments are sent to a LBRY, Inc. server, not the LBRY network itself.", "Read the App Basics FAQ": "Read the App Basics FAQ", "View all LBRY FAQs": "View all LBRY FAQs", "Find Assistance": "Find Assistance", @@ -412,7 +389,6 @@ "Share On Twitter": "Share On Twitter", "View on lbry.tv": "View on lbry.tv", "Your Email - ": "Your Email - ", - "This information is disclosed only to LBRY, Inc. and not to the LBRY network. It is only required to save account information and earn rewards.": "This information is disclosed only to LBRY, Inc. and not to the LBRY network. It is only required to save account information and earn rewards.", "You will receive an SMS text message confirming that your phone number is correct. Does not work for Canada and possibly other regions": "You will receive an SMS text message confirming that your phone number is correct. Does not work for Canada and possibly other regions", "Standard messaging rates apply. LBRY will not text or call you otherwise. Having trouble?": "Standard messaging rates apply. LBRY will not text or call you otherwise. Having trouble?", "You currently have the highest bid for this name.": "You currently have the highest bid for this name.", @@ -429,10 +405,8 @@ "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. ": "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. ", "Encrypt my wallet with a custom password": "Encrypt my wallet with a custom password", "Enable claim support": "Enable claim support", - "vanity names": "vanity names", "Send LBC to your friends or favorite creators.": "Send LBC to your friends or favorite creators.", "Your Address": "Your Address", - "Send a tip to this creator": "Send a tip to this creator", "Support this claim": "Support this claim", "content viewing preferences": "content viewing preferences", "Encrypt Wallet": "Encrypt Wallet", @@ -460,7 +434,7 @@ "Redeem": "Redeem", "Code": "Code", "Nothing here": "Nothing here", - "Publish something and claim this spot!": "Publish something and claim this spot!", + "Upload something and claim this spot!": "Upload something and claim this spot!", "Currently, there is no automatic backup. If you lose access to these files, you will lose your credits, channels, and publishes.": "Currently, there is no automatic backup. If you lose access to these files, you will lose your credits, channels, and publishes.", "File Size": "File Size", "You deposited 1 LBC as a support!": "You deposited 1 LBC as a support!", @@ -542,7 +516,7 @@ "... in your publishes": "... in your publishes", "... in your supports": "... in your supports", "Add a tag": "Add a tag", - "Publish something totally wacky and wild.": "Publish something totally wacky and wild.", + "Upload something totally wacky and wild.": "Upload something totally wacky and wild.", "Available Rewards": "Available Rewards", "Nothing published to LBRY yet.": "Nothing published to LBRY yet.", "Follow New Tags": "Follow New Tags", @@ -598,7 +572,6 @@ "You must enter \"%acknowledgement_text%\"": "You must enter \"%acknowledgement_text%\"", "Decrypt Wallet": "Decrypt Wallet", "Your wallet has been encrypted with a local password, performing this action will remove this password.": "Your wallet has been encrypted with a local password, performing this action will remove this password.", - "Enter a LBRY URL or search for videos, music, games and more": "Enter a LBRY URL or search for videos, music, games and more", "This app will automatically download new free content from channels you are subscribed to. You may configure this in Settings or on the Subscriptions page.": "This app will automatically download new free content from channels you are subscribed to. You may configure this in Settings or on the Subscriptions page.", "(Only available on the desktop app.)": "(Only available on the desktop app.)", "If we have your email address, we will send you notifications related to new content. You may configure these emails from the Help page.": "If we have your email address, we will send you notifications related to new content. You may configure these emails from the Help page.", @@ -637,7 +610,7 @@ "Sign In to LBRY": "Sign In to LBRY", "Check Your Email": "Check Your Email", "sign in": "sign in", - "An email was sent to %email%. Follow the link to %verify_text%. This will update automatically.": "An email was sent to %email%. Follow the link to %verify_text%. This will update automatically.", + "An email was sent to %email%. Follow the link to %verify_text%.": "An email was sent to %email%. Follow the link to %verify_text%.", "Resend Email": "Resend Email", "Sync your balance and preferences across devices.": "Sync your balance and preferences across devices.", "Add Email": "Add Email", @@ -652,7 +625,6 @@ "Latest Transactions": "Latest Transactions", "Looks like you don't have any transactions.": "Looks like you don't have any transactions.", "If Sync is on, LBRY will backup your wallet and preferences. If disabled, you are responsible for keeping a backup.": "If Sync is on, LBRY will backup your wallet and preferences. If disabled, you are responsible for keeping a backup.", - "View My Publishes": "View My Publishes", "Your update is now pending on LBRY. It will take a few minutes to appear for other users.": "Your update is now pending on LBRY. It will take a few minutes to appear for other users.", "Your file is now pending on LBRY. It will take a few minutes to appear for other users.": "Your file is now pending on LBRY. It will take a few minutes to appear for other users.", "Upload will continue in the background, please do not shut down immediately. Leaving the app running helps the network, thank you!": "Upload will continue in the background, please do not shut down immediately. Leaving the app running helps the network, thank you!", @@ -755,7 +727,6 @@ "Your deposit must be higher": "Your deposit must be higher", "%view_count% views": "%view_count% views", "1 view": "1 view", - "Upload your thumbnail to %speech_link%. Recommended size is 16:9.": "Upload your thumbnail to %speech_link%. Recommended size is 16:9.", "Get %amount% LBC": "Get %amount% LBC", "Get %range% LBC": "Get %range% LBC", "Did something go wrong? Have a look in your log file, or send it to %support_link%.": "Did something go wrong? Have a look in your log file, or send it to %support_link%.", @@ -763,21 +734,17 @@ "%amount% fee": "%amount% fee", "1 file hidden due to your %content_viewing_preferences_link%": "1 file hidden due to your %content_viewing_preferences_link%", "Thumbnail": "Thumbnail", - "spee.ch": "spee.ch", "This Week": "This Week", "This Month": "This Month", "This Year": "This Year", "Khmer": "Khmer", "Invites": "Invites", - "This is an experiment, and may be removed in the future. Publish something with the #homepagecagematch tag to battle for the top spot on the home page!": "This is an experiment, and may be removed in the future. Publish something with the #homepagecagematch tag to battle for the top spot on the home page!", - "%claimsInChannel% publishes": "%claimsInChannel% publishes", - "%claimsInChannel% publish": "%claimsInChannel% publish", + "This is an experiment, and may be removed in the future. Upload something with the #homepagecagematch tag to battle for the top spot on the home page!": "This is an experiment, and may be removed in the future. Upload something with the #homepagecagematch tag to battle for the top spot on the home page!", "Publishing": "Publishing", "Update published": "Update published", "Delete this file from my computer": "Delete this file from my computer", "Are you sure you'd like to remove %title% from LBRY?": "Are you sure you'd like to remove %title% from LBRY?", "This will increase the overall bid amount for this content, which will boost its ability to be discovered while active.": "This will increase the overall bid amount for this content, which will boost its ability to be discovered while active.", - "Support %amount% LBC": "Support %amount% LBC", "You deposited %amount% LBC as a support!": "You deposited %amount% LBC as a support!", "LBRY Link": "LBRY Link", "Comment Acknowledgement": "Comment Acknowledgement", @@ -804,7 +771,8 @@ "Woohoo! Successfully reposted this claim.": "Woohoo! Successfully reposted this claim.", "There was an error reposting this claim. Please try again later.": "There was an error reposting this claim. Please try again later.", "Claim ID": "Claim ID", - "Official YouTube Creator - Last updated %time_ago%": "Official YouTube Creator - Last updated %time_ago%", + "Official YouTube Creator": "Official YouTube Creator", + "Official YouTube Creator - Last checked %time_ago%": "Official YouTube Creator - Last checked %time_ago%", "Install Now": "Install Now", "Invite Link": "Invite Link", "Share this link with friends (or enemies) and earn LBC when they join lbry.tv": "Share this link with friends (or enemies) and earn LBC when they join lbry.tv", @@ -847,7 +815,6 @@ "Let's go": "Let's go", "Do you agree to the %terms%?": "Do you agree to the %terms%?", "While we respect the desire for maximally private usage, please note that choosing this option hurts the ability for creators to understand how their content is performing.": "While we respect the desire for maximally private usage, please note that choosing this option hurts the ability for creators to understand how their content is performing.", - "A copy of your wallet is synced to lbry.tv": "A copy of your wallet is synced to lbry.tv", "Internal sharing is required while signed in.": "Internal sharing is required while signed in.", "FINAL WARNING: This action is permanent and cannot be undone.": "FINAL WARNING: This action is permanent and cannot be undone.", "This action is permanent and cannot be undone.": "This action is permanent and cannot be undone.", @@ -863,35 +830,22 @@ "Long": "Long", "Short": "Short", "How Fresh": "How Fresh", - "This Default": "This Default", "Image": "Image", "Model": "Model", - "Binary": "Binary", "Other": "Other", "You can try refreshing to fix it. If you still have issues, your anti-virus software or firewall may be preventing startup.": "You can try refreshing to fix it. If you still have issues, your anti-virus software or firewall may be preventing startup.", - "Add relevant tags...": "Add relevant tags...", - "Enter up to five (5) tags that are relevant to your content, and use the Mature tag as appropriate. Tag abuse will not be tolerated.": "Enter up to five (5) tags that are relevant to your content, and use the Mature tag as appropriate. Tag abuse will not be tolerated.", "gaming, crypto": "gaming, crypto", "Autocomplete": "Autocomplete", "Followed Tags": "Followed Tags", - "Add tags that are relevant to your content. If mature content, ensure it is tagged mature. Tag abuse and missing mature tags will not be tolerated.": "Add tags that are relevant to your content. If mature content, ensure it is tagged mature. Tag abuse and missing mature tags will not be tolerated.", "%selectTagsLabel% (%number% left)": "%selectTagsLabel% (%number% left)", "Matching": "Matching", - "No matching tags": "No matching tags", "Please check your deposit amount.": "Please check your deposit amount.", - "Checking your video...": "Checking your video...", - "Your video may not be the best format. Use MP4s in H264/AAC format and a friendly bitrate (1080p) for more reliable streaming.": "Your video may not be the best format. Use MP4s in H264/AAC format and a friendly bitrate (1080p) for more reliable streaming.", - "Publishing Guide": "Publishing Guide", + "Upload Guide": "Upload Guide", "This is equivalent to a password. Do not post or share this.": "This is equivalent to a password. Do not post or share this.", "Your video may not be the best format. Use MP4s in H264/AAC format and a friendly bitrate (720p) for more reliable streaming.": "Your video may not be the best format. Use MP4s in H264/AAC format and a friendly bitrate (720p) for more reliable streaming.", - "Your video has a bitrate over 6 mbps. We suggest transcoding to provide viewers the best experience.": "Your video has a bitrate over 6 mbps. We suggest transcoding to provide viewers the best experience.", "Transcoding": "Transcoding", "Optimize and transcode video": "Optimize and transcode video", - "FFmpeg not found": "FFmpeg not found", - "FFmpeg is correctly configured": "FFmpeg is correctly configured", - "ffmpeg not found": "ffmpeg not found", "Known Tags": "Known Tags", - "Your video has a bitrate over 5 mbps. We suggest transcoding to provide viewers the best experience.": "Your video has a bitrate over 5 mbps. We suggest transcoding to provide viewers the best experience.", "Almost there": "Almost there", "More Channels": "More Channels", "You aren’t blocking any channels": "You aren’t blocking any channels", @@ -901,13 +855,12 @@ "view all claims": "view all claims", "Top claims at lbry://%name%": "Top claims at lbry://%name%", "Last Updated": "Last Updated", - "Total Publishes": "Total Publishes", - "Are you sure you want to delete this channel?": "Are you sure you want to delete this channel?", "Are you sure? Type %name% to confirm that you wish to delete the channel.": "Are you sure? Type %name% to confirm that you wish to delete the channel.", "You're about to permanently delete a channel. Content published under this channel will be orphaned and their signing channel invalid. Content sync programs using this channel will fail.": "You're about to permanently delete a channel. Content published under this channel will be orphaned and their signing channel invalid. Content sync programs using this channel will fail.", "You are signed into lbry.tv which automatically shares data with LBRY inc. %signout_button%.": "You are signed into lbry.tv which automatically shares data with LBRY inc. %signout_button%.", "LBRY works better if you find and follow at least 5 creators you like. You can also block channels you never want to see.": "LBRY works better if you find and follow at least 5 creators you like. You can also block channels you never want to see.", "Nice! You are currently following %followingCount% creator": "Nice! You are currently following %followingCount% creator", + "Nice! You are currently following %followingCount% creators": "Nice! You are currently following %followingCount% creators", "You will receive notifications related to new content.": "You will receive notifications related to new content.", "Rewards Validation": "Rewards Validation", "Rewards Program": "Rewards Program", @@ -920,9 +873,9 @@ "rename your existing wallet in the lbry/wallets directory": "rename your existing wallet in the lbry/wallets directory", "Your wallet data will remain intact. If you sign in with a different account, the wallets will be merged. To prevent this, you need to %rename_wallet_instructions%": "Your wallet data will remain intact. If you sign in with a different account, the wallets will be merged. To prevent this, you need to %rename_wallet_instructions%", "rename your existing wallet": "rename your existing wallet", - "Your wallet data will remain intact. If you sign in with a different account, the wallets will be merged. To prevent this, you need to %rename_wallet_instructions% in the lbry/wallets directory": "Your wallet data will remain intact. If you sign in with a different account, the wallets will be merged. To prevent this, you need to %rename_wallet_instructions% in the lbry/wallets directory", "Your wallet data will remain intact. If you sign in with a different account, the wallets will be merged. To prevent this, you need to %rename_wallet_instructions% in the lbry/wallets directory.": "Your wallet data will remain intact. If you sign in with a different account, the wallets will be merged. To prevent this, you need to %rename_wallet_instructions% in the lbry/wallets directory.", "Your wallet": "Your wallet", + "Your Wallet": "Your Wallet", "Publish a file, or create a channel": "Publish a file, or create a channel", "Your account": "Your account", "Creator Analytics": "Creator Analytics", @@ -933,7 +886,6 @@ "Select some tags to help us show you interesting things.": "Select some tags to help us show you interesting things.", "You are currently following %followingCount% tags": "You are currently following %followingCount% tags", "Back": "Back", - "Nice! You are currently following %followingCount% creators": "Nice! You are currently following %followingCount% creators", "Experimental Transcoding": "Experimental Transcoding", "A Folder containing FFmpeg": "A Folder containing FFmpeg", "Check again": "Check again", @@ -955,19 +907,16 @@ "Amount cannot be more than available": "Amount cannot be more than available", "Amount to unlock": "Amount to unlock", "Unlock Tips": "Unlock Tips", - "%message%": "%message%", "Support This Claim": "Support This Claim", - "Send a tip to %url%": "Send a tip to %url%", "view other claims at lbry://%name%": "view other claims at lbry://%name%", - "loading": "loading", "Original Publish Amount": "Original Publish Amount", "Total Staked Amount": "Total Staked Amount", "Set Inviter": "Set Inviter", "Change Inviter": "Change Inviter", "Sign In to lbry.tv to Earn Rewards From Inviting Your Friends": "Sign In to lbry.tv to Earn Rewards From Inviting Your Friends", - "You haven't published anything with this channel yet!": "You haven't published anything with this channel yet!", + "You haven't uploaded anything with this channel yet!": "You haven't uploaded anything with this channel yet!", "You haven't created a channel yet, let's fix that!": "You haven't created a channel yet, let's fix that!", - "Publish Something": "Publish Something", + "Upload Something": "Upload Something", "Amount cannot be zero": "Amount cannot be zero", "Your content will do better with more staked on it": "Your content will do better with more staked on it", "She's about to close up the library!": "She's about to close up the library!", @@ -1034,7 +983,7 @@ "%lbc_received_changed% this week": "%lbc_received_changed% this week", "Earnings may also include any LBC you've sent yourself or added as support. We are working on making this more accurate. Check your wallet page for the correct total balance.": "Earnings may also include any LBC you've sent yourself or added as support. We are working on making this more accurate. Check your wallet page for the correct total balance.", "Your Recent Content": "Your Recent Content", - "No recent publishes found for this channel. Publish something new and track how it's performing here.": "No recent publishes found for this channel. Publish something new and track how it's performing here.", + "No recent uploads found for this channel. Upload something new and track how it's performing here.": "No recent uploads found for this channel. Upload something new and track how it's performing here.", "Most Viewed Content": "Most Viewed Content", "%all_time_top_views% views - %all_time_views_weekly_change% this week": "%all_time_top_views% views - %all_time_views_weekly_change% this week", "Successfully abandoned your support.": "Successfully abandoned your support.", @@ -1169,7 +1118,6 @@ "Your cart contains 1 item.": "Your cart contains 1 item.", "lbry.tv Premium - 1 month": "lbry.tv Premium - 1 month", "We will refund no questions asked within 30 days.": "We will refund no questions asked within 30 days.", - "Your Wallet": "Your Wallet", "Buy": "Buy", "buy": "buy", "Buy LBRY Credits": "Buy LBRY Credits", @@ -1200,6 +1148,7 @@ "No information will be sent directly to LBRY, Inc. or third-parties about your usage. Note that as\n peer-to-peer software, your IP address and potentially other system information can be sent to other\n users, though this information is not stored permanently.": "No information will be sent directly to LBRY, Inc. or third-parties about your usage. Note that as\n peer-to-peer software, your IP address and potentially other system information can be sent to other\n users, though this information is not stored permanently.", "%view_count% Views": "%view_count% Views", "Tap to unmute": "Tap to unmute", + "Retry": "Retry", "Playing in %seconds_left% seconds...": "Playing in %seconds_left% seconds...", "Autoplay timer paused.": "Autoplay timer paused.", "0 Bytes": "0 Bytes", @@ -1266,7 +1215,7 @@ "We can't find that email. Did you mean to register?": "We can't find that email. Did you mean to register?", "App Notifications": "App Notifications", "Notification settings for the desktop app.": "Notification settings for the desktop app.", - "Get notified when a publish or channel is confirmed.": "Get notified when a publish or channel is confirmed.", + "Get notified when an upload or channel is confirmed.": "Get notified when an upload or channel is confirmed.", "Email Preferences": "Email Preferences", "Opt out of any topics you don't want to receive email about.": "Opt out of any topics you don't want to receive email about.", "Uncheck your email below if you want to stop receiving messages.": "Uncheck your email below if you want to stop receiving messages.", @@ -1311,10 +1260,27 @@ "Links": "Links", "LBRY URL": "LBRY URL", "Download Link": "Download Link", + "Mature content blocked.": "Mature content blocked.", + "Change this in your %content_settings%.": "Change this in your %content_settings%.", + "content settings": "content settings", + "Autoplay next in list": "Autoplay next in list", + "Autoplay the next media file in the related list.": "Autoplay the next media file in the related list.", "There was an error with LBRY first publishing.": "There was an error with LBRY first publishing.", "Automagically upload to your youtube channel.": "Automagically upload to your youtube channel.", - "Your publish on LBRY was successful, but uploading to YouTube Failed.": "Your publish on LBRY was successful, but uploading to YouTube Failed.", - "Your publish on LBRY was successful, but the YouTube upload failed.": "Your publish on LBRY was successful, but the YouTube upload failed.", "Your file was published to LBRY, but the YouTube upload failed.": "Your file was published to LBRY, but the YouTube upload failed.", + "Your servers were not available. Check your url and port, or switch back to defaults.": "Your servers were not available. Check your url and port, or switch back to defaults.", + "LBRY Status": "LBRY Status", + "Check the status of various LBRY services.": "Check the status of various LBRY services.", + "Check Status": "Check Status", + "Upload your thumbnail to %domain%. Recommended size is 16:9.": "Upload your thumbnail to %domain%. Recommended size is 16:9.", + "Are you sure you want to upload this thumbnail to %domain%": "Are you sure you want to upload this thumbnail to %domain%", + "View thumbnail": "View thumbnail", + "These changes will appear shortly.": "These changes will appear shortly.", + "Block Channel": "Block Channel", + "Manage Notifications": "Manage Notifications", + "Uploads": "Uploads", + "Advanced Settings": "Advanced Settings", + "Browse": "Browse", + "Automatic Transcoding": "Automatic Transcoding", "--end--": "--end--" } diff --git a/ui/analytics.js b/ui/analytics.js index 5bec8710a26..f5c9630aef8 100644 --- a/ui/analytics.js +++ b/ui/analytics.js @@ -149,7 +149,8 @@ const analytics: Analytics = { } }, apiLogPublish: (claimResult: ChannelClaim | StreamClaim) => { - if (internalAnalyticsEnabled && isProduction) { + // Don't check if this is production so channels created on localhost are still linked to user + if (internalAnalyticsEnabled) { const { permanent_url: uri, claim_id: claimId, txid, nout, signing_channel: signingChannel } = claimResult; let channelClaimId; if (signingChannel) { diff --git a/ui/component/abandonedChannelPreview/index.js b/ui/component/abandonedChannelPreview/index.js index caec28e6257..a401da12fe3 100644 --- a/ui/component/abandonedChannelPreview/index.js +++ b/ui/component/abandonedChannelPreview/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { selectBlockedChannels } from 'lbry-redux'; +import { selectBlockedChannels } from 'redux/selectors/blocked'; import { doChannelUnsubscribe } from 'redux/actions/subscriptions'; import { doOpenModal } from 'redux/actions/app'; import AbandonedChannelPreview from './view'; diff --git a/ui/component/app/index.js b/ui/component/app/index.js index af954ce5831..98871dbb043 100644 --- a/ui/component/app/index.js +++ b/ui/component/app/index.js @@ -1,11 +1,10 @@ -import * as SETTINGS from 'constants/settings'; import { hot } from 'react-hot-loader/root'; import { connect } from 'react-redux'; import { selectGetSyncErrorMessage, selectUploadCount } from 'lbryinc'; import { doFetchAccessToken, doUserSetReferrer } from 'redux/actions/user'; import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUnclaimedRewards } from 'redux/selectors/rewards'; -import { doFetchChannelListMine } from 'lbry-redux'; +import { doFetchChannelListMine, SETTINGS } from 'lbry-redux'; import { makeSelectClientSetting, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings'; import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app'; import { doSetLanguage } from 'redux/actions/settings'; diff --git a/ui/component/app/view.jsx b/ui/component/app/view.jsx index d6330172065..0a5a1fd952d 100644 --- a/ui/component/app/view.jsx +++ b/ui/component/app/view.jsx @@ -17,6 +17,9 @@ import Nag from 'component/common/nag'; import REWARDS from 'rewards'; import usePersistedState from 'effects/use-persisted-state'; import FileDrop from 'component/fileDrop'; +// @if TARGET='app' +import useZoom from 'effects/use-zoom'; +// @endif // @if TARGET='web' import OpenInAppLink from 'web/component/openInAppLink'; import YoutubeWelcome from 'web/component/youtubeReferralWelcome'; @@ -74,6 +77,7 @@ type Props = { setReferrer: (string, boolean) => void, analyticsTagSync: () => void, isAuthenticated: boolean, + socketConnect: () => void, }; function App(props: Props) { @@ -104,10 +108,8 @@ function App(props: Props) { const appRef = useRef(); const isEnhancedLayout = useKonamiListener(); const [hasSignedIn, setHasSignedIn] = useState(false); - const userId = user && user.id; const hasVerifiedEmail = user && user.has_verified_email; const isRewardApproved = user && user.is_reward_approved; - const previousUserId = usePrevious(userId); const previousHasVerifiedEmail = usePrevious(hasVerifiedEmail); const previousRewardApproved = usePrevious(isRewardApproved); // @if TARGET='web' @@ -174,6 +176,11 @@ function App(props: Props) { return () => window.removeEventListener('keydown', handleKeyPress); }, []); + // Enable ctrl +/- zooming on Desktop. + // @if TARGET='app' + useZoom(); + // @endif + useEffect(() => { if (referredRewardAvailable && sanitizedReferrerParam && isRewardApproved) { setReferrer(sanitizedReferrerParam, true); @@ -188,10 +195,11 @@ function App(props: Props) { if (wrapperElement) { ReactModal.setAppElement(wrapperElement); } + fetchAccessToken(); // @if TARGET='app' - fetchChannelListMine(); // This needs to be done for web too... + fetchChannelListMine(); // This is fetched after a user is signed in on web // @endif }, [appRef, fetchAccessToken, fetchChannelListMine]); @@ -207,12 +215,6 @@ function App(props: Props) { // eslint-disable-next-line react-hooks/exhaustive-deps }, [language, languages]); - useEffect(() => { - if (previousUserId === undefined && userId) { - analytics.setUser(userId); - } - }, [previousUserId, userId]); - useEffect(() => { // Check that previousHasVerifiedEmail was not undefined instead of just not truthy // This ensures we don't fire the emailVerified event on the initial user fetch diff --git a/ui/component/autoplayCountdown/index.js b/ui/component/autoplayCountdown/index.js index e7d7670716d..68fdcf135f2 100644 --- a/ui/component/autoplayCountdown/index.js +++ b/ui/component/autoplayCountdown/index.js @@ -1,6 +1,5 @@ -import * as SETTINGS from 'constants/settings'; import { connect } from 'react-redux'; -import { makeSelectClaimForUri } from 'lbry-redux'; +import { makeSelectClaimForUri, SETTINGS } from 'lbry-redux'; import { withRouter } from 'react-router'; import { makeSelectIsPlayerFloating, makeSelectNextUnplayedRecommended } from 'redux/selectors/content'; import { makeSelectClientSetting } from 'redux/selectors/settings'; diff --git a/ui/component/blockButton/index.js b/ui/component/blockButton/index.js index 33653b2770b..7ac0212bfda 100644 --- a/ui/component/blockButton/index.js +++ b/ui/component/blockButton/index.js @@ -1,12 +1,8 @@ import { connect } from 'react-redux'; -import { - selectChannelIsBlocked, - doToggleBlockChannel, - makeSelectClaimIsMine, - makeSelectShortUrlForUri, - makeSelectPermanentUrlForUri, -} from 'lbry-redux'; +import { makeSelectClaimIsMine, makeSelectShortUrlForUri, makeSelectPermanentUrlForUri } from 'lbry-redux'; +import { selectChannelIsBlocked } from 'redux/selectors/blocked'; import { doToast } from 'redux/actions/notifications'; +import { doToggleBlockChannel } from 'redux/actions/blocked'; import BlockButton from './view'; const select = (state, props) => ({ diff --git a/ui/component/channelAbout/view.jsx b/ui/component/channelAbout/view.jsx index 94e16dd8044..9e0bc613cec 100644 --- a/ui/component/channelAbout/view.jsx +++ b/ui/component/channelAbout/view.jsx @@ -61,7 +61,7 @@ function ChannelAbout(props: Props) { - +
{claim.meta.claims_in_channel}
diff --git a/ui/component/channelContent/index.js b/ui/component/channelContent/index.js index 68390df9e6e..29cfaadc511 100644 --- a/ui/component/channelContent/index.js +++ b/ui/component/channelContent/index.js @@ -1,4 +1,3 @@ -import * as SETTINGS from 'constants/settings'; import { connect } from 'react-redux'; import { PAGE_SIZE } from 'constants/claim'; import { @@ -6,9 +5,10 @@ import { makeSelectFetchingChannelClaims, makeSelectClaimIsMine, makeSelectTotalPagesInChannelSearch, - selectChannelIsBlocked, makeSelectClaimForUri, + SETTINGS, } from 'lbry-redux'; +import { selectChannelIsBlocked } from 'redux/selectors/blocked'; import { withRouter } from 'react-router'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { makeSelectClientSetting } from 'redux/selectors/settings'; diff --git a/ui/component/channelContent/view.jsx b/ui/component/channelContent/view.jsx index 6eb79a6c6a5..b2a1977be7e 100644 --- a/ui/component/channelContent/view.jsx +++ b/ui/component/channelContent/view.jsx @@ -131,7 +131,7 @@ function ChannelContent(props: Props) {
{}} className="wunderbar--inline"> ({ thumbnail: makeSelectThumbnailForUri(props.uri)(state), + claim: makeSelectClaimForUri(props.uri)(state), }); -export default connect( - select, - null -)(ChannelThumbnail); +export default connect(select, { + doResolveUri, +})(ChannelThumbnail); diff --git a/ui/component/channelThumbnail/view.jsx b/ui/component/channelThumbnail/view.jsx index 499353f9363..b86fd1afb16 100644 --- a/ui/component/channelThumbnail/view.jsx +++ b/ui/component/channelThumbnail/view.jsx @@ -13,6 +13,8 @@ type Props = { obscure?: boolean, small?: boolean, allowGifs?: boolean, + claim: ?ChannelClaim, + doResolveUri: string => void, }; function ChannelThumbnail(props: Props) { @@ -24,8 +26,11 @@ function ChannelThumbnail(props: Props) { obscure, small = false, allowGifs = false, + claim, + doResolveUri, } = props; const [thumbError, setThumbError] = React.useState(false); + const shouldResolve = claim === undefined; const thumbnail = rawThumbnail && rawThumbnail.trim().replace(/^http:\/\//i, 'https://'); const thumbnailPreview = rawThumbnailPreview && rawThumbnailPreview.trim().replace(/^http:\/\//i, 'https://'); const channelThumbnail = thumbnail || thumbnailPreview; @@ -41,6 +46,12 @@ function ChannelThumbnail(props: Props) { colorClassName = `channel-thumbnail__default--4`; } + React.useEffect(() => { + if (shouldResolve && uri) { + doResolveUri(uri); + } + }, [doResolveUri, shouldResolve, uri]); + if (channelThumbnail && channelThumbnail.endsWith('gif') && !allowGifs) { return ; } diff --git a/ui/component/claimListDiscover/index.js b/ui/component/claimListDiscover/index.js index d59c1e81673..3f4f74c523b 100644 --- a/ui/component/claimListDiscover/index.js +++ b/ui/component/claimListDiscover/index.js @@ -2,11 +2,12 @@ import { connect } from 'react-redux'; import { doClaimSearch, selectClaimSearchByQuery, + selectClaimSearchByQueryLastPageReached, selectFetchingClaimSearch, - selectBlockedChannels, SETTINGS, selectFollowedTags, } from 'lbry-redux'; +import { selectBlockedChannels } from 'redux/selectors/blocked'; import { doToggleTagFollowDesktop } from 'redux/actions/tags'; import { makeSelectClientSetting } from 'redux/selectors/settings'; import ClaimListDiscover from './view'; @@ -14,6 +15,7 @@ import ClaimListDiscover from './view'; const select = state => ({ followedTags: selectFollowedTags(state), claimSearchByQuery: selectClaimSearchByQuery(state), + claimSearchByQueryLastPageReached: selectClaimSearchByQueryLastPageReached(state), loading: selectFetchingClaimSearch(state), showNsfw: makeSelectClientSetting(SETTINGS.SHOW_MATURE)(state), hideReposts: makeSelectClientSetting(SETTINGS.HIDE_REPOSTS)(state), diff --git a/ui/component/claimListDiscover/view.jsx b/ui/component/claimListDiscover/view.jsx index a4fe4cff18e..8f29a7a2b97 100644 --- a/ui/component/claimListDiscover/view.jsx +++ b/ui/component/claimListDiscover/view.jsx @@ -31,6 +31,7 @@ type Props = { claimSearchByQuery: { [string]: Array, }, + claimSearchByQueryLastPageReached: { [string]: boolean }, hiddenUris: Array, hiddenNsfwMessage?: Node, channelIds?: Array, @@ -63,6 +64,7 @@ function ClaimListDiscover(props: Props) { const { doClaimSearch, claimSearchByQuery, + claimSearchByQueryLastPageReached, tags, defaultTags, loading, @@ -103,7 +105,7 @@ function ClaimListDiscover(props: Props) { const [page, setPage] = useState(1); const [forceRefresh, setForceRefresh] = useState(); const [expanded, setExpanded] = usePersistedState(`expanded-${location.pathname}`, false); - const [orderParamEntry, setOrderParamEntry] = useState(CS.ORDER_BY_TRENDING); + const [orderParamEntry, setOrderParamEntry] = usePersistedState(`entry-${location.pathname}`, CS.ORDER_BY_TRENDING); const [orderParamUser, setOrderParamUser] = usePersistedState(`orderUser-${location.pathname}`, CS.ORDER_BY_TRENDING); const followed = (followedTags && followedTags.map(t => t.name)) || []; const urlParams = new URLSearchParams(search); @@ -155,7 +157,9 @@ function ClaimListDiscover(props: Props) { useEffect(() => { // One-time update to stash the finalized 'orderParam' at entry. - setOrderParamEntry(orderParam); + if (history.action !== 'POP') { + setOrderParamEntry(orderParam); + } }, []); let options: { @@ -297,6 +301,7 @@ function ClaimListDiscover(props: Props) { const hasMatureTags = tagsParam && tagsParam.split(',').some(t => MATURE_TAGS.includes(t)); const claimSearchCacheQuery = createNormalizedClaimSearchKey(options); const claimSearchResult = claimSearchByQuery[claimSearchCacheQuery]; + const claimSearchResultLastPageReached = claimSearchByQueryLastPageReached[claimSearchCacheQuery]; const [prevOptions, setPrevOptions] = useState(null); @@ -468,10 +473,7 @@ function ClaimListDiscover(props: Props) { function handleScrollBottom() { if (!loading && infiniteScroll) { - if (claimSearchResult && claimSearchResult.length % CS.PAGE_SIZE === 0) { - // Only increment the page if the current page is full. A partially-filled page probably - // indicates "no more search results" (at least based on my testing). Gating this prevents - // incrementing the page when scrolling upwards. + if (claimSearchResult && !claimSearchResultLastPageReached) { setPage(page + 1); } } diff --git a/ui/component/claimPreview/index.js b/ui/component/claimPreview/index.js index 20eeb0d2c1b..d80bd621fb4 100644 --- a/ui/component/claimPreview/index.js +++ b/ui/component/claimPreview/index.js @@ -7,13 +7,12 @@ import { makeSelectClaimIsPending, makeSelectCoverForUri, makeSelectClaimIsNsfw, - selectBlockedChannels, - selectChannelIsBlocked, doFileGet, makeSelectReflectingClaimForUri, makeSelectClaimWasPurchased, makeSelectStreamingUrlForUri, } from 'lbry-redux'; +import { selectBlockedChannels, selectChannelIsBlocked } from 'redux/selectors/blocked'; import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc'; import { selectShowMatureContent } from 'redux/selectors/settings'; import { makeSelectHasVisitedUri } from 'redux/selectors/content'; diff --git a/ui/component/claimPreviewSubtitle/index.js b/ui/component/claimPreviewSubtitle/index.js index b46f46880af..78a458c07ee 100644 --- a/ui/component/claimPreviewSubtitle/index.js +++ b/ui/component/claimPreviewSubtitle/index.js @@ -13,11 +13,8 @@ const perform = dispatch => ({ beginPublish: name => { dispatch(doClearPublish()); dispatch(doPrepareEdit({ name })); - dispatch(push(`/$/${PAGES.PUBLISH}`)); + dispatch(push(`/$/${PAGES.UPLOAD}`)); }, }); -export default connect( - select, - perform -)(ClaimPreviewSubtitle); +export default connect(select, perform)(ClaimPreviewSubtitle); diff --git a/ui/component/claimPreviewSubtitle/view.jsx b/ui/component/claimPreviewSubtitle/view.jsx index 131b33eb08e..830026040bc 100644 --- a/ui/component/claimPreviewSubtitle/view.jsx +++ b/ui/component/claimPreviewSubtitle/view.jsx @@ -34,7 +34,7 @@ function ClaimPreviewSubtitle(props: Props) { ) : ( -
{__('Publish something and claim this spot!')}
+
{__('Upload something and claim this spot!')}
diff --git a/ui/component/claimPreviewTile/index.js b/ui/component/claimPreviewTile/index.js index 997f5708ca8..9e6da683ce3 100644 --- a/ui/component/claimPreviewTile/index.js +++ b/ui/component/claimPreviewTile/index.js @@ -7,9 +7,9 @@ import { makeSelectTitleForUri, doFileGet, makeSelectChannelForClaimUri, - selectBlockedChannels, makeSelectClaimIsNsfw, } from 'lbry-redux'; +import { selectBlockedChannels } from 'redux/selectors/blocked'; import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc'; import { selectShowMatureContent } from 'redux/selectors/settings'; import ClaimPreviewTile from './view'; @@ -32,7 +32,4 @@ const perform = dispatch => ({ getFile: uri => dispatch(doFileGet(uri, false)), }); -export default connect( - select, - perform -)(ClaimPreviewTile); +export default connect(select, perform)(ClaimPreviewTile); diff --git a/ui/component/claimTilesDiscover/index.js b/ui/component/claimTilesDiscover/index.js index bfd8b94b48a..a549c501079 100644 --- a/ui/component/claimTilesDiscover/index.js +++ b/ui/component/claimTilesDiscover/index.js @@ -1,11 +1,6 @@ import { connect } from 'react-redux'; -import { - doClaimSearch, - selectClaimSearchByQuery, - selectFetchingClaimSearch, - selectBlockedChannels, - SETTINGS, -} from 'lbry-redux'; +import { doClaimSearch, selectClaimSearchByQuery, selectFetchingClaimSearch, SETTINGS } from 'lbry-redux'; +import { selectBlockedChannels } from 'redux/selectors/blocked'; import { doToggleTagFollowDesktop } from 'redux/actions/tags'; import { makeSelectClientSetting } from 'redux/selectors/settings'; import ClaimListDiscover from './view'; diff --git a/ui/component/comment/index.js b/ui/component/comment/index.js index 5fccbab3541..2f2c786ba17 100644 --- a/ui/component/comment/index.js +++ b/ui/component/comment/index.js @@ -5,10 +5,10 @@ import { makeSelectClaimForUri, makeSelectThumbnailForUri, makeSelectIsUriResolving, - selectChannelIsBlocked, - doCommentUpdate, // doEditComment would be a more fitting name - doCommentAbandon, } from 'lbry-redux'; +import { doCommentAbandon, doCommentUpdate } from 'redux/actions/comments'; +import { doToggleBlockChannel } from 'redux/actions/blocked'; +import { selectChannelIsBlocked } from 'redux/selectors/blocked'; import Comment from './view'; const select = (state, props) => ({ @@ -23,6 +23,7 @@ const perform = dispatch => ({ resolveUri: uri => dispatch(doResolveUri(uri)), updateComment: (commentId, comment) => dispatch(doCommentUpdate(commentId, comment)), deleteComment: commentId => dispatch(doCommentAbandon(commentId)), + blockChannel: channelUri => dispatch(doToggleBlockChannel(channelUri)), }); export default connect(select, perform)(Comment); diff --git a/ui/component/comment/view.jsx b/ui/component/comment/view.jsx index 8b9d25993e8..c0fdd26636f 100644 --- a/ui/component/comment/view.jsx +++ b/ui/component/comment/view.jsx @@ -1,4 +1,7 @@ // @flow +import * as ICONS from 'constants/icons'; +import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field'; +import { SIMPLE_SITE } from 'config'; import React, { useEffect, useState } from 'react'; import { isEmpty } from 'util/object'; import DateTime from 'component/dateTime'; @@ -8,12 +11,10 @@ import MarkdownPreview from 'component/common/markdown-preview'; import ChannelThumbnail from 'component/channelThumbnail'; import { Menu, MenuList, MenuButton, MenuItem } from '@reach/menu-button'; import Icon from 'component/common/icon'; -import * as ICONS from 'constants/icons'; import { FormField, Form } from 'component/common/form'; import CommentCreate from 'component/commentCreate'; import classnames from 'classnames'; import usePersistedState from 'effects/use-persisted-state'; -import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field'; type Props = { uri: string, @@ -32,6 +33,7 @@ type Props = { commentIsMine: boolean, // if this comment was signed by an owned channel updateComment: (string, string) => void, deleteComment: string => void, + blockChannel: string => void, }; const LENGTH_TO_COLLAPSE = 300; @@ -54,6 +56,7 @@ function Comment(props: Props) { parentId, updateComment, deleteComment, + blockChannel, } = props; const [isEditing, setEditing] = useState(false); @@ -98,12 +101,8 @@ function Comment(props: Props) { } }, [isResolvingUri, shouldFetch, author, authorUri, resolveUri, editedMessage, isEditing, setEditing]); - function handleSetEditing() { - setEditing(true); - } - function handleEditMessageChanged(event) { - setCommentValue(advancedEditor ? event : event.target.value); + setCommentValue(!SIMPLE_SITE && advancedEditor ? event : event.target.value); } function handleSubmit() { @@ -112,31 +111,11 @@ function Comment(props: Props) { setReplying(false); } - function handleDeleteComment() { - deleteComment(commentId); - } - - function handleReply() { - setReplying(true); - } - - function handleMouseOver() { - setMouseHover(true); - } - - function handleMouseOut() { - setMouseHover(false); - } - - function toggleEditorMode() { - setAdvancedEditor(!advancedEditor); - } - return (
  • setMouseHover(true)} + onMouseOut={() => setMouseHover(false)} >
    {authorUri ? : } @@ -159,44 +138,44 @@ function Comment(props: Props) {
    - {commentIsMine && ( - - - - - - {commentIsMine ? ( - - - {__('Edit')} - - - {__('Delete')} - - - ) : ( - '' - )} - - - )} + + + + + + {commentIsMine ? ( + <> + setEditing(true)}> + {__('Edit')} + + deleteComment(commentId)}> + {__('Delete')} + + + ) : ( + blockChannel(authorUri)}> + {__('Block Channel')} + + )} + +
    {isEditing ? ( setAdvancedEditor(!advancedEditor)} textAreaMaxLength={FF_MAX_CHARS_IN_COMMENT} />
    @@ -222,12 +201,12 @@ function Comment(props: Props) {
    )}
    - {!parentId && ( + {!parentId && !isEditing && ( + ); + + // Below is disabled until scroll style issues are resolved + // return ( + // + // + // + // {unreadCount > 0 && {unreadCount}} + // + + // {notifications && notifications.length > 0 ? ( + // + // {notifications.slice(0, 7).map((notification, index) => ( + // + // ))} + + // push(`/$/${PAGES.NOTIFICATIONS}`)}> + // + // {__('View All')} + // + // + // ) : ( + // + //
    No notifications yet.
    + // {/* Below is needed because MenuPopover isn't meant to be used this way */} + // + // {}} /> + // + //
    + // )} + //
    + // ); +} diff --git a/ui/component/page/view.jsx b/ui/component/page/view.jsx index 2a453e92965..0c575937514 100644 --- a/ui/component/page/view.jsx +++ b/ui/component/page/view.jsx @@ -19,7 +19,13 @@ type Props = { noHeader: boolean, noFooter: boolean, noSideNavigation: boolean, - backout: { backFunction: () => void, backTitle: string }, + backout: { + backLabel?: string, + backCB?: () => void, + backNavDefault?: string, + title: string, + simpleTitle: string, // Just use the same value as `title` if `title` is already short (~< 10 chars), unless you have a better idea for title overlfow on mobile + }, }; function Page(props: Props) { diff --git a/ui/component/publishAdditionalOptions/view.jsx b/ui/component/publishAdditionalOptions/view.jsx index 4cc61424900..103728fbd91 100644 --- a/ui/component/publishAdditionalOptions/view.jsx +++ b/ui/component/publishAdditionalOptions/view.jsx @@ -4,12 +4,12 @@ import classnames from 'classnames'; import usePersistedState from 'effects/use-persisted-state'; import { FormField } from 'component/common/form'; import Button from 'component/button'; -import { LbryFirst } from 'lbry-redux'; import LicenseType from './license-type'; import Card from 'component/common/card'; -import ErrorText from 'component/common/error-text'; // @if TARGET='app' -import { ipcRenderer } from 'electron'; +// import ErrorText from 'component/common/error-text'; +// import { LbryFirst } from 'lbry-redux'; +// import { ipcRenderer } from 'electron'; // @endif type Props = { @@ -29,82 +29,82 @@ type Props = { function PublishAdditionalOptions(props: Props) { const { - user, language, name, licenseType, otherLicenseDescription, licenseUrl, updatePublishForm, - useLBRYUploader, - needsYTAuth, - accessToken, - fetchAccessToken, + // user, + // useLBRYUploader, + // needsYTAuth, + // accessToken, + // fetchAccessToken, } = props; const [hideSection, setHideSection] = usePersistedState('publish-advanced-options', true); - const [hasLaunchedLbryFirst, setHasLaunchedLbryFirst] = React.useState(false); - const [ytError, setYtError] = React.useState(false); - const isLBRYFirstUser = user && user.lbry_first_approved; - const showLbryFirstCheckbox = !IS_WEB && isLBRYFirstUser && hasLaunchedLbryFirst; + // const [hasLaunchedLbryFirst, setHasLaunchedLbryFirst] = React.useState(false); + // const [ytError, setYtError] = React.useState(false); + // const isLBRYFirstUser = user && user.lbry_first_approved; + // const showLbryFirstCheckbox = !IS_WEB && isLBRYFirstUser && hasLaunchedLbryFirst; function toggleHideSection() { setHideSection(!hideSection); } // @if TARGET='app' - function signup() { - updatePublishForm({ ytSignupPending: true }); - LbryFirst.ytSignup() - .then(response => { - updatePublishForm({ needsYTAuth: false, ytSignupPending: false }); - }) - .catch(error => { - updatePublishForm({ ytSignupPending: false }); - setYtError(true); - console.error(error); // eslint-disable-line - }); - } + // function signup() { + // updatePublishForm({ ytSignupPending: true }); + // LbryFirst.ytSignup() + // .then(response => { + // updatePublishForm({ needsYTAuth: false, ytSignupPending: false }); + // }) + // .catch(error => { + // updatePublishForm({ ytSignupPending: false }); + // setYtError(true); + // console.error(error); // eslint-disable-line + // }); + // } - function unlink() { - setYtError(false); + // function unlink() { + // setYtError(false); - LbryFirst.remove() - .then(response => { - updatePublishForm({ needsYTAuth: true }); - }) - .catch(error => { - setYtError(true); - console.error(error); // eslint-disable-line - }); - } + // LbryFirst.remove() + // .then(response => { + // updatePublishForm({ needsYTAuth: true }); + // }) + // .catch(error => { + // setYtError(true); + // console.error(error); // eslint-disable-line + // }); + // } - React.useEffect(() => { - if (!accessToken) { - fetchAccessToken(); - } - }, [accessToken, fetchAccessToken]); + // React.useEffect(() => { + // if (!accessToken) { + // fetchAccessToken(); + // } + // }, [accessToken, fetchAccessToken]); - React.useEffect(() => { - if (isLBRYFirstUser && !hasLaunchedLbryFirst) { - ipcRenderer.send('launch-lbry-first'); - ipcRenderer.on('lbry-first-launched', () => { - setHasLaunchedLbryFirst(true); - }); - } - }, [isLBRYFirstUser, hasLaunchedLbryFirst, setHasLaunchedLbryFirst]); + // React.useEffect(() => { + // if (isLBRYFirstUser && !hasLaunchedLbryFirst) { + // ipcRenderer.send('launch-lbry-first'); + // ipcRenderer.on('lbry-first-launched', () => { + // setHasLaunchedLbryFirst(true); + // }); + // } + // }, [isLBRYFirstUser, hasLaunchedLbryFirst, setHasLaunchedLbryFirst]); - React.useEffect(() => { - if (useLBRYUploader && isLBRYFirstUser && hasLaunchedLbryFirst && accessToken) { - LbryFirst.hasYTAuth(accessToken) - .then(response => { - updatePublishForm({ needsYTAuth: !response.HasAuth }); - }) - .catch(error => { - setYtError(true); - console.error(error); // eslint-disable-line - }); - } - }, [updatePublishForm, useLBRYUploader, isLBRYFirstUser, hasLaunchedLbryFirst, accessToken]); + // React.useEffect(() => { + // if (useLBRYUploader && isLBRYFirstUser && hasLaunchedLbryFirst && accessToken) { + // LbryFirst.hasYTAuth(accessToken) + // .then(response => { + // updatePublishForm({ needsYTAuth: !response.HasAuth }); + // }) + // .catch(error => { + // setYtError(true); + // console.error(error); // eslint-disable-line + // }); + // } + // }, [updatePublishForm, useLBRYUploader, isLBRYFirstUser, hasLaunchedLbryFirst, accessToken]); // @endif return ( @@ -114,7 +114,7 @@ function PublishAdditionalOptions(props: Props) { {!hideSection && (
    {/* @if TARGET='app' */} - {showLbryFirstCheckbox && ( + {/* {showLbryFirstCheckbox && (
    <>
    - )} + )} */} {/* @endif */}
    {__(UPLOAD_SIZE_MESSAGE)}{' '} -
    @@ -152,7 +150,7 @@ class SelectThumbnail extends React.PureComponent { )} {status === THUMBNAIL_STATUSES.READY && ( -
    +
    ); } diff --git a/ui/component/settingAccountPassword/index.js b/ui/component/settingAccountPassword/index.js index 03eb8a813c2..29393c734a2 100644 --- a/ui/component/settingAccountPassword/index.js +++ b/ui/component/settingAccountPassword/index.js @@ -4,7 +4,7 @@ import { makeSelectClientSetting } from 'redux/selectors/settings'; import { doUserPasswordSet, doClearPasswordEntry } from 'redux/actions/user'; import { doToast } from 'redux/actions/notifications'; import UserSignIn from './view'; -import * as SETTINGS from 'constants/settings'; +import { SETTINGS } from 'lbry-redux'; const select = state => ({ user: selectUser(state), diff --git a/ui/component/settingAutoLaunch/index.js b/ui/component/settingAutoLaunch/index.js index 67dbb12f7a1..a45096f6138 100644 --- a/ui/component/settingAutoLaunch/index.js +++ b/ui/component/settingAutoLaunch/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import * as SETTINGS from 'constants/settings'; +import { SETTINGS } from 'lbry-redux'; import { doSetAutoLaunch } from 'redux/actions/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings'; import { doToast } from 'redux/actions/notifications'; diff --git a/ui/component/settingLanguage/index.js b/ui/component/settingLanguage/index.js index e2df344bd93..d173530ab93 100644 --- a/ui/component/settingLanguage/index.js +++ b/ui/component/settingLanguage/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import * as SETTINGS from 'constants/settings'; +import { SETTINGS } from 'lbry-redux'; import { doSetLanguage } from 'redux/actions/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings'; import SettingLanguage from './view'; @@ -12,7 +12,4 @@ const perform = dispatch => ({ setLanguage: value => dispatch(doSetLanguage(value)), }); -export default connect( - select, - perform -)(SettingLanguage); +export default connect(select, perform)(SettingLanguage); diff --git a/ui/component/settingWalletServer/view.jsx b/ui/component/settingWalletServer/view.jsx index 14ed968755c..2d96cdf3935 100644 --- a/ui/component/settingWalletServer/view.jsx +++ b/ui/component/settingWalletServer/view.jsx @@ -6,6 +6,7 @@ import Button from 'component/button'; import I18nMessage from 'component/i18nMessage'; import * as ICONS from 'constants/icons'; import ServerInputRow from './internal/inputRow'; +import { stringifyServerParam } from 'util/sync-settings'; type StatusOfServer = { host: string, @@ -84,13 +85,6 @@ function SettingWalletServer(props: Props) { return () => clearInterval(interval); }, []); - function makeServerParam(configList) { - return configList.reduce((acc, cur) => { - acc.push(`${cur[0]}:${cur[1]}`); - return acc; - }, []); - } - function doClear() { setAdvancedMode(false); clearWalletServers(); @@ -110,7 +104,7 @@ function SettingWalletServer(props: Props) { function updateServers(newConfig) { saveServerConfig(newConfig); - setCustomWalletServers(makeServerParam(newConfig)); + setCustomWalletServers(stringifyServerParam(newConfig)); } return ( @@ -134,7 +128,7 @@ function SettingWalletServer(props: Props) { onChange={e => { setAdvancedMode(e.target.checked); if (e.target.checked && customWalletServers.length) { - setCustomWalletServers(makeServerParam(customWalletServers)); + setCustomWalletServers(stringifyServerParam(customWalletServers)); } }} label={__('Use custom wallet servers')} diff --git a/ui/component/sideNavigation/index.js b/ui/component/sideNavigation/index.js index 743c11a5ab5..620104dbaff 100644 --- a/ui/component/sideNavigation/index.js +++ b/ui/component/sideNavigation/index.js @@ -1,7 +1,6 @@ -import * as SETTINGS from 'constants/settings'; import { connect } from 'react-redux'; import { selectSubscriptions } from 'redux/selectors/subscriptions'; -import { selectFollowedTags, selectPurchaseUriSuccess, doClearPurchasedUriSuccess } from 'lbry-redux'; +import { selectFollowedTags, selectPurchaseUriSuccess, doClearPurchasedUriSuccess, SETTINGS } from 'lbry-redux'; import { selectUploadCount } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { makeSelectClientSetting } from 'redux/selectors/settings'; diff --git a/ui/component/sideNavigation/view.jsx b/ui/component/sideNavigation/view.jsx index 89183f51924..61d71f82adf 100644 --- a/ui/component/sideNavigation/view.jsx +++ b/ui/component/sideNavigation/view.jsx @@ -85,7 +85,7 @@ function SideNavigation(props: Props) { } }, [setPulseLibrary, purchaseSuccess, doClearPurchasedUriSuccess]); - function buildLink(path, label, icon, onClick, requiresAuth = false, isLiteral = false) { + function buildLink(path, label, icon, onClick, requiresAuth = false, isLiteral = false) { return { navigate: !isLiteral ? `$/${path}` : `${path}`, label, @@ -136,7 +136,7 @@ function SideNavigation(props: Props) { ...buildLink(PAGES.DISCOVER, __('All Content'), ICONS.DISCOVER), }, { - ...buildLink(PAGES.LIBRARY, __('Library'), ICONS.LIBRARY), + ...buildLink(PAGES.LIBRARY, IS_WEB ? __('Purchased') : __('Library'), ICONS.LIBRARY), }, // @if TARGET='web' { @@ -177,14 +177,14 @@ function SideNavigation(props: Props) { }, { ...buildLink( - PAGES.PUBLISHED, + PAGES.UPLOADS, uploadCount ? ( - {__('Publishes')} + {__('Uploads')} ) : ( - __('Publishes') + __('Uploads') ), ICONS.PUBLISH ), @@ -202,7 +202,7 @@ function SideNavigation(props: Props) { ...buildLink(PAGES.INVITE, __('Invites'), ICONS.INVITE), }, { - ...buildLink(PAGES.PUBLISH, __('Publish'), ICONS.PUBLISH), + ...buildLink(PAGES.UPLOAD, __('Upload'), ICONS.PUBLISH), }, { ...buildLink(PAGES.HELP, __('Help'), ICONS.HELP), diff --git a/ui/component/socialShare/view.jsx b/ui/component/socialShare/view.jsx index 218ea4cccca..073b0f524f2 100644 --- a/ui/component/socialShare/view.jsx +++ b/ui/component/socialShare/view.jsx @@ -74,7 +74,7 @@ function SocialShare(props: Props) { return ( - + {showStartAt && (
    ({ modal: selectModal(state), daemonVersionMatched: selectDaemonVersionMatched(state), - animationHidden: makeSelectClientSetting(settings.HIDE_SPLASH_ANIMATION)(state), + animationHidden: makeSelectClientSetting(SETTINGS.HIDE_SPLASH_ANIMATION)(state), }); const perform = dispatch => ({ diff --git a/ui/component/splash/view.jsx b/ui/component/splash/view.jsx index 02bb54020c7..4a5243261a0 100644 --- a/ui/component/splash/view.jsx +++ b/ui/component/splash/view.jsx @@ -1,10 +1,9 @@ // @flow import type { Node } from 'react'; import * as MODALS from 'constants/modal_types'; -import * as SETTINGS from 'constants/settings'; import * as ICONS from 'constants/icons'; import React from 'react'; -import { Lbry } from 'lbry-redux'; +import { Lbry, SETTINGS } from 'lbry-redux'; import Button from 'component/button'; import ModalWalletUnlock from 'modal/modalWalletUnlock'; import ModalIncompatibleDaemon from 'modal/modalIncompatibleDaemon'; diff --git a/ui/component/syncToggle/index.js b/ui/component/syncToggle/index.js index 7899cf49870..b94209c9709 100644 --- a/ui/component/syncToggle/index.js +++ b/ui/component/syncToggle/index.js @@ -1,4 +1,4 @@ -import * as SETTINGS from 'constants/settings'; +import { SETTINGS } from 'lbry-redux'; import { connect } from 'react-redux'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectGetSyncErrorMessage } from 'lbryinc'; diff --git a/ui/component/transactionListTable/internal/txo-list-item.jsx b/ui/component/transactionListTable/internal/txo-list-item.jsx index b68567029fb..378541ef551 100644 --- a/ui/component/transactionListTable/internal/txo-list-item.jsx +++ b/ui/component/transactionListTable/internal/txo-list-item.jsx @@ -121,7 +121,7 @@ class TxoListItem extends React.PureComponent { {(isTip && __('Tip')) || (type === 'support' && !isTip && __('Support')) || - (valueType && ((valueType === 'stream' && __('Publish')) || __(toCapitalCase(valueType)))) || + (valueType && ((valueType === 'stream' && __('Upload')) || __(toCapitalCase(valueType)))) || (type && __(toCapitalCase(type)))} {' '} {isRevokeable && this.getLink(type, isTip)} diff --git a/ui/component/userChannelFollowIntro/view.jsx b/ui/component/userChannelFollowIntro/view.jsx index f2441c8fa73..df17d28d49d 100644 --- a/ui/component/userChannelFollowIntro/view.jsx +++ b/ui/component/userChannelFollowIntro/view.jsx @@ -6,6 +6,7 @@ import Nag from 'component/common/nag'; import { parseURI } from 'lbry-redux'; import Button from 'component/button'; import Card from 'component/common/card'; +import { AUTO_FOLLOW_CHANNELS } from 'config'; type Props = { subscribedChannels: Array, @@ -14,8 +15,7 @@ type Props = { channelSubscribe: (sub: Subscription) => void, }; -const LBRY_URI = 'lbry://@lbry#3fda836a92faaceedfe398225fb9b2ee2ed1f01a'; -const LBRYCAST_URI = 'lbry://@lbrycast#4c29f8b013adea4d5cca1861fb2161d5089613ea'; +const channelsToSubscribe = AUTO_FOLLOW_CHANNELS.trim().split(' '); function UserChannelFollowIntro(props: Props) { const { subscribedChannels, channelSubscribe, onContinue, onBack } = props; @@ -23,15 +23,12 @@ function UserChannelFollowIntro(props: Props) { // subscribe to lbry useEffect(() => { - channelSubscribe({ - channelName: parseURI(LBRY_URI).claimName, - uri: LBRY_URI, - }); - - channelSubscribe({ - channelName: parseURI(LBRYCAST_URI).claimName, - uri: LBRYCAST_URI, - }); + channelsToSubscribe.forEach(c => + channelSubscribe({ + channelName: parseURI(c).claimName, + uri: c, + }) + ); }, []); return ( diff --git a/ui/component/userEmailNew/index.js b/ui/component/userEmailNew/index.js index 3261ffaaec5..174cec6f7b8 100644 --- a/ui/component/userEmailNew/index.js +++ b/ui/component/userEmailNew/index.js @@ -1,4 +1,3 @@ -import * as SETTINGS from 'constants/settings'; import { connect } from 'react-redux'; import { doClearEmailEntry, doUserSignUp } from 'redux/actions/user'; import { @@ -7,7 +6,7 @@ import { selectEmailAlreadyExists, selectUser, } from 'redux/selectors/user'; -import { DAEMON_SETTINGS } from 'lbry-redux'; +import { DAEMON_SETTINGS, SETTINGS } from 'lbry-redux'; import { doSetClientSetting, doSetDaemonSetting } from 'redux/actions/settings'; import { makeSelectClientSetting, selectDaemonSettings } from 'redux/selectors/settings'; import UserEmailNew from './view'; diff --git a/ui/component/userEmailReturning/view.jsx b/ui/component/userEmailReturning/view.jsx index 576a87bc75a..c179bd7504c 100644 --- a/ui/component/userEmailReturning/view.jsx +++ b/ui/component/userEmailReturning/view.jsx @@ -1,5 +1,5 @@ // @flow -import * as SETTINGS from 'constants/settings'; +import { SETTINGS } from 'lbry-redux'; import * as PAGES from 'constants/pages'; import React, { useState } from 'react'; import { FormField, Form } from 'component/common/form'; diff --git a/ui/component/userSignUp/index.js b/ui/component/userSignUp/index.js index 8c637d7261c..2597714fa0d 100644 --- a/ui/component/userSignUp/index.js +++ b/ui/component/userSignUp/index.js @@ -1,4 +1,3 @@ -import * as SETTINGS from 'constants/settings'; import REWARD_TYPES from 'rewards'; import { connect } from 'react-redux'; import { selectGetSyncIsPending, selectGetSyncErrorMessage, selectSyncHash } from 'lbryinc'; @@ -12,7 +11,13 @@ import { selectUser, selectAccessToken, } from 'redux/selectors/user'; -import { selectMyChannelClaims, selectBalance, selectFetchingMyChannels, selectCreatingChannel } from 'lbry-redux'; +import { + selectMyChannelClaims, + selectBalance, + selectFetchingMyChannels, + selectCreatingChannel, + SETTINGS, +} from 'lbry-redux'; import { makeSelectClientSetting } from 'redux/selectors/settings'; import UserSignIn from './view'; diff --git a/ui/component/viewers/videoViewer/index.js b/ui/component/viewers/videoViewer/index.js index 28cf5155f21..69718d9a916 100644 --- a/ui/component/viewers/videoViewer/index.js +++ b/ui/component/viewers/videoViewer/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { makeSelectClaimForUri, makeSelectFileInfoForUri, makeSelectThumbnailForUri } from 'lbry-redux'; +import { makeSelectClaimForUri, makeSelectFileInfoForUri, makeSelectThumbnailForUri, SETTINGS } from 'lbry-redux'; import { doChangeVolume, doChangeMute, doAnalyticsView } from 'redux/actions/app'; import { selectVolume, selectMute } from 'redux/selectors/app'; import { savePosition, clearPosition } from 'redux/actions/content'; @@ -8,7 +8,6 @@ import VideoViewer from './view'; import { withRouter } from 'react-router'; import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards'; import { makeSelectClientSetting } from 'redux/selectors/settings'; -import * as SETTINGS from 'constants/settings'; const select = (state, props) => { const { search } = props.location; diff --git a/ui/component/viewers/videoViewer/internal/videojs.jsx b/ui/component/viewers/videoViewer/internal/videojs.jsx index 407c164b8b0..c4c7e848f31 100644 --- a/ui/component/viewers/videoViewer/internal/videojs.jsx +++ b/ui/component/viewers/videoViewer/internal/videojs.jsx @@ -1,5 +1,5 @@ // @flow -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import Button from 'component/button'; import * as ICONS from 'constants/icons'; import classnames from 'classnames'; @@ -7,6 +7,7 @@ import videojs from 'video.js/dist/alt/video.core.novtt.min.js'; import 'video.js/dist/alt/video-js-cdn.min.css'; import eventTracking from 'videojs-event-tracking'; import isUserTyping from 'util/detect-typing'; +const isDev = process.env.NODE_ENV !== 'production'; export type Player = { on: (string, (any) => void) => void, @@ -21,6 +22,7 @@ export type Player = { currentTime: (?number) => number, ended: () => boolean, error: () => any, + loadingSpinner: any, }; type Props = { @@ -39,7 +41,6 @@ type VideoJSOptions = { responsive: boolean, poster?: string, muted?: boolean, - poster?: string, }; const IS_IOS = @@ -79,6 +80,7 @@ properties for this component should be kept to ONLY those that if changed shoul */ export default React.memo(function VideoJs(props: Props) { const { startMuted, source, sourceType, poster, isAudio, onPlayerReady } = props; + const [reload, setReload] = useState('initial'); let player: ?Player; const containerRef = useRef(); const videoJsOptions = { @@ -97,17 +99,41 @@ export default React.memo(function VideoJs(props: Props) { videoJsOptions.muted = startMuted; const tapToUnmuteRef = useRef(); + const tapToRetryRef = useRef(); + + const TAP = { + NONE: 'NONE', + UNMUTE: 'UNMUTE', + RETRY: 'RETRY', + }; - function showTapToUnmute(newState: boolean) { - // Use the DOM to control the state of the button to prevent re-renders. - // The button only needs to appear once per session. - if (tapToUnmuteRef.current) { - const curState = tapToUnmuteRef.current.style.visibility === 'visible'; - if (newState !== curState) { - tapToUnmuteRef.current.style.visibility = newState ? 'visible' : 'hidden'; + function showTapButton(tapButton) { + const setButtonVisibility = (theRef, newState) => { + // Use the DOM to control the state of the button to prevent re-renders. + if (theRef.current) { + const curState = theRef.current.style.visibility === 'visible'; + if (newState !== curState) { + theRef.current.style.visibility = newState ? 'visible' : 'hidden'; + } } - } else if (process.env.NODE_ENV === 'development') { - throw new Error('[videojs.jsx] Empty video ref should not happen'); + }; + + switch (tapButton) { + case TAP.NONE: + setButtonVisibility(tapToUnmuteRef, false); + setButtonVisibility(tapToRetryRef, false); + break; + case TAP.UNMUTE: + setButtonVisibility(tapToUnmuteRef, true); + setButtonVisibility(tapToRetryRef, false); + break; + case TAP.RETRY: + setButtonVisibility(tapToUnmuteRef, false); + setButtonVisibility(tapToRetryRef, true); + break; + default: + if (isDev) throw new Error('showTapButton: unexpected ref'); + break; } } @@ -118,29 +144,40 @@ export default React.memo(function VideoJs(props: Props) { player.volume(1.0); } } - showTapToUnmute(false); + showTapButton(TAP.NONE); + } + + function retryVideoAfterFailure() { + if (player) { + setReload(Date.now()); + showTapButton(TAP.NONE); + } } function onInitialPlay() { if (player && (player.muted() || player.volume() === 0)) { // The css starts as "hidden". We make it visible here without // re-rendering the whole thing. - showTapToUnmute(true); + showTapButton(TAP.UNMUTE); } } function onVolumeChange() { if (player && !player.muted()) { - showTapToUnmute(false); + showTapButton(TAP.NONE); } } function onError() { - showTapToUnmute(false); + showTapButton(TAP.RETRY); + + if (player && player.loadingSpinner) { + player.loadingSpinner.hide(); + } } function onEnded() { - showTapToUnmute(false); + showTapButton(TAP.NONE); } function handleKeyDown(e: KeyboardEvent) { @@ -222,9 +259,9 @@ export default React.memo(function VideoJs(props: Props) { }); return ( - // $FlowFixMe -
    - { + reload && ( + // $FlowFixMe +
    +
    + ) ); }); diff --git a/ui/component/webUploadList/view.jsx b/ui/component/webUploadList/view.jsx index b3bd014b5bc..c4e6b827622 100644 --- a/ui/component/webUploadList/view.jsx +++ b/ui/component/webUploadList/view.jsx @@ -21,11 +21,7 @@ export default function WebUploadList(props: Props) { !!uploadCount && ( 1 - ? __('You files are currently uploading. This will update automatically.') - : __('Your file is currently uploading. This will update automatically.') - } + subtitle={uploadCount > 1 ? __('You files are currently uploading.') : __('Your file is currently uploading.')} body={
    {/* $FlowFixMe */} diff --git a/ui/component/wunderbar/view.jsx b/ui/component/wunderbar/view.jsx index 0821a514ad5..e8e4c067569 100644 --- a/ui/component/wunderbar/view.jsx +++ b/ui/component/wunderbar/view.jsx @@ -199,7 +199,7 @@ class WunderBar extends React.PureComponent { this.input = el; }} className="wunderbar__input" - placeholder={__('Enter a LBRY URL or search for videos, music, games and more')} + placeholder={__('Search')} /> )} renderItem={({ value, type, shorthand }, isHighlighted) => ( diff --git a/ui/component/youtubeBadge/index.js b/ui/component/youtubeBadge/index.js new file mode 100644 index 00000000000..9e345ec82bc --- /dev/null +++ b/ui/component/youtubeBadge/index.js @@ -0,0 +1,8 @@ +import { connect } from 'react-redux'; +import YoutubeBadge from './view'; + +const select = state => ({}); + +const perform = dispatch => ({}); + +export default connect(select, perform)(YoutubeBadge); diff --git a/ui/component/youtubeBadge/view.jsx b/ui/component/youtubeBadge/view.jsx new file mode 100644 index 00000000000..b3cf546ed62 --- /dev/null +++ b/ui/component/youtubeBadge/view.jsx @@ -0,0 +1,50 @@ +// @flow +import * as ICONS from 'constants/icons'; +import * as React from 'react'; +import DateTime from 'component/dateTime'; +import Icon from 'component/common/icon'; +import { Lbryio } from 'lbryinc'; + +type Props = { + channelClaimId: string, + includeSyncDate: boolean, +}; + +export default function YoutubeBadge(props: Props) { + const { channelClaimId, includeSyncDate = true } = props; + + const [isVerified, setIsVerified] = React.useState(); + const [lastYtSyncDate, setLastYtSyncDate] = React.useState(); + + React.useEffect(() => { + if (channelClaimId) { + Lbryio.call('yt', 'get_youtuber', { channel_claim_id: channelClaimId }).then(response => { + if (response.is_verified_youtuber) { + setIsVerified(true); + setLastYtSyncDate(response.last_synced); + } else { + setIsVerified(false); + setLastYtSyncDate(undefined); + } + }); + } else { + setIsVerified(false); + setLastYtSyncDate(undefined); + } + }, [channelClaimId]); + + if (isVerified) { + const str = + includeSyncDate && lastYtSyncDate + ? __('Official YouTube Creator - Last checked %time_ago%', { time_ago: DateTime.getTimeAgoStr(lastYtSyncDate) }) + : __('Official YouTube Creator'); + return ( +
    + + {str} +
    + ); + } else { + return null; + } +} diff --git a/ui/constants/action_types.js b/ui/constants/action_types.js index 1588104b8e1..98c52458a87 100644 --- a/ui/constants/action_types.js +++ b/ui/constants/action_types.js @@ -8,6 +8,10 @@ XXX_COMPLETE // if there is no fail case */ +// redux-persist +export const REHYDRATE = 'persist/REHYDRATE'; + +// app export const WINDOW_FOCUSED = 'WINDOW_FOCUSED'; export const DAEMON_READY = 'DAEMON_READY'; export const DAEMON_VERSION_MATCH = 'DAEMON_VERSION_MATCH'; @@ -22,6 +26,7 @@ export const TOGGLE_SEARCH_EXPANDED = 'TOGGLE_SEARCH_EXPANDED'; export const PASSWORD_SAVED = 'PASSWORD_SAVED'; export const SET_WELCOME_VERSION = 'SET_WELCOME_VERSION'; export const SET_ALLOW_ANALYTICS = 'SET_ALLOW_ANALYTICS'; +export const SET_HAS_NAVIGATED = 'SET_HAS_NAVIGATED'; // Navigation export const CHANGE_AFTER_AUTH_PATH = 'CHANGE_AFTER_AUTH_PATH'; @@ -120,6 +125,7 @@ export const CLIENT_SETTING_CHANGED = 'CLIENT_SETTING_CHANGED'; export const UPDATE_IS_NIGHT = 'UPDATE_IS_NIGHT'; export const FINDING_FFMPEG_STARTED = 'FINDING_FFMPEG_STARTED'; export const FINDING_FFMPEG_COMPLETED = 'FINDING_FFMPEG_COMPLETED'; +export const SYNC_CLIENT_SETTINGS = 'SYNC_CLIENT_SETTINGS'; // User export const AUTHENTICATION_STARTED = 'AUTHENTICATION_STARTED'; @@ -216,15 +222,17 @@ export const CLEAR_PUBLISH_ERROR = 'CLEAR_PUBLISH_ERROR'; export const REMOVE_PENDING_PUBLISH = 'REMOVE_PENDING_PUBLISH'; export const DO_PREPARE_EDIT = 'DO_PREPARE_EDIT'; -// media +// Media export const MEDIA_PLAY = 'MEDIA_PLAY'; export const MEDIA_PAUSE = 'MEDIA_PAUSE'; // Notifications -export const CREATE_NOTIFICATION = 'CREATE_NOTIFICATION'; -export const EDIT_NOTIFICATION = 'EDIT_NOTIFICATION'; -export const DELETE_NOTIFICATION = 'DELETE_NOTIFICATION'; -export const DISMISS_NOTIFICATION = 'DISMISS_NOTIFICATION'; +export const NOTIFICATION_LIST_STARTED = 'NOTIFICATION_LIST_STARTED'; +export const NOTIFICATION_LIST_COMPLETED = 'NOTIFICATION_LIST_COMPLETED'; +export const NOTIFICATION_LIST_FAILED = 'NOTIFICATION_LIST_FAILED'; +export const NOTIFICATION_READ_STARTED = 'NOTIFICATION_READ_STARTED'; +export const NOTIFICATION_READ_COMPLETED = 'NOTIFICATION_READ_COMPLETED'; +export const NOTIFICATION_READ_FAILED = 'NOTIFICATION_READ_FAILED'; export const CREATE_TOAST = 'CREATE_TOAST'; export const DISMISS_TOAST = 'DISMISS_TOAST'; export const CREATE_ERROR = 'CREATE_ERROR'; @@ -246,3 +254,10 @@ export const COMMENT_UPDATE_FAILED = 'COMMENT_UPDATE_FAILED'; export const COMMENT_HIDE_STARTED = 'COMMENT_HIDE_STARTED'; export const COMMENT_HIDE_COMPLETED = 'COMMENT_HIDE_COMPLETED'; export const COMMENT_HIDE_FAILED = 'COMMENT_HIDE_FAILED'; + +// Blocked Channels +export const TOGGLE_BLOCK_CHANNEL = 'TOGGLE_BLOCK_CHANNEL'; + +// Notifications +export const WS_CONNECT = 'WS_CONNECT'; +export const WS_DISCONNECT = 'WS_DISCONNECT'; diff --git a/ui/constants/icons.js b/ui/constants/icons.js index f1fb7edd69a..8f43d735208 100644 --- a/ui/constants/icons.js +++ b/ui/constants/icons.js @@ -110,3 +110,5 @@ export const CAMERA = 'Camera'; export const OPEN_LOG = 'FilePlus'; export const OPEN_LOG_FOLDER = 'Folder'; export const STORY = 'Story'; +export const LBRY_STATUS = 'BarChart'; +export const NOTIFICATION = 'Bell'; diff --git a/ui/constants/modal_types.js b/ui/constants/modal_types.js index ef32f3b30ed..71852a0b4ab 100644 --- a/ui/constants/modal_types.js +++ b/ui/constants/modal_types.js @@ -9,7 +9,6 @@ export const AUTO_GENERATE_THUMBNAIL = 'auto_generate_thumbnail'; export const AUTO_UPDATE_DOWNLOADED = 'auto_update_downloaded'; export const ERROR = 'error'; export const UPGRADE = 'upgrade'; -export const WELCOME = 'welcome'; export const EMAIL_COLLECTION = 'email_collection'; export const PHONE_COLLECTION = 'phone_collection'; export const FIRST_REWARD = 'first_reward'; diff --git a/ui/constants/pages.js b/ui/constants/pages.js index 3f68188d449..4a66d9759b0 100644 --- a/ui/constants/pages.js +++ b/ui/constants/pages.js @@ -1,8 +1,8 @@ exports.AUTH = 'signup'; exports.AUTH_SIGNIN = 'signin'; exports.AUTH_VERIFY = 'verify'; -exports.AUTH_PASSWORD_RESET = 'reset'; -exports.AUTH_PASSWORD_SET = 'set'; +exports.AUTH_PASSWORD_RESET = 'resetpassword'; +exports.AUTH_PASSWORD_SET = 'reset'; // This is tied to a link in internal-apis - don't change this exports.BACKUP = 'backup'; exports.CHANNEL = 'channel'; exports.DISCOVER = 'discover'; @@ -10,8 +10,10 @@ exports.HOME = 'home'; exports.HELP = 'help'; exports.LIBRARY = 'library'; exports.INVITE = 'invite'; -exports.PUBLISH = 'publish'; -exports.PUBLISHED = 'published'; +exports.DEPRECATED__PUBLISH = 'publish'; +exports.DEPRECATED__PUBLISHED = 'published'; +exports.UPLOAD = 'upload'; +exports.UPLOADS = 'uploads'; exports.GET_CREDITS = 'getcredits'; exports.REPORT = 'report'; exports.REWARDS = 'rewards'; @@ -19,6 +21,7 @@ exports.REWARDS_VERIFY = 'rewards/verify'; exports.SEND = 'send'; exports.SETTINGS = 'settings'; exports.SETTINGS_NOTIFICATIONS = 'settings/notifications'; +exports.SETTINGS_ADVANCED = 'settings/advanced'; exports.SHOW = 'show'; exports.ACCOUNT = 'account'; exports.SEARCH = 'search'; @@ -40,4 +43,5 @@ exports.CREATOR_DASHBOARD = 'dashboard'; exports.CHECKOUT = 'checkout'; exports.CODE_2257 = '2257'; exports.BUY = 'buy'; -exports.CHANNEL_NEW = 'channelnew'; +exports.CHANNEL_NEW = 'channel/new'; +exports.NOTIFICATIONS = 'notifications'; diff --git a/ui/effects/use-zoom.js b/ui/effects/use-zoom.js new file mode 100644 index 00000000000..32022ffb2fe --- /dev/null +++ b/ui/effects/use-zoom.js @@ -0,0 +1,47 @@ +import { useEffect } from 'react'; +import { changeZoomFactor, ZOOM } from 'util/zoomWindow'; + +export default function useHover(ref) { + useEffect(() => { + const handleKeyPress = e => { + if (e.ctrlKey && !e.shiftKey) { + switch (e.code) { + case 'NumpadAdd': + case 'Equal': + e.preventDefault(); + changeZoomFactor(ZOOM.INCREMENT); + break; + case 'NumpadSubtract': + case 'Minus': + e.preventDefault(); + changeZoomFactor(ZOOM.DECREMENT); + break; + case 'Numpad0': + case 'Digit0': + e.preventDefault(); + changeZoomFactor(ZOOM.RESET); + break; + default: + // Do nothing + break; + } + } + }; + window.addEventListener('keydown', handleKeyPress); + return () => window.removeEventListener('keydown', handleKeyPress); + }, []); + + useEffect(() => { + const handleWheel = e => { + if (e.ctrlKey && !e.shiftKey) { + if (e.deltaY < 0) { + changeZoomFactor(ZOOM.INCREMENT); + } else { + changeZoomFactor(ZOOM.DECREMENT); + } + } + }; + window.addEventListener('wheel', handleWheel); + return () => window.removeEventListener('wheel', handleWheel); + }, []); +} diff --git a/ui/index.jsx b/ui/index.jsx index 68b566aab8c..b4bb646af79 100644 --- a/ui/index.jsx +++ b/ui/index.jsx @@ -6,6 +6,7 @@ import SnackBar from 'component/snackBar'; // @if TARGET='app' import SplashScreen from 'component/splash'; import * as ACTIONS from 'constants/action_types'; +import { changeZoomFactor } from 'util/zoomWindow'; // @endif import { ipcRenderer, remote, shell } from 'electron'; import moment from 'moment'; @@ -193,6 +194,10 @@ ipcRenderer.on('open-menu', (event, uri) => { } }); +ipcRenderer.on('zoom-window', (event, action) => { + changeZoomFactor(action); +}); + const { dock } = remote.app; ipcRenderer.on('window-is-focused', () => { diff --git a/ui/modal/modalConfirmAge/view.jsx b/ui/modal/modalConfirmAge/view.jsx index e569b432ed4..621eea56b5e 100644 --- a/ui/modal/modalConfirmAge/view.jsx +++ b/ui/modal/modalConfirmAge/view.jsx @@ -1,5 +1,5 @@ // @flow -import * as SETTINGS from 'constants/settings'; +import { SETTINGS } from 'lbry-redux'; import React from 'react'; import { Modal } from 'modal/modal'; import Card from 'component/common/card'; diff --git a/ui/modal/modalConfirmThumbnailUpload/view.jsx b/ui/modal/modalConfirmThumbnailUpload/view.jsx index e9fa7685561..a4a736e2d80 100644 --- a/ui/modal/modalConfirmThumbnailUpload/view.jsx +++ b/ui/modal/modalConfirmThumbnailUpload/view.jsx @@ -1,6 +1,7 @@ // @flow import React from 'react'; import { Modal } from 'modal/modal'; +import { DOMAIN } from 'config'; type Props = { upload: WebFile => void, @@ -30,7 +31,7 @@ class ModalConfirmThumbnailUpload extends React.PureComponent { onConfirmed={() => this.upload()} onAborted={closeModal} > -

    {__('Are you sure you want to upload this thumbnail to spee.ch')}?

    +
    {file.path || file.name}
    diff --git a/ui/modal/modalFileSelection/view.jsx b/ui/modal/modalFileSelection/view.jsx index 39c5c12f366..c79c825ed46 100644 --- a/ui/modal/modalFileSelection/view.jsx +++ b/ui/modal/modalFileSelection/view.jsx @@ -18,7 +18,7 @@ type Props = { }, }; -const PUBLISH_URL = `/$/${PAGES.PUBLISH}`; +const PUBLISH_URL = `/$/${PAGES.UPLOAD}`; const ModalFileSelection = (props: Props) => { const { history, files, hideModal, updatePublishForm } = props; diff --git a/ui/modal/modalPublish/view.jsx b/ui/modal/modalPublish/view.jsx index 6dd868fb07e..770f4f071a6 100644 --- a/ui/modal/modalPublish/view.jsx +++ b/ui/modal/modalPublish/view.jsx @@ -1,4 +1,5 @@ // @flow +import * as PAGES from 'constants/pages'; import React from 'react'; import { Modal } from 'modal/modal'; import ClaimPreview from 'component/claimPreview'; @@ -55,10 +56,10 @@ class ModalPublishSuccess extends React.PureComponent {
    + <> +
    +
    +

    {__('These changes will appear shortly.')}

    + } /> diff --git a/ui/modal/modalRepost/view.jsx b/ui/modal/modalRepost/view.jsx index 4d1b5a697cf..748d1da875a 100644 --- a/ui/modal/modalRepost/view.jsx +++ b/ui/modal/modalRepost/view.jsx @@ -130,7 +130,7 @@ function ModalRepost(props: Props) { actions={
    setRepostChannel(newChannel)} diff --git a/ui/modal/modalRevokeClaim/index.js b/ui/modal/modalRevokeClaim/index.js index a9cea98d692..052867f65c8 100644 --- a/ui/modal/modalRevokeClaim/index.js +++ b/ui/modal/modalRevokeClaim/index.js @@ -1,6 +1,7 @@ import { connect } from 'react-redux'; import { doHideModal } from 'redux/actions/app'; import { doAbandonTxo, doAbandonClaim, selectTransactionItems } from 'lbry-redux'; +import { doToast } from 'redux/actions/notifications'; import ModalRevokeClaim from './view'; const select = state => ({ @@ -8,6 +9,7 @@ const select = state => ({ }); const perform = dispatch => ({ + toast: (message, isError) => dispatch(doToast({ message, isError })), closeModal: () => dispatch(doHideModal()), abandonTxo: (txo, cb) => dispatch(doAbandonTxo(txo, cb)), abandonClaim: (txid, nout, cb) => dispatch(doAbandonClaim(txid, nout, cb)), diff --git a/ui/modal/modalRouter/view.jsx b/ui/modal/modalRouter/view.jsx index d4c7e46ad24..54535003f06 100644 --- a/ui/modal/modalRouter/view.jsx +++ b/ui/modal/modalRouter/view.jsx @@ -7,7 +7,6 @@ import ModalDownloading from 'modal/modalDownloading'; import ModalAutoGenerateThumbnail from 'modal/modalAutoGenerateThumbnail'; import ModalAutoUpdateDownloaded from 'modal/modalAutoUpdateDownloaded'; import ModalUpgrade from 'modal/modalUpgrade'; -import ModalWelcome from 'modal/modalWelcome'; import ModalFirstReward from 'modal/modalFirstReward'; import ModalRemoveFile from 'modal/modalRemoveFile'; import ModalTransactionFailed from 'modal/modalTransactionFailed'; @@ -80,8 +79,6 @@ function ModalRouter(props: Props) { return ; case MODALS.FILE_TIMEOUT: return ; - case MODALS.WELCOME: - return ; case MODALS.FIRST_REWARD: return ; case MODALS.TRANSACTION_FAILED: diff --git a/ui/modal/modalWelcome/index.js b/ui/modal/modalWelcome/index.js deleted file mode 100644 index 3c143fa57dc..00000000000 --- a/ui/modal/modalWelcome/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import * as settings from 'constants/settings'; -import { connect } from 'react-redux'; -import { doHideModal } from 'redux/actions/app'; -import { doSetClientSetting } from 'redux/actions/settings'; -import ModalWelcome from './view'; - -const perform = dispatch => () => ({ - closeModal: () => { - dispatch(doSetClientSetting(settings.NEW_USER_ACKNOWLEDGED, true)); - dispatch(doHideModal()); - }, -}); - -export default connect( - null, - perform -)(ModalWelcome); diff --git a/ui/modal/modalWelcome/view.jsx b/ui/modal/modalWelcome/view.jsx deleted file mode 100644 index fb4db63eb43..00000000000 --- a/ui/modal/modalWelcome/view.jsx +++ /dev/null @@ -1,28 +0,0 @@ -// @flow -import React from 'react'; -import { Modal } from 'modal/modal'; -import Button from 'component/button'; - -type Props = { - closeModal: () => void, -}; - -const ModalWelcome = (props: Props) => { - const { closeModal } = props; - - return ( - -

    - {__('Using LBRY is like dating a centaur. Totally normal up top, and')} {__('way different')}{' '} - {__('underneath.')} -

    -

    {__('Up top, LBRY is similar to popular media sites.')}

    -

    {__('Below, LBRY is controlled by users -- you -- via blockchain and decentralization.')}

    -
    -
    -
    - ); -}; - -export default ModalWelcome; diff --git a/ui/page/channel/index.js b/ui/page/channel/index.js index 184a51649ed..50e07a8d86d 100644 --- a/ui/page/channel/index.js +++ b/ui/page/channel/index.js @@ -6,9 +6,9 @@ import { makeSelectCoverForUri, selectCurrentChannelPage, makeSelectClaimForUri, - selectChannelIsBlocked, makeSelectClaimIsPending, } from 'lbry-redux'; +import { selectChannelIsBlocked } from 'redux/selectors/blocked'; import { selectBlackListedOutpoints, doFetchSubCount, makeSelectSubCountForUri } from 'lbryinc'; import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; import { doOpenModal } from 'redux/actions/app'; diff --git a/ui/page/channel/view.jsx b/ui/page/channel/view.jsx index 8b0d3f7f9be..2aed017ab2e 100644 --- a/ui/page/channel/view.jsx +++ b/ui/page/channel/view.jsx @@ -2,7 +2,6 @@ import * as ICONS from 'constants/icons'; import React from 'react'; import { parseURI } from 'lbry-redux'; -import { Lbryio } from 'lbryinc'; import Page from 'component/page'; import SubscribeButton from 'component/subscribeButton'; import BlockButton from 'component/blockButton'; @@ -18,10 +17,9 @@ import ChannelThumbnail from 'component/channelThumbnail'; import ChannelEdit from 'component/channelEdit'; import ClaimUri from 'component/claimUri'; import classnames from 'classnames'; -import Icon from 'component/common/icon'; import HelpLink from 'component/common/help-link'; -import DateTime from 'component/dateTime'; import ClaimSupportButton from 'component/claimSupportButton'; +import YoutubeBadge from 'component/youtubeBadge'; const PAGE_VIEW_QUERY = `view`; const ABOUT_PAGE = `about`; @@ -71,8 +69,8 @@ function ChannelPage(props: Props) { const urlParams = new URLSearchParams(search); const currentView = urlParams.get(PAGE_VIEW_QUERY) || undefined; const editInUrl = urlParams.get(PAGE_VIEW_QUERY) === EDIT_PAGE; - const [editing, setEditing] = React.useState(editInUrl); - const [lastYtSyncDate, setLastYtSyncDate] = React.useState(); + 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; @@ -105,36 +103,11 @@ function ChannelPage(props: Props) { push(`${url}${search}`); } - function onDone() { - setEditing(false); - goBack(); - } - - React.useEffect(() => { - if (!channelIsMine && editing) { - setEditing(false); - } - - if (channelIsMine && editing) { - push(`?${PAGE_VIEW_QUERY}=${EDIT_PAGE}`); - } - }, [channelIsMine, editing, push]); - React.useEffect(() => { - if (currentView === EDIT_PAGE) { - setEditing(true); - } else { - setEditing(false); + if (currentView === DISCUSSION_PAGE) { + setDiscussionWasMounted(true); } - }, [currentView, setEditing]); - - React.useEffect(() => { - Lbryio.call('yt', 'get_youtuber', { channel_claim_id: claimId }).then(response => { - if (response.is_verified_youtuber) { - setLastYtSyncDate(response.last_synced); - } - }); - }, [claimId]); + }, [currentView]); React.useEffect(() => { fetchSubCount(claimId); @@ -146,12 +119,11 @@ function ChannelPage(props: Props) { noFooter noSideNavigation={editing} backout={{ - backFunction: onDone, title: __('Editing @%channel%', { channel: channelName }), simpleTitle: __('Editing'), }} > - + goBack()} /> ); } @@ -159,15 +131,7 @@ function ChannelPage(props: Props) { return ( - - {lastYtSyncDate && ( -
    - - {__('Official YouTube Creator - Last updated %time_ago%', { - time_ago: DateTime.getTimeAgoStr(lastYtSyncDate), - })} -
    - )} +
    {!channelIsBlocked && !channelIsBlackListed && } @@ -202,7 +166,7 @@ function ChannelPage(props: Props) {
    @@ -96,12 +97,12 @@ function FileListPublished(props: Props) { {!fetching ? (
    -

    {__('Nothing published to LBRY yet.')}

    +

    {__('Nothing uploaded to LBRY yet.')}

    diff --git a/ui/page/help/view.jsx b/ui/page/help/view.jsx index 2d060738df9..125f896cc3a 100644 --- a/ui/page/help/view.jsx +++ b/ui/page/help/view.jsx @@ -148,6 +148,21 @@ class HelpPage extends React.PureComponent { } /> + +
    + } + /> + , @@ -61,21 +61,20 @@ function HomePage(props: Props) { {rowData.map(({ title, link, help, options = {} }) => (

    - {link ? ( -

    + {link && ( +
    ))} diff --git a/ui/page/invite/index.js b/ui/page/invite/index.js index 506e49632c1..2593f715424 100644 --- a/ui/page/invite/index.js +++ b/ui/page/invite/index.js @@ -1,4 +1,4 @@ -import * as SETTINGS from 'constants/settings'; +import { SETTINGS } from 'lbry-redux'; import { connect } from 'react-redux'; import { selectUserInviteStatusFailed, diff --git a/ui/page/listBlocked/index.js b/ui/page/listBlocked/index.js index c8088e9a535..80ecb2e976d 100644 --- a/ui/page/listBlocked/index.js +++ b/ui/page/listBlocked/index.js @@ -1,12 +1,9 @@ import { connect } from 'react-redux'; -import { selectBlockedChannels } from 'lbry-redux'; +import { selectBlockedChannels } from 'redux/selectors/blocked'; import ListBlocked from './view'; const select = state => ({ uris: selectBlockedChannels(state), }); -export default connect( - select, - null -)(ListBlocked); +export default connect(select, null)(ListBlocked); diff --git a/ui/page/listBlocked/view.jsx b/ui/page/listBlocked/view.jsx index 44cdfd8852d..9be6d301555 100644 --- a/ui/page/listBlocked/view.jsx +++ b/ui/page/listBlocked/view.jsx @@ -2,6 +2,7 @@ import React from 'react'; import ClaimList from 'component/claimList'; import Page from 'component/page'; +import Card from 'component/common/card'; type Props = { uris: Array, @@ -13,13 +14,10 @@ function ListBlocked(props: Props) { return ( {uris && uris.length ? ( - {__('Your Blocked Channels')}} - persistedStorageKey="block-list-published" - uris={uris} - defaultSort - showUnresolvedClaims - showHiddenByUser + } /> ) : (
    diff --git a/ui/page/notifications/index.js b/ui/page/notifications/index.js new file mode 100644 index 00000000000..0218f2329a4 --- /dev/null +++ b/ui/page/notifications/index.js @@ -0,0 +1,15 @@ +import { connect } from 'react-redux'; +import { + selectNotifications, + selectIsFetchingNotifications, + selectUnreadNotificationCount, +} from 'redux/selectors/notifications'; +import NotificationsPage from './view'; + +const select = state => ({ + notifications: selectNotifications(state), + fetching: selectIsFetchingNotifications(state), + unreadCount: selectUnreadNotificationCount(state), +}); + +export default connect(select)(NotificationsPage); diff --git a/ui/page/notifications/view.jsx b/ui/page/notifications/view.jsx new file mode 100644 index 00000000000..fd251768952 --- /dev/null +++ b/ui/page/notifications/view.jsx @@ -0,0 +1,40 @@ +// @flow +import React from 'react'; +import Page from 'component/page'; +import Card from 'component/common/card'; +import Spinner from 'component/spinner'; +import Notification from 'component/notification'; + +type Props = { + notifications: ?Array, + fetching: boolean, +}; + +export default function NotificationsPage(props: Props) { + const { notifications, fetching } = props; + + return ( + + {fetching && ( +
    + +
    + )} + {notifications && notifications.length > 0 ? ( + + {notifications.map((notification, index) => { + return ; + })} +
    + } + /> + ) : ( +
    {__('No notifications')}
    + )} +
    + ); +} diff --git a/ui/page/publish/view.jsx b/ui/page/publish/view.jsx index 85a7cba4006..2a6f0037037 100644 --- a/ui/page/publish/view.jsx +++ b/ui/page/publish/view.jsx @@ -34,7 +34,7 @@ function PublishPage(props: Props) {

    diff --git a/ui/page/search/index.js b/ui/page/search/index.js index 2386e45c7bb..c2cfc011357 100644 --- a/ui/page/search/index.js +++ b/ui/page/search/index.js @@ -1,6 +1,12 @@ import { connect } from 'react-redux'; -import * as SETTINGS from 'constants/settings'; -import { doSearch, selectIsSearching, makeSelectSearchUris, makeSelectQueryWithOptions, doToast } from 'lbry-redux'; +import { + doSearch, + selectIsSearching, + makeSelectSearchUris, + makeSelectQueryWithOptions, + doToast, + SETTINGS, +} from 'lbry-redux'; import { makeSelectClientSetting } from 'redux/selectors/settings'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import analytics from 'analytics'; diff --git a/ui/page/search/view.jsx b/ui/page/search/view.jsx index 4b81f84c9da..35e3ac6cab6 100644 --- a/ui/page/search/view.jsx +++ b/ui/page/search/view.jsx @@ -1,4 +1,5 @@ // @flow +import { SIMPLE_SITE } from 'config'; import * as ICONS from 'constants/icons'; import * as PAGES from 'constants/pages'; import React, { useEffect, Fragment } from 'react'; @@ -75,23 +76,25 @@ export default function SearchPage(props: Props) {

    {urlQuery && ( -
    -
    - -
    -
    - -
    -
    + {!SIMPLE_SITE && ( +
    +
    + +
    +
    + +
    +
    + )} ({ allowAnalytics: selectAllowAnalytics(state), isAuthenticated: selectUserVerifiedEmail(state), showNsfw: makeSelectClientSetting(SETTINGS.SHOW_MATURE)(state), - instantPurchaseEnabled: makeSelectClientSetting(SETTINGS.INSTANT_PURCHASE_ENABLED)(state), - instantPurchaseMax: makeSelectClientSetting(SETTINGS.INSTANT_PURCHASE_MAX)(state), currentTheme: makeSelectClientSetting(SETTINGS.THEME)(state), themes: makeSelectClientSetting(SETTINGS.THEMES)(state), automaticDarkModeEnabled: makeSelectClientSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED)(state), @@ -44,24 +31,21 @@ const select = state => ({ floatingPlayer: makeSelectClientSetting(SETTINGS.FLOATING_PLAYER)(state), hideReposts: makeSelectClientSetting(SETTINGS.HIDE_REPOSTS)(state), darkModeTimes: makeSelectClientSetting(SETTINGS.DARK_MODE_TIMES)(state), - ffmpegStatus: selectFfmpegStatus(state), - findingFFmpeg: selectFindingFFmpeg(state), language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state), + syncEnabled: makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state), }); const perform = dispatch => ({ setDaemonSetting: (key, value) => dispatch(doSetDaemonSetting(key, value)), + syncSettings: () => dispatch(doSyncClientSettings()), clearDaemonSetting: key => dispatch(doClearDaemonSetting(key)), toggle3PAnalytics: allow => dispatch(doToggle3PAnalytics(allow)), clearCache: () => dispatch(doClearCache()), setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)), - encryptWallet: () => dispatch(doNotifyEncryptWallet()), - decryptWallet: () => dispatch(doNotifyDecryptWallet()), updateWalletStatus: () => dispatch(doWalletStatus()), confirmForgetPassword: modalProps => dispatch(doNotifyForgetPassword(modalProps)), clearPlayingUri: () => dispatch(doSetPlayingUri(null)), setDarkTime: (time, options) => dispatch(doSetDarkTime(time, options)), - findFFmpeg: () => dispatch(doFindFFmpeg()), openModal: (id, params) => dispatch(doOpenModal(id, params)), }); diff --git a/ui/page/settings/view.jsx b/ui/page/settings/view.jsx index c43f9110116..f19dbb09d85 100644 --- a/ui/page/settings/view.jsx +++ b/ui/page/settings/view.jsx @@ -1,38 +1,27 @@ // @flow -/* eslint react/no-unescaped-entities:0 */ -/* eslint react/jsx-no-comment-textnodes:0 */ - 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, FormFieldPrice } from 'component/common/form'; +import { FormField } from 'component/common/form'; import Button from 'component/button'; -import I18nMessage from 'component/i18nMessage'; import Page from 'component/page'; import SettingLanguage from 'component/settingLanguage'; -import SettingWalletServer from 'component/settingWalletServer'; -import SettingAutoLaunch from 'component/settingAutoLaunch'; import FileSelector from 'component/common/file-selector'; import SyncToggle from 'component/syncToggle'; -import { SETTINGS } from 'lbry-redux'; import Card from 'component/common/card'; -import { getPasswordFromCookie } from 'util/saved-passwords'; -import Spinner from 'component/spinner'; import SettingAccountPassword from 'component/settingAccountPassword'; +import { getPasswordFromCookie } from 'util/saved-passwords'; import { Lbryio } from 'lbryinc'; -// @if TARGET='app' -export const IS_MAC = process.platform === 'darwin'; -// @endif - type Price = { currency: string, amount: number, }; -type SetDaemonSettingArg = boolean | string | number | Price; +type SetDaemonSettingArg = boolean | string | number; type DarkModeTimes = { from: { hour: string, min: string, formattedTime: string }, @@ -47,11 +36,6 @@ type OptionTimes = { type DaemonSettings = { download_dir: string, share_usage_data: boolean, - max_key_fee?: Price, - max_connections_per_download?: number, - save_files: boolean, - save_blobs: boolean, - ffmpeg_path: string, }; type Props = { @@ -70,24 +54,19 @@ type Props = { themes: Array, automaticDarkModeEnabled: boolean, autoplay: boolean, - // autoDownload: boolean, - encryptWallet: () => void, - decryptWallet: () => void, updateWalletStatus: () => void, walletEncrypted: boolean, userBlockedChannelsCount?: number, - hideBalance: boolean, confirmForgetPassword: ({}) => void, floatingPlayer: boolean, hideReposts: ?boolean, clearPlayingUri: () => void, darkModeTimes: DarkModeTimes, setDarkTime: (string, {}) => void, - ffmpegStatus: { available: boolean, which: string }, - findingFFmpeg: boolean, - findFFmpeg: () => void, openModal: string => void, language?: string, + syncEnabled: boolean, + syncSettings: () => void, }; type State = { @@ -104,28 +83,16 @@ class SettingsPage extends React.PureComponent { storedPassword: false, }; - (this: any).onKeyFeeChange = this.onKeyFeeChange.bind(this); - (this: any).onMaxConnectionsChange = this.onMaxConnectionsChange.bind(this); - (this: any).onKeyFeeDisableChange = this.onKeyFeeDisableChange.bind(this); - (this: any).onInstantPurchaseMaxChange = this.onInstantPurchaseMaxChange.bind(this); (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); + (this: any).onDone = this.onDone.bind(this); } componentDidMount() { - const { isAuthenticated, ffmpegStatus, daemonSettings, findFFmpeg } = this.props; - // @if TARGET='app' - const { available } = ffmpegStatus; - const { ffmpeg_path: ffmpegPath } = daemonSettings; - if (!available) { - if (ffmpegPath) { - this.clearDaemonSetting('ffmpeg_path'); - } - findFFmpeg(); - } - // @endif + const { isAuthenticated } = this.props; + if (isAuthenticated || !IS_WEB) { this.props.updateWalletStatus(); getPasswordFromCookie().then(p => { @@ -136,22 +103,12 @@ class SettingsPage extends React.PureComponent { } } - onFFmpegFolder(path: string) { - this.setDaemonSetting('ffmpeg_path', path); - this.findFFmpeg(); - } - - onKeyFeeChange(newValue: Price) { - this.setDaemonSetting('max_key_fee', newValue); - } - - onMaxConnectionsChange(event: SyntheticInputEvent<*>) { - const { value } = event.target; - this.setDaemonSetting('max_connections_per_download', value); - } + onDone() { + const { syncSettings } = this.props; - onKeyFeeDisableChange(isDisabled: boolean) { - if (isDisabled) this.setDaemonSetting('max_key_fee'); + if (this.props.syncEnabled) { + syncSettings(); + } } onThemeChange(event: SyntheticInputEvent<*>) { @@ -168,23 +125,6 @@ class SettingsPage extends React.PureComponent { this.props.setClientSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED, value); } - onInstantPurchaseEnabledChange(enabled: boolean) { - this.props.setClientSetting(SETTINGS.INSTANT_PURCHASE_ENABLED, enabled); - } - - onInstantPurchaseMaxChange(newValue: Price) { - this.props.setClientSetting(SETTINGS.INSTANT_PURCHASE_MAX, newValue); - } - - onChangeEncryptWallet() { - const { decryptWallet, walletEncrypted, encryptWallet } = this.props; - if (walletEncrypted) { - decryptWallet(); - } else { - encryptWallet(); - } - } - onConfirmForgetPassword() { const { confirmForgetPassword } = this.props; confirmForgetPassword({ @@ -216,18 +156,11 @@ class SettingsPage extends React.PureComponent { this.props.clearDaemonSetting(name); } - findFFmpeg(): void { - this.props.findFFmpeg(); - } - render() { const { daemonSettings, - ffmpegStatus, allowAnalytics, showNsfw, - instantPurchaseEnabled, - instantPurchaseMax, isAuthenticated, currentTheme, themes, @@ -238,31 +171,30 @@ class SettingsPage extends React.PureComponent { setDaemonSetting, setClientSetting, toggle3PAnalytics, - hideBalance, userBlockedChannelsCount, floatingPlayer, hideReposts, clearPlayingUri, darkModeTimes, clearCache, - findingFFmpeg, openModal, - language, } = this.props; const { storedPassword } = this.state; const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0; - // @if TARGET='app' - const { available: ffmpegAvailable, which: ffmpegPath } = ffmpegStatus; - // @endif - const defaultMaxKeyFee = { currency: 'USD', amount: 50 }; - - const disableMaxKeyFee = !(daemonSettings && daemonSettings.max_key_fee); - const connectionOptions = [1, 2, 4, 6, 10, 20]; const startHours = ['18', '19', '20', '21']; const endHours = ['5', '6', '7', '8']; return ( - + this.onDone(), + title: __('Settings'), + backLabel: __('Done'), + }} + className="card-stack" + > {!IS_WEB && noDaemonSettings ? (
    {__('Failed to load settings.')}
    @@ -272,15 +204,6 @@ class SettingsPage extends React.PureComponent { } /> {isAuthenticated && } {/* @if TARGET='app' */} - } - /> { } /> - - - setDaemonSetting('save_files', !daemonSettings.save_files)} - checked={daemonSettings.save_files} - label={__('Save all viewed content to your downloads directory')} - helper={__( - 'Paid content and some file types are saved by default. Changing this setting will not affect previously downloaded content.' - )} - /> - - setDaemonSetting('save_blobs', !daemonSettings.save_blobs)} - checked={daemonSettings.save_blobs} - label={__('Save hosting data to help the LBRY network')} - helper={ - - {__("If disabled, LBRY will be very sad and you won't be helping improve the network.")}{' '} -
    - } - /> - - -
    - } - /> - - )} - - {/* @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)` - )}{' '} -
    + } + /> + + +
    + } + /> + + +