From ff059c58fd88454c8eaa9cba89300aebad6f288a Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Thu, 15 Jul 2021 09:57:55 +0800 Subject: [PATCH 01/80] Fix continuous reaction fetch in incognito myReactions will never be filled in incognito. Also, it's probably enough to just check othersReactions, but for now, still do both when logged in. --- ui/component/commentsList/view.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/component/commentsList/view.jsx b/ui/component/commentsList/view.jsx index a4714bca8..cd3d1e6b4 100644 --- a/ui/component/commentsList/view.jsx +++ b/ui/component/commentsList/view.jsx @@ -130,7 +130,7 @@ function CommentList(props: Props) { } else { idsForReactionFetch = allCommentIds.filter((commentId) => { const key = activeChannelId ? `${commentId}:${activeChannelId}` : commentId; - return !othersReactsById[key] || !myReactsByCommentId[key]; + return !othersReactsById[key] || (activeChannelId && !myReactsByCommentId[key]); }); } From 47b594107a89827d4b8c2f80738c1b0f2a785a24 Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Thu, 15 Jul 2021 14:39:44 +0800 Subject: [PATCH 02/80] Use better icon for "Copy Link" Not re-using the same icon as "Share". --- ui/component/claimMenuList/view.jsx | 2 +- ui/component/common/icon-custom.jsx | 6 ++++++ ui/constants/icons.js | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ui/component/claimMenuList/view.jsx b/ui/component/claimMenuList/view.jsx index 6d11581ed..df7925e82 100644 --- a/ui/component/claimMenuList/view.jsx +++ b/ui/component/claimMenuList/view.jsx @@ -411,7 +411,7 @@ function ClaimMenuList(props: Props) {
- + {__('Copy Link')}
diff --git a/ui/component/common/icon-custom.jsx b/ui/component/common/icon-custom.jsx index 8cf72cc42..c28e8de54 100644 --- a/ui/component/common/icon-custom.jsx +++ b/ui/component/common/icon-custom.jsx @@ -772,6 +772,12 @@ export const icons = { viewBox: '0 0 60 60', } ), + [ICONS.COPY_LINK]: buildIcon( + + + + + ), [ICONS.PURCHASED]: buildIcon( diff --git a/ui/constants/icons.js b/ui/constants/icons.js index 2e9793e83..8f57851ee 100644 --- a/ui/constants/icons.js +++ b/ui/constants/icons.js @@ -52,6 +52,7 @@ export const LINKEDIN = 'LinkedIn'; export const EMBED = 'Embed'; export const MORE = 'More'; export const SHARE_LINK = 'ShareLink'; +export const COPY_LINK = 'CopyLink'; export const ACCOUNT = 'User'; export const SETTINGS = 'Settings'; export const FILTER = 'Filter'; From 08548916df69d821376564fd6729ae8adc0931d1 Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Thu, 15 Jul 2021 22:23:14 +0800 Subject: [PATCH 03/80] Revert "Fix continuous reaction fetch in incognito" This reverts commit ff059c58fd88454c8eaa9cba89300aebad6f288a. --- ui/component/commentsList/view.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/component/commentsList/view.jsx b/ui/component/commentsList/view.jsx index cd3d1e6b4..a4714bca8 100644 --- a/ui/component/commentsList/view.jsx +++ b/ui/component/commentsList/view.jsx @@ -130,7 +130,7 @@ function CommentList(props: Props) { } else { idsForReactionFetch = allCommentIds.filter((commentId) => { const key = activeChannelId ? `${commentId}:${activeChannelId}` : commentId; - return !othersReactsById[key] || (activeChannelId && !myReactsByCommentId[key]); + return !othersReactsById[key] || !myReactsByCommentId[key]; }); } From a2a1ddb403c4ff1198c02c590946a56164d93762 Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Thu, 15 Jul 2021 22:23:26 +0800 Subject: [PATCH 04/80] Revert "Comments Pagination #6390" This reverts commit 16ef013025588edd9c3e7b52b892a8dc1bb5eb58, reversing changes made to fba8b89b3b5aa8b20125714b92a6de23d25f46c3. --- flow-typed/Comment.js | 66 +---- static/app-strings.json | 2 - ui/comments.js | 1 - ui/component/channelDiscussion/index.js | 4 +- ui/component/channelDiscussion/view.jsx | 6 +- ui/component/comment/index.js | 43 ++- ui/component/comment/view.jsx | 83 +----- ui/component/commentCreate/view.jsx | 11 +- ui/component/commentMenuList/index.js | 4 +- ui/component/commentMenuList/view.jsx | 13 +- ui/component/commentReactions/index.js | 23 +- ui/component/commentsList/index.js | 40 ++- ui/component/commentsList/view.jsx | 233 +++++++---------- ui/component/commentsReplies/index.js | 10 +- ui/component/commentsReplies/view.jsx | 104 ++++---- ui/component/livestreamComments/view.jsx | 4 +- ui/constants/action_types.js | 2 - ui/constants/comment.js | 10 - ui/page/file/index.js | 4 +- ui/page/file/view.jsx | 8 +- ui/redux/actions/comments.js | 114 +------- ui/redux/reducers/comments.js | 316 +++-------------------- ui/redux/selectors/comments.js | 36 +-- ui/scss/component/_comments.scss | 4 - ui/util/comments.js | 9 +- 25 files changed, 273 insertions(+), 877 deletions(-) diff --git a/flow-typed/Comment.js b/flow-typed/Comment.js index 15c6d3038..adbecea26 100644 --- a/flow-typed/Comment.js +++ b/flow-typed/Comment.js @@ -13,7 +13,6 @@ declare type Comment = { parent_id?: number, // comment_id of comment this is in reply to is_pinned: boolean, support_amount: number, - replies: number, // number of direct replies (i.e. excluding nested replies). }; declare type PerChannelSettings = { @@ -28,21 +27,15 @@ declare type PerChannelSettings = { declare type CommentsState = { commentsByUri: { [string]: string }, superChatsByUri: { [string]: { totalAmount: number, comments: Array } }, - byId: { [string]: Array }, // ClaimID -> list of fetched comment IDs. - totalCommentsById: {}, // ClaimId -> ultimate total (including replies) in commentron. - repliesByParentId: { [string]: Array }, // ParentCommentID -> list of fetched replies. - totalRepliesByParentId: {}, // ParentCommentID -> total replies in commentron. - topLevelCommentsById: { [string]: Array }, // ClaimID -> list of fetched top level comments. - topLevelTotalPagesById: { [string]: number }, // ClaimID -> total number of top-level pages in commentron. Based on COMMENT_PAGE_SIZE_TOP_LEVEL. - topLevelTotalCommentsById: { [string]: number }, // ClaimID -> total top level comments in commentron. + byId: { [string]: Array }, + repliesByParentId: { [string]: Array }, // ParentCommentID -> list of reply comments + topLevelCommentsById: { [string]: Array }, // ClaimID -> list of top level comments commentById: { [string]: Comment }, - linkedCommentAncestors: { [string]: Array }, // {"linkedCommentId": ["parentId", "grandParentId", ...]} isLoading: boolean, - isLoadingByParentId: { [string]: boolean }, myComments: ?Set, isFetchingReacts: boolean, - myReactsByCommentId: ?{ [string]: Array }, // {"CommentId:MyChannelId": ["like", "dislike", ...]} - othersReactsByCommentId: ?{ [string]: { [string]: number } }, // {"CommentId:MyChannelId": {"like": 2, "dislike": 2, ...}} + myReactsByCommentId: any, + othersReactsByCommentId: any, pendingCommentReactions: Array, moderationBlockList: ?Array, // @KP rename to "personalBlockList"? adminBlockList: ?Array, @@ -71,48 +64,17 @@ declare type CommentReactParams = { remove?: boolean, }; -declare type CommentReactListParams = { - comment_ids?: string, - channel_id?: string, - channel_name?: string, - wallet_id?: string, - react_types?: string, -}; - declare type CommentListParams = { - page: number, // pagination: which page of results - page_size: number, // pagination: nr of comments to show in a page (max 200) - claim_id: string, // claim id of claim being commented on - channel_name?: string, // signing channel name of claim (enables 'commentsEnabled' check) - channel_id?: string, // signing channel claim id of claim (enables 'commentsEnabled' check) - author_claim_id?: string, // filters comments to just this author - parent_id?: string, // filters comments to those under this thread - top_level?: boolean, // filters to only top level comments - hidden?: boolean, // if true, will show hidden comments as well - sort_by?: number, // NEWEST=0, OLDEST=1, CONTROVERSY=2, POPULARITY=3, + page: number, + page_size: number, + claim_id: string, }; declare type CommentListResponse = { items: Array, - page: number, - page_size: number, - total_items: number, // Grand total for the claim being commented on. - total_filtered_items: number, // Total for filtered queries (e.g. top_level=true, parent_id=xxx, etc.). - total_pages: number, - has_hidden_comments: boolean, + total_amount: number, }; -declare type CommentByIdParams = { - comment_id: string, - with_ancestors: boolean, -} - -declare type CommentByIdResponse = { - item: Comment, - items: Comment, - ancestors: Array, -} - declare type CommentAbandonParams = { comment_id: string, creator_channel_id?: string, @@ -132,16 +94,6 @@ declare type CommentCreateParams = { declare type SuperListParams = {}; -declare type SuperListResponse = { - page: number, - page_size: number, - total_pages: number, - total_items: number, - total_amount: number, - items: Array, - has_hidden_comments: boolean, -}; - declare type ModerationBlockParams = {}; declare type ModerationAddDelegateParams = { diff --git a/static/app-strings.json b/static/app-strings.json index e3849098f..6f4749142 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -1445,7 +1445,6 @@ "You loved this": "You loved this", "Creator loved this": "Creator loved this", "A channel is required to throw fire and slime": "A channel is required to throw fire and slime", - "The requested comment is no longer available.": "The requested comment is no longer available.", "Best": "Best", "Controversial": "Controversial", "Show Replies": "Show Replies", @@ -1514,7 +1513,6 @@ "Create A Channel": "Create A Channel", "At least 10 views are required to earn the reward, consume more!": "At least 10 views are required to earn the reward, consume more!", "Blocked %channel%": "Blocked %channel%", - "Comment(s) blocked.": "Comment(s) blocked.", "You earned %lbc% for streaming your first video.": "You earned %lbc% for streaming your first video.", "You earned %lbc% for successfully completing The Journey L4: Perfect Harmony.": "You earned %lbc% for successfully completing The Journey L4: Perfect Harmony.", "You earned %lbc% for successfully completing The Journey L3: Bliss.": "You earned %lbc% for successfully completing The Journey L3: Bliss.", diff --git a/ui/comments.js b/ui/comments.js index 885d54715..912c7266e 100644 --- a/ui/comments.js +++ b/ui/comments.js @@ -17,7 +17,6 @@ const Comments = { comment_list: (params: CommentListParams) => fetchCommentsApi('comment.List', params), comment_abandon: (params: CommentAbandonParams) => fetchCommentsApi('comment.Abandon', params), comment_create: (params: CommentCreateParams) => fetchCommentsApi('comment.Create', params), - comment_by_id: (params: CommentByIdParams) => fetchCommentsApi('comment.ByID', params), setting_list: (params: SettingsParams) => fetchCommentsApi('setting.List', params), setting_block_word: (params: BlockWordParams) => fetchCommentsApi('setting.BlockWord', params), setting_unblock_word: (params: BlockWordParams) => fetchCommentsApi('setting.UnBlockWord', params), diff --git a/ui/component/channelDiscussion/index.js b/ui/component/channelDiscussion/index.js index ff198701f..cb0c52704 100644 --- a/ui/component/channelDiscussion/index.js +++ b/ui/component/channelDiscussion/index.js @@ -1,5 +1,6 @@ import { connect } from 'react-redux'; import { withRouter } from 'react-router'; +import { makeSelectCommentForCommentId } from 'redux/selectors/comments'; import { DISABLE_COMMENTS_TAG } from 'constants/tags'; import ChannelDiscussion from './view'; import { makeSelectTagInClaimOrChannelForUri } from 'lbry-redux'; @@ -7,9 +8,10 @@ import { makeSelectTagInClaimOrChannelForUri } from 'lbry-redux'; const select = (state, props) => { const { search } = props.location; const urlParams = new URLSearchParams(search); + const linkedCommentId = urlParams.get('lc'); return { - linkedCommentId: urlParams.get('lc'), + linkedComment: makeSelectCommentForCommentId(linkedCommentId)(state), commentsDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state), }; }; diff --git a/ui/component/channelDiscussion/view.jsx b/ui/component/channelDiscussion/view.jsx index 15b215f50..50a308a70 100644 --- a/ui/component/channelDiscussion/view.jsx +++ b/ui/component/channelDiscussion/view.jsx @@ -5,19 +5,19 @@ import Empty from 'component/common/empty'; type Props = { uri: string, - linkedCommentId?: string, + linkedComment: ?any, commentsDisabled: boolean, }; function ChannelDiscussion(props: Props) { - const { uri, linkedCommentId, commentsDisabled } = props; + const { uri, linkedComment, commentsDisabled } = props; if (commentsDisabled) { return ; } return (
- +
); } diff --git a/ui/component/comment/index.js b/ui/component/comment/index.js index 9e4ed5825..0e92f94f5 100644 --- a/ui/component/comment/index.js +++ b/ui/component/comment/index.js @@ -1,43 +1,30 @@ import { connect } from 'react-redux'; -import { - makeSelectStakedLevelForChannelUri, - makeSelectClaimForUri, - makeSelectThumbnailForUri, - selectMyChannelClaims, -} from 'lbry-redux'; -import { doCommentUpdate, doCommentList } from 'redux/actions/comments'; +import { makeSelectStakedLevelForChannelUri, makeSelectClaimForUri, makeSelectThumbnailForUri, selectMyChannelClaims } from 'lbry-redux'; +import { doCommentUpdate } from 'redux/actions/comments'; import { makeSelectChannelIsMuted } from 'redux/selectors/blocked'; import { doToast } from 'redux/actions/notifications'; import { doSetPlayingUri } from 'redux/actions/content'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; -import { selectLinkedCommentAncestors, makeSelectOthersReactionsForComment } from 'redux/selectors/comments'; -import { selectActiveChannelId, selectActiveChannelClaim } from 'redux/selectors/app'; +import { makeSelectOthersReactionsForComment } from 'redux/selectors/comments'; +import { selectActiveChannelClaim } from 'redux/selectors/app'; import { selectPlayingUri } from 'redux/selectors/content'; import Comment from './view'; -const select = (state, props) => { - const activeChannelId = selectActiveChannelId(state); - const reactionKey = activeChannelId ? `${props.commentId}:${activeChannelId}` : props.commentId; - - return { - claim: makeSelectClaimForUri(props.uri)(state), - thumbnail: props.authorUri && makeSelectThumbnailForUri(props.authorUri)(state), - channelIsBlocked: props.authorUri && makeSelectChannelIsMuted(props.authorUri)(state), - commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true, - othersReacts: makeSelectOthersReactionsForComment(reactionKey)(state), - activeChannelClaim: selectActiveChannelClaim(state), - myChannels: selectMyChannelClaims(state), - playingUri: selectPlayingUri(state), - stakedLevel: makeSelectStakedLevelForChannelUri(props.authorUri)(state), - linkedCommentAncestors: selectLinkedCommentAncestors(state), - }; -}; +const select = (state, props) => ({ + claim: makeSelectClaimForUri(props.uri)(state), + thumbnail: props.authorUri && makeSelectThumbnailForUri(props.authorUri)(state), + channelIsBlocked: props.authorUri && makeSelectChannelIsMuted(props.authorUri)(state), + commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true, + othersReacts: makeSelectOthersReactionsForComment(props.commentId)(state), + activeChannelClaim: selectActiveChannelClaim(state), + myChannels: selectMyChannelClaims(state), + playingUri: selectPlayingUri(state), + stakedLevel: makeSelectStakedLevelForChannelUri(props.authorUri)(state), +}); const perform = (dispatch) => ({ clearPlayingUri: () => dispatch(doSetPlayingUri({ uri: null })), updateComment: (commentId, comment) => dispatch(doCommentUpdate(commentId, comment)), - fetchReplies: (uri, parentId, page, pageSize, sortBy) => - dispatch(doCommentList(uri, parentId, page, pageSize, sortBy)), doToast: (options) => dispatch(doToast(options)), }); diff --git a/ui/component/comment/view.jsx b/ui/component/comment/view.jsx index 19afc945d..421e4f7b4 100644 --- a/ui/component/comment/view.jsx +++ b/ui/component/comment/view.jsx @@ -1,7 +1,6 @@ // @flow import * as ICONS from 'constants/icons'; import * as PAGES from 'constants/pages'; -import { SORT_BY, COMMENT_PAGE_SIZE_REPLIES } from 'constants/comment'; import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field'; import { SITE_NAME, SIMPLE_SITE, ENABLE_COMMENT_REACTIONS } from 'config'; import React, { useEffect, useState } from 'react'; @@ -24,8 +23,6 @@ import CommentMenuList from 'component/commentMenuList'; import UriIndicator from 'component/uriIndicator'; import CreditAmount from 'component/common/credit-amount'; -const AUTO_EXPAND_ALL_REPLIES = false; - type Props = { clearPlayingUri: () => void, uri: string, @@ -39,10 +36,8 @@ type Props = { claimIsMine: boolean, // if you control the claim which this comment was posted on commentIsMine: boolean, // if this comment was signed by an owned channel updateComment: (string, string) => void, - fetchReplies: (string, string, number, number, number) => void, commentModBlock: (string) => void, - linkedCommentId?: string, - linkedCommentAncestors: { [string]: Array }, + linkedComment?: any, myChannels: ?Array, commentingEnabled: boolean, doToast: ({ message: string }) => void, @@ -58,7 +53,6 @@ type Props = { playingUri: ?PlayingUri, stakedLevel: number, supportAmount: number, - numDirectReplies: number, }; const LENGTH_TO_COLLAPSE = 300; @@ -77,9 +71,7 @@ function Comment(props: Props) { commentIsMine, commentId, updateComment, - fetchReplies, - linkedCommentId, - linkedCommentAncestors, + linkedComment, commentingEnabled, myChannels, doToast, @@ -90,23 +82,18 @@ function Comment(props: Props) { playingUri, stakedLevel, supportAmount, - numDirectReplies, } = props; - const { push, replace, location: { pathname, search }, } = useHistory(); - const [isReplying, setReplying] = React.useState(false); const [isEditing, setEditing] = useState(false); const [editedMessage, setCommentValue] = useState(message); const [charCount, setCharCount] = useState(editedMessage.length); // used for controlling the visibility of the menu icon const [mouseIsHovering, setMouseHover] = useState(false); - const [showReplies, setShowReplies] = useState(false); - const [page, setPage] = useState(0); const [advancedEditor] = usePersistedState('comment-editor-mode', false); const [displayDeadComment, setDisplayDeadComment] = React.useState(false); const hasChannels = myChannels && myChannels.length > 0; @@ -124,19 +111,6 @@ function Comment(props: Props) { } } catch (e) {} - // Auto-expand (limited to linked-comments for now, but can be for all) - useEffect(() => { - const isInLinkedCommentChain = - linkedCommentId && - linkedCommentAncestors[linkedCommentId] && - linkedCommentAncestors[linkedCommentId].includes(commentId); - - if (isInLinkedCommentChain || AUTO_EXPAND_ALL_REPLIES) { - setShowReplies(true); - setPage(1); - } - }, []); // eslint-disable-line react-hooks/exhaustive-deps - useEffect(() => { if (isEditing) { setCharCount(editedMessage.length); @@ -157,12 +131,6 @@ function Comment(props: Props) { } }, [author, authorUri, editedMessage, isEditing, setEditing]); - useEffect(() => { - if (page > 0) { - fetchReplies(uri, commentId, page, COMMENT_PAGE_SIZE_REPLIES, SORT_BY.OLDEST); - } - }, [page, uri, commentId, fetchReplies]); - function handleEditMessageChanged(event) { setCommentValue(!SIMPLE_SITE && advancedEditor ? event : event.target.value); } @@ -208,7 +176,7 @@ function Comment(props: Props) { >
@@ -334,43 +302,13 @@ function Comment(props: Props) { {ENABLE_COMMENT_REACTIONS && }
- {numDirectReplies > 0 && !showReplies && ( -
-
- )} - - {numDirectReplies > 0 && showReplies && ( -
-
- )} - {isReplying && ( { - setShowReplies(true); - setReplying(false); - }} - onCancelReplying={() => { - setReplying(false); - }} + onDoneReplying={() => setReplying(false)} + onCancelReplying={() => setReplying(false)} /> )} @@ -379,16 +317,7 @@ function Comment(props: Props) { - {showReplies && ( - setPage(page + 1)} - /> - )} + ); } diff --git a/ui/component/commentCreate/view.jsx b/ui/component/commentCreate/view.jsx index 4c32eca47..e683d9b20 100644 --- a/ui/component/commentCreate/view.jsx +++ b/ui/component/commentCreate/view.jsx @@ -35,6 +35,7 @@ type Props = { toast: (string) => void, claimIsMine: boolean, sendTip: ({}, (any) => void, (any) => void) => void, + justCommented: Array, }; export function CommentCreate(props: Props) { @@ -53,6 +54,7 @@ export function CommentCreate(props: Props) { livestream, claimIsMine, sendTip, + justCommented, } = props; const buttonref: ElementRef = React.useRef(); const { @@ -151,6 +153,7 @@ export function CommentCreate(props: Props) { setIsReviewingSupportComment(false); setIsSupportComment(false); setCommentFailure(false); + justCommented.push(res.comment_id); if (onDoneReplying) { onDoneReplying(); @@ -214,13 +217,7 @@ export function CommentCreate(props: Props) { autoFocus button="primary" disabled={disabled} - label={ - isSubmitting - ? __('Sending...') - : commentFailure && tipAmount === successTip.tipAmount - ? __('Re-submit') - : __('Send') - } + label={isSubmitting ? __('Sending...') : (commentFailure && tipAmount === successTip.tipAmount) ? __('Re-submit') : __('Send')} onClick={handleSupportComment} /> + + ); +} From be9640972eb21fcdff9291e512c971c4daa208f9 Mon Sep 17 00:00:00 2001 From: zeppi Date: Mon, 19 Jul 2021 14:16:55 -0400 Subject: [PATCH 57/80] meme style --- ui/scss/component/_meme.scss | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 ui/scss/component/_meme.scss diff --git a/ui/scss/component/_meme.scss b/ui/scss/component/_meme.scss new file mode 100644 index 000000000..e1e8234e7 --- /dev/null +++ b/ui/scss/component/_meme.scss @@ -0,0 +1,12 @@ +.home__meme { + text-align: center; + font-weight: bold; + line-height: 1; + font-size: 1rem; + margin-bottom: var(--spacing-m); + +@media (min-width: $breakpoint-small) { + font-size: 1.2rem; + margin-bottom: var(--spacing-l); +} +} From 424ba855072a6bb6784a31b7b6c2f8bca315523f Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Tue, 20 Jul 2021 02:31:33 +0800 Subject: [PATCH 58/80] 100% compression doesn't work with current CDN url ...sometimes produces larger-than-original file sizes too. --- ui/util/thumbnail.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/util/thumbnail.js b/ui/util/thumbnail.js index c35baba1c..3d5c8d73c 100644 --- a/ui/util/thumbnail.js +++ b/ui/util/thumbnail.js @@ -3,7 +3,7 @@ import { THUMBNAIL_CDN_URL } from 'config'; const THUMBNAIL_HEIGHT = 220; const THUMBNAIL_WIDTH = 390; -const THUMBNAIL_QUALITY = 100; +const THUMBNAIL_QUALITY = 85; type Props = { thumbnail: ?string, From 6fc44720d66e762efdd7a2dc8b98e24458267f4b Mon Sep 17 00:00:00 2001 From: zeppi Date: Mon, 19 Jul 2021 15:34:15 -0400 Subject: [PATCH 59/80] styles --- ui/scss/component/_button.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ui/scss/component/_button.scss b/ui/scss/component/_button.scss index a37a3a54a..74b600e41 100644 --- a/ui/scss/component/_button.scss +++ b/ui/scss/component/_button.scss @@ -620,6 +620,12 @@ svg + .button__label { border-top-left-radius: 0; border-bottom-left-radius: 0; } + + .button--file-action { + &:first-child { + margin-right: var(--spacing-s); + } + } } .button--file-action { From ed1671fe2f6e2e30c66d690887357ec64845a448 Mon Sep 17 00:00:00 2001 From: zeppi Date: Mon, 19 Jul 2021 17:29:01 -0400 Subject: [PATCH 60/80] matching comments --- ui/page/settingsStripeCard/view.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/page/settingsStripeCard/view.jsx b/ui/page/settingsStripeCard/view.jsx index e99ef2719..7fd138038 100644 --- a/ui/page/settingsStripeCard/view.jsx +++ b/ui/page/settingsStripeCard/view.jsx @@ -29,7 +29,7 @@ type Props = { openModal: (string, {}) => void, setAsConfirmingCard: () => void, }; -// + // type State = { // open: boolean, // currentFlowStage: string, From f6dc48fdc09c88df810827e2e321333cadb6367c Mon Sep 17 00:00:00 2001 From: zeppi Date: Mon, 19 Jul 2021 17:19:53 -0400 Subject: [PATCH 61/80] use odysee recsys plugin --- .../internal/plugins/videojs-recsys/plugin.js | 135 ++++++------------ 1 file changed, 45 insertions(+), 90 deletions(-) diff --git a/ui/component/viewers/videoViewer/internal/plugins/videojs-recsys/plugin.js b/ui/component/viewers/videoViewer/internal/plugins/videojs-recsys/plugin.js index 43858f814..d7bacdcce 100644 --- a/ui/component/viewers/videoViewer/internal/plugins/videojs-recsys/plugin.js +++ b/ui/component/viewers/videoViewer/internal/plugins/videojs-recsys/plugin.js @@ -95,10 +95,10 @@ class RecsysPlugin extends Component { this.player = player; this.recsysEvents = []; + this.loadedAt = Date.now(); this.lastTimeUpdate = null; this.currentTimeUpdate = null; - this.loadedAt = Date.now(); - this.playInitiated = false; + this.inPause = false; // Plugin event listeners player.on('playing', (event) => this.onPlay(event)); @@ -113,83 +113,13 @@ class RecsysPlugin extends Component { } addRecsysEvent(recsysEvent) { - if (!this.playInitiated) { - switch (recsysEvent.event) { - case RecsysData.event.start: - this.playInitiated = true; - break; - case RecsysData.event.scrub: - // If playback hasn't started, swallow scrub events. They offer some - // information, but if there isn't a subsequent play event, it's - // mostly nonsensical. - return undefined; - case RecsysData.event.stop: - // If playback hasn't started, swallow stop events. This means - // you're going to start from an offset but the start event - // captures that information. (With the ambiguity that you can't - // tell if they scrubbed, landed at the offset, or restarted. But - // I don't think that matters much.) - return undefined; - case RecsysData.event.speed: - if (this.recsysEvents.length > 0 && this.recsysEvents[0].event === RecsysData.event.speed) { - // video.js will sometimes fire the default play speed followed by the - // user preference. This is not useful information so we can keep the latter. - this.recsysEvents.pop(); - } - } - } else { - const lastEvent = this.recsysEvents[this.recsysEvents.length - 1]; - - switch (recsysEvent.event) { - case RecsysData.event.scrub: - if (lastEvent.event === RecsysData.event.stop) { - // Video.js fires a stop before the seek. This extra information isn't - // useful to log though, so this code prunes the stop event if it was - // within 0.25 seconds. - if (Math.abs(lastEvent.offset - recsysEvent.offset) < 0.25) { - this.recsysEvents.pop(); - recsysEvent.offset = lastEvent.arg; - } - } else if (lastEvent.event === RecsysData.event.start) { - // If the last event was a play and this event is a scrub close to - // that play position, I think it's just a weird emit order for - // video.js and we don't need to log the scrub. - if (Math.abs(lastEvent.offset - recsysEvent.arg) < 0.25) { - return undefined; - } - } - break; - case RecsysData.event.start: - if (lastEvent.event === RecsysData.event.scrub) { - // If the last event was a seek and this is a play, - // it's reasonable to just implicitly assume the play occurred, - // no need to create the play event. - return undefined; - } else if (lastEvent.event === RecsysData.event.start) { - // A start followed by a start is a buffering event. - // It may make sense to keep these. A user may abandon - // a page *not because it's bad content but because - // there are network troubles right now*. - } - break; - } - } - + // For now, don't do client-side preprocessing. I think there + // are browser inconsistencies and preprocessing loses too much info. this.recsysEvents.push(recsysEvent); } getRecsysEvents() { - return this.recsysEvents.map((event) => { - if (event !== RecsysData.event.stop) { - return event; - } - - // I used the arg in stop events to smuggle the seek time into - // the scrub events. But the backend doesn't expect it. - const dup = { ...event }; - delete dup.arg; - return dup; - }); + return this.recsysEvents; } sendRecsysEvents() { @@ -207,16 +137,17 @@ class RecsysPlugin extends Component { const recsysEvent = newRecsysEvent(RecsysData.event.start, this.player.currentTime()); this.log('onPlay', recsysEvent); this.addRecsysEvent(recsysEvent); + + this.inPause = false; + this.lastTimeUpdate = recsysEvent.offset; } onPause(event) { - // The API doesn't want an `arg` for `STOP` events. However, video.js - // emits these before the seek events, and that seems to be the easiest - // way to lift time you are seeking from into the scrub record (via lastTimeUpdate). - // Hacky, but works. - const recsysEvent = newRecsysEvent(RecsysData.event.stop, this.player.currentTime(), this.lastTimeUpdate); + const recsysEvent = newRecsysEvent(RecsysData.event.stop, this.player.currentTime()); this.log('onPause', recsysEvent); this.addRecsysEvent(recsysEvent); + + this.inPause = true; } onEnded(event) { @@ -226,26 +157,50 @@ class RecsysPlugin extends Component { } onRateChange(event) { - // This is actually a bug. The offset should be the offset. The change speed should be change speed. - // Otherise, you don't know where it changed and the time calc is wrong. const recsysEvent = newRecsysEvent(RecsysData.event.speed, this.player.currentTime(), this.player.playbackRate()); this.log('onRateChange', recsysEvent); this.addRecsysEvent(recsysEvent); } onTimeUpdate(event) { - this.lastTimeUpdate = this.currentTimeUpdate; - this.currentTimeUpdate = this.player.currentTime(); + const nextCurrentTime = this.player.currentTime(); + + if (!this.inPause && Math.abs(this.lastTimeUpdate - nextCurrentTime) < 0.5) { + // Don't update lastTimeUpdate if we are in a pause segment. + // + // However, if we aren't in a pause and the time jumped + // the onTimeUpdate event probably fired before the pause and seek. + // Don't update in that case, either. + this.lastTimeUpdate = this.currentTimeUpdate; + } + + this.currentTimeUpdate = nextCurrentTime; } onSeeked(event) { - // The problem? `lastTimeUpdate` is wrong. - // So every seeks l + const curTime = this.player.currentTime(); - // If the immediately prior event is a pause? - const recsysEvent = newRecsysEvent(RecsysData.event.scrub, this.lastTimeUpdate, this.player.currentTime()); - this.log('onSeeked', recsysEvent); - this.addRecsysEvent(recsysEvent); + // There are three patterns for seeking: + // + // Assuming the video is playing, + // + // 1. Dragging the player head emits: onPause -> onSeeked -> onSeeked -> ... -> onPlay + // 2. Key press left right emits: onSeeked -> onPlay + // 3. Clicking a position emits: onPause -> onSeeked -> onPlay + // + // If the video is NOT playing, + // + // 1. Dragging the player head emits: onSeeked + // 2. Key press left right emits: onSeeked + // 3. Clicking a position emits: onSeeked + const fromTime = this.lastTimeUpdate; + + if (fromTime !== curTime) { + // This removes duplicates that aren't useful. + const recsysEvent = newRecsysEvent(RecsysData.event.scrub, fromTime, curTime); + this.log('onSeeked', recsysEvent); + this.addRecsysEvent(recsysEvent); + } } onDispose(event) { From 3e4206ee695017ce4074092f91985416e31fec85 Mon Sep 17 00:00:00 2001 From: zeppi Date: Mon, 19 Jul 2021 17:32:44 -0400 Subject: [PATCH 62/80] yt welcome recon --- ui/modal/modalYoutubeWelcome/view.jsx | 32 ++++++++++++++++++--------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/ui/modal/modalYoutubeWelcome/view.jsx b/ui/modal/modalYoutubeWelcome/view.jsx index c8584952d..2548019db 100644 --- a/ui/modal/modalYoutubeWelcome/view.jsx +++ b/ui/modal/modalYoutubeWelcome/view.jsx @@ -1,4 +1,5 @@ // @flow +import { SIMPLE_SITE } from 'config'; import * as PAGES from 'constants/pages'; import React from 'react'; import { Modal } from 'modal/modal'; @@ -15,18 +16,27 @@ const YoutubeWelcome = (props: Props) => { -

- {__("You've escaped the land of spying, censorship, and exploitation.")} - 💩 -

-

- {__('Welcome to the land of content freedom.')} - 🌈 -

- + !SIMPLE_SITE ? ( + +

+ {__("You've escaped the land of spying, censorship, and exploitation.")} + 💩 +

+

+ {__('Welcome to the land of content freedom.')} + 🌈 +

+
+ ) : ( + +

+ {__('You make the party extra special!')} + 💖 +

+
+ ) } actions={
From 33ee8ed3b7c87dea200a11ee9daa717ac0f1dec1 Mon Sep 17 00:00:00 2001 From: zeppi Date: Mon, 19 Jul 2021 17:35:37 -0400 Subject: [PATCH 63/80] site help email transactoin failed --- ui/modal/modalTransactionFailed/view.jsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/modal/modalTransactionFailed/view.jsx b/ui/modal/modalTransactionFailed/view.jsx index b4f4e4dea..d2566ee79 100644 --- a/ui/modal/modalTransactionFailed/view.jsx +++ b/ui/modal/modalTransactionFailed/view.jsx @@ -1,6 +1,7 @@ // @flow import React from 'react'; import { Modal } from 'modal/modal'; +import { SITE_HELP_EMAIL } from 'config'; type Props = { closeModal: () => void, @@ -12,7 +13,11 @@ class ModalTransactionFailed extends React.PureComponent { return ( -

{__('Sorry about that. Contact help@lbry.com if you continue to have issues.')}

+

+ {__("Try refreshing to fix the issue. If that doesn't work, email %SITE_HELP_EMAIL% for support.", { + SITE_HELP_EMAIL, + })} +

); } From 1f902726fb4ca38373515c5f5c66dcf485a55be8 Mon Sep 17 00:00:00 2001 From: zeppi Date: Mon, 19 Jul 2021 17:39:59 -0400 Subject: [PATCH 64/80] copy --- ui/modal/modalTransactionFailed/view.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/modal/modalTransactionFailed/view.jsx b/ui/modal/modalTransactionFailed/view.jsx index d2566ee79..64c77d504 100644 --- a/ui/modal/modalTransactionFailed/view.jsx +++ b/ui/modal/modalTransactionFailed/view.jsx @@ -14,7 +14,7 @@ class ModalTransactionFailed extends React.PureComponent { return (

- {__("Try refreshing to fix the issue. If that doesn't work, email %SITE_HELP_EMAIL% for support.", { + {__('Sorry about that. Contact %SITE_HELP_EMAIL% if you continue to have issues.', { SITE_HELP_EMAIL, })}

From 3dc7c35cd7e3496bf39a8221e2cd47c2ac0fc953 Mon Sep 17 00:00:00 2001 From: zeppi Date: Mon, 19 Jul 2021 21:45:51 -0400 Subject: [PATCH 65/80] recon --- ui/component/livestreamLink/view.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/component/livestreamLink/view.jsx b/ui/component/livestreamLink/view.jsx index d92590546..a41510e39 100644 --- a/ui/component/livestreamLink/view.jsx +++ b/ui/component/livestreamLink/view.jsx @@ -17,7 +17,7 @@ export default function LivestreamLink(props: Props) { const { push } = useHistory(); const [livestreamClaim, setLivestreamClaim] = React.useState(false); const [isLivestreaming, setIsLivestreaming] = React.useState(false); - const livestreamChannelId = channelClaim.claim_id || ''; // TODO: fail in a safer way, probably + const livestreamChannelId = (channelClaim && channelClaim.claim_id) || ''; // TODO: fail in a safer way, probably React.useEffect(() => { if (livestreamChannelId) { @@ -29,7 +29,7 @@ export default function LivestreamLink(props: Props) { }) .then((res) => { if (res && res.items && res.items.length > 0) { - const claim = res.items[res.items.length - 1]; + const claim = res.items[0]; setLivestreamClaim(claim); } }) From 765cef75645668eb2615727a0853dd3b419678b9 Mon Sep 17 00:00:00 2001 From: zeppi Date: Mon, 19 Jul 2021 22:02:59 -0400 Subject: [PATCH 66/80] recon notify components --- ui/component/notificationBubble/view.jsx | 3 ++- ui/component/notificationHeaderButton/view.jsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ui/component/notificationBubble/view.jsx b/ui/component/notificationBubble/view.jsx index b8ac0edb6..9da6b1659 100644 --- a/ui/component/notificationBubble/view.jsx +++ b/ui/component/notificationBubble/view.jsx @@ -1,6 +1,7 @@ // @flow import React from 'react'; import classnames from 'classnames'; +import { ENABLE_UI_NOTIFICATIONS } from 'config'; type Props = { unseenCount: number, @@ -10,7 +11,7 @@ type Props = { export default function NotificationHeaderButton(props: Props) { const { unseenCount, inline = false, user } = props; - const notificationsEnabled = user && user.experimental_ui; + const notificationsEnabled = ENABLE_UI_NOTIFICATIONS || (user && user.experimental_ui); if (unseenCount === 0 || !notificationsEnabled) { return null; diff --git a/ui/component/notificationHeaderButton/view.jsx b/ui/component/notificationHeaderButton/view.jsx index 18dc409a0..74c581888 100644 --- a/ui/component/notificationHeaderButton/view.jsx +++ b/ui/component/notificationHeaderButton/view.jsx @@ -6,6 +6,7 @@ import Icon from 'component/common/icon'; import NotificationBubble from 'component/notificationBubble'; import Button from 'component/button'; import { useHistory } from 'react-router'; +import { ENABLE_UI_NOTIFICATIONS } from 'config'; type Props = { unseenCount: number, @@ -21,7 +22,7 @@ export default function NotificationHeaderButton(props: Props) { doSeeAllNotifications, user, } = props; - const notificationsEnabled = user && user.experimental_ui; + const notificationsEnabled = ENABLE_UI_NOTIFICATIONS || (user && user.experimental_ui); const { push } = useHistory(); function handleMenuClick() { From 4bf7c6857416b37c027d7176c1a341596a639c7c Mon Sep 17 00:00:00 2001 From: zeppi Date: Mon, 19 Jul 2021 22:38:55 -0400 Subject: [PATCH 67/80] use config for showTagsIntro --- .env.defaults | 1 + config.js | 1 + ui/component/userSignUp/view.jsx | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.env.defaults b/.env.defaults index b194fae90..4459153bc 100644 --- a/.env.defaults +++ b/.env.defaults @@ -90,3 +90,4 @@ ENABLE_UI_NOTIFICATIONS=false #USE_DISCOVER_WHITELIST=false #ENABLE_WILD_WEST=false #FULL_SIDE_LINKS=true +SHOW_TAGS_INTRO=true diff --git a/config.js b/config.js index 4c3ee2f9d..c0eca56f8 100644 --- a/config.js +++ b/config.js @@ -62,6 +62,7 @@ const config = { ENABLE_UI_NOTIFICATIONS: process.env.ENABLE_UI_NOTIFICATIONS === 'true', ENABLE_MATURE: process.env.ENABLE_MATURE === 'true', CUSTOM_HOMEPAGE: process.env.CUSTOM_HOMEPAGE === 'true', + SHOW_TAGS_INTRO: process.env.SHOW_TAGS_INTRO === 'true', }; config.URL_LOCAL = `http://localhost:${config.WEB_SERVER_PORT}`; diff --git a/ui/component/userSignUp/view.jsx b/ui/component/userSignUp/view.jsx index 11ddbcaeb..0fca417c4 100644 --- a/ui/component/userSignUp/view.jsx +++ b/ui/component/userSignUp/view.jsx @@ -19,6 +19,7 @@ import YoutubeTransferStatus from 'component/youtubeTransferStatus'; import useFetched from 'effects/use-fetched'; import Confetti from 'react-confetti'; import usePrevious from 'effects/use-previous'; +import { SHOW_TAGS_INTRO } from 'config'; const REDIRECT_PARAM = 'redirect'; const REDIRECT_IMMEDIATELY_PARAM = 'immediate'; @@ -118,7 +119,7 @@ function UserSignUp(props: Props) { interestedInYoutubeSync); const showYoutubeTransfer = hasVerifiedEmail && hasYoutubeChannels && !isYoutubeTransferComplete; const showFollowIntro = step === 'channels' || (hasVerifiedEmail && !followingAcknowledged); - const showTagsIntro = step === 'tags' || (hasVerifiedEmail && !tagsAcknowledged); + const showTagsIntro = SHOW_TAGS_INTRO && (step === 'tags' || (hasVerifiedEmail && !tagsAcknowledged)); const canHijackSignInFlowWithSpinner = hasVerifiedEmail && !showFollowIntro && !showTagsIntro && !rewardsAcknowledged; const isCurrentlyFetchingSomething = fetchingChannels || claimingReward || syncingWallet || creatingChannel; const isWaitingForSomethingToFinish = From c71e4718d0da5b62eb93156ec8e1c118c4bc8e8b Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Tue, 20 Jul 2021 11:14:56 +0800 Subject: [PATCH 68/80] Remove (revert) reaction-fetch hardstop Root-cause is known, so removing it to detect other issues. --- ui/component/commentsList/view.jsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ui/component/commentsList/view.jsx b/ui/component/commentsList/view.jsx index 450127a86..433103792 100644 --- a/ui/component/commentsList/view.jsx +++ b/ui/component/commentsList/view.jsx @@ -76,8 +76,6 @@ function CommentList(props: Props) { const [page, setPage] = React.useState(0); const totalFetchedComments = allCommentIds ? allCommentIds.length : 0; - const [reactionFetchCount, setReactionFetchCount] = React.useState(0); - // Display comments immediately if not fetching reactions // If not, wait to show comments until reactions are fetched const [readyToDisplayComments, setReadyToDisplayComments] = React.useState( @@ -138,9 +136,7 @@ function CommentList(props: Props) { }); } - if (idsForReactionFetch.length !== 0 && reactionFetchCount < 500) { - setReactionFetchCount(reactionFetchCount + 1); - + if (idsForReactionFetch.length !== 0) { fetchReacts(idsForReactionFetch) .then(() => { setReadyToDisplayComments(true); @@ -158,8 +154,6 @@ function CommentList(props: Props) { activeChannelId, fetchingChannels, isFetchingReacts, - reactionFetchCount, - setReactionFetchCount, ]); // Scroll to linked-comment From 08738ffcee0573df1eb6e21cad15064d1c6a114f Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Tue, 20 Jul 2021 14:38:29 +0800 Subject: [PATCH 69/80] Reaction-fetch: handle "deleted all channels" - use `selectActiveChannelClaim` as that takes the current channel list into account (i.e. correct state when all channels are deleted). - `selectActiveChannelId` should probably be removed or not exposed through a selector, as it is not updated when channel list changes? --- ui/component/comment/index.js | 7 ++++--- ui/component/commentReactions/index.js | 5 +++-- ui/component/commentsList/index.js | 5 +++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/ui/component/comment/index.js b/ui/component/comment/index.js index 9e4ed5825..26e604e64 100644 --- a/ui/component/comment/index.js +++ b/ui/component/comment/index.js @@ -11,12 +11,13 @@ import { doToast } from 'redux/actions/notifications'; import { doSetPlayingUri } from 'redux/actions/content'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectLinkedCommentAncestors, makeSelectOthersReactionsForComment } from 'redux/selectors/comments'; -import { selectActiveChannelId, selectActiveChannelClaim } from 'redux/selectors/app'; +import { selectActiveChannelClaim } from 'redux/selectors/app'; import { selectPlayingUri } from 'redux/selectors/content'; import Comment from './view'; const select = (state, props) => { - const activeChannelId = selectActiveChannelId(state); + const activeChannelClaim = selectActiveChannelClaim(state); + const activeChannelId = activeChannelClaim && activeChannelClaim.claim_id; const reactionKey = activeChannelId ? `${props.commentId}:${activeChannelId}` : props.commentId; return { @@ -25,7 +26,7 @@ const select = (state, props) => { channelIsBlocked: props.authorUri && makeSelectChannelIsMuted(props.authorUri)(state), commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true, othersReacts: makeSelectOthersReactionsForComment(reactionKey)(state), - activeChannelClaim: selectActiveChannelClaim(state), + activeChannelClaim, myChannels: selectMyChannelClaims(state), playingUri: selectPlayingUri(state), stakedLevel: makeSelectStakedLevelForChannelUri(props.authorUri)(state), diff --git a/ui/component/commentReactions/index.js b/ui/component/commentReactions/index.js index 585cb7a10..eb72e7362 100644 --- a/ui/component/commentReactions/index.js +++ b/ui/component/commentReactions/index.js @@ -4,10 +4,11 @@ import { makeSelectClaimIsMine, makeSelectClaimForUri } from 'lbry-redux'; import { doToast } from 'redux/actions/notifications'; import { makeSelectMyReactionsForComment, makeSelectOthersReactionsForComment } from 'redux/selectors/comments'; import { doCommentReact } from 'redux/actions/comments'; -import { selectActiveChannelId } from 'redux/selectors/app'; +import { selectActiveChannelClaim } from 'redux/selectors/app'; const select = (state, props) => { - const activeChannelId = selectActiveChannelId(state); + const activeChannelClaim = selectActiveChannelClaim(state); + const activeChannelId = activeChannelClaim && activeChannelClaim.claim_id; const reactionKey = activeChannelId ? `${props.commentId}:${activeChannelId}` : props.commentId; return { diff --git a/ui/component/commentsList/index.js b/ui/component/commentsList/index.js index 72a5b2916..dac16d16d 100644 --- a/ui/component/commentsList/index.js +++ b/ui/component/commentsList/index.js @@ -13,10 +13,11 @@ import { } from 'redux/selectors/comments'; import { doCommentReset, doCommentList, doCommentById, doCommentReactList } from 'redux/actions/comments'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; -import { selectActiveChannelId } from 'redux/selectors/app'; +import { selectActiveChannelClaim } from 'redux/selectors/app'; import CommentsList from './view'; const select = (state, props) => { + const activeChannelClaim = selectActiveChannelClaim(state); return { myChannels: selectMyChannelClaims(state), allCommentIds: makeSelectCommentIdsForUri(props.uri)(state), @@ -31,7 +32,7 @@ const select = (state, props) => { fetchingChannels: selectFetchingMyChannels(state), myReactsByCommentId: selectMyReactionsByCommentId(state), othersReactsById: selectOthersReactsById(state), - activeChannelId: selectActiveChannelId(state), + activeChannelId: activeChannelClaim && activeChannelClaim.claim_id, }; }; From e5f32b21c4f13b3c1801be6a74b059326ca7b884 Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Tue, 20 Jul 2021 14:55:26 +0800 Subject: [PATCH 70/80] Reaction-fetch: handle "no results" If there are no API errors but no reactions returned, consider the requested IDs as "done" and stop requesting again. When a channel is being confirmed, Commentron doesn't return the reaction object. Also added extra guard in case Commentron does return an object in the future, but an empty one. --- ui/redux/actions/comments.js | 5 +++-- ui/redux/reducers/comments.js | 23 ++++++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/ui/redux/actions/comments.js b/ui/redux/actions/comments.js index beeb0a246..b3349ec26 100644 --- a/ui/redux/actions/comments.js +++ b/ui/redux/actions/comments.js @@ -236,9 +236,10 @@ export function doCommentReactList(commentIds: Array) { dispatch({ type: ACTIONS.COMMENT_REACTION_LIST_COMPLETED, data: { - myReactions: myReactions || {}, + myReactions, othersReactions, channelId: activeChannelClaim ? activeChannelClaim.claim_id : undefined, + commentIds, }, }); }) @@ -379,7 +380,7 @@ export function doCommentCreate( livestream?: boolean = false, txid?: string, payment_intent_id?: string, - environment?: string, + environment?: string ) { return async (dispatch: Dispatch, getState: GetState) => { const state = getState(); diff --git a/ui/redux/reducers/comments.js b/ui/redux/reducers/comments.js index 5065fa9bd..6c09339f3 100644 --- a/ui/redux/reducers/comments.js +++ b/ui/redux/reducers/comments.js @@ -182,12 +182,15 @@ export default handleActions( }, [ACTIONS.COMMENT_REACTION_LIST_COMPLETED]: (state: CommentsState, action: any): CommentsState => { - const { myReactions, othersReactions, channelId } = action.data; + const { myReactions, othersReactions, channelId, commentIds } = action.data; const myReacts = Object.assign({}, state.myReactsByCommentId); const othersReacts = Object.assign({}, state.othersReactsByCommentId); - if (myReactions) { - Object.entries(myReactions).forEach(([commentId, reactions]) => { + const myReactionsEntries = myReactions ? Object.entries(myReactions) : []; + const othersReactionsEntries = othersReactions ? Object.entries(othersReactions) : []; + + if (myReactionsEntries.length > 0) { + myReactionsEntries.forEach(([commentId, reactions]) => { const key = channelId ? `${commentId}:${channelId}` : commentId; myReacts[key] = Object.entries(reactions).reduce((acc, [name, count]) => { if (count === 1) { @@ -196,13 +199,23 @@ export default handleActions( return acc; }, []); }); + } else { + commentIds.forEach((commentId) => { + const key = channelId ? `${commentId}:${channelId}` : commentId; + myReacts[key] = []; + }); } - if (othersReactions) { - Object.entries(othersReactions).forEach(([commentId, reactions]) => { + if (othersReactionsEntries.length > 0) { + othersReactionsEntries.forEach(([commentId, reactions]) => { const key = channelId ? `${commentId}:${channelId}` : commentId; othersReacts[key] = reactions; }); + } else { + commentIds.forEach((commentId) => { + const key = channelId ? `${commentId}:${channelId}` : commentId; + othersReacts[key] = {}; + }); } return { From 73cf52426fd3e1224331bebc9efad1cc2bb94003 Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Mon, 19 Jul 2021 22:27:25 +0800 Subject: [PATCH 71/80] Preload fonts properly with 'crossorigin' We probably don't need to preload fonts (it will reduce browser warnings), since it wasn't working all this while. But it's probably there to address something (perhaps to handle OG better?), so do it right by setting the proper flags. https://stackoverflow.com/questions/1330825/preloading-font-face-fonts/46830425#comment87712868_46830425 --- static/index-web.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/static/index-web.html b/static/index-web.html index 9776b34ff..f34303615 100644 --- a/static/index-web.html +++ b/static/index-web.html @@ -7,12 +7,12 @@ - - - - - - + + + + + +