Merge pull request #2076 from ecency/nt/mute-upgrade

Nt/mute upgrade
This commit is contained in:
Feruz M 2021-09-21 13:54:38 +03:00 committed by GitHub
commit c86ffe432b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 147 additions and 30 deletions

View File

@ -18,7 +18,7 @@ import { toggleAccountsBottomSheet } from '../../../redux/actions/uiAction';
//Constants
import AUTH_TYPE from '../../../constants/authType';
import { getDigitPinCode } from '../../../providers/hive/dhive';
import { getDigitPinCode, getMutes } from '../../../providers/hive/dhive';
import { setFeedPosts, setInitPosts } from '../../../redux/actions/postsAction';
import { Alert } from 'react-native';
import { useIntl } from 'react-intl';
@ -105,6 +105,7 @@ const AccountsBottomSheetContainer = ({ navigation }) => {
_currentAccount.unread_activity_count = await getUnreadNotificationCount(
decryptKey(encryptedAccessToken, getDigitPinCode(pinHash))
);
_currentAccount.mutes = await getMutes(_currentAccount.username);
dispatch(updateCurrentAccount(_currentAccount));
}

View File

@ -17,7 +17,7 @@ import { TextWithIcon } from '../../basicUIElements';
// Styles
import styles from './commentStyles';
import Animated from 'react-native-reanimated';
import { useAppSelector } from '../../../hooks';
const CommentView = ({
avatarSize,
@ -41,12 +41,16 @@ const CommentView = ({
hideManyCommentsButton,
openReplyThread,
}) => {
const intl = useIntl();
const actionSheet = useRef(null);
const isMuted = useAppSelector(state => state.account.currentAccount.mutes?.indexOf(comment.author) > -1);
const [_isShowSubComments, setIsShowSubComments] = useState(isShowSubComments || false);
const [isPressedShowButton, setIsPressedShowButton] = useState(false);
const [activeVotes, setActiveVotes] = useState([]);
const intl = useIntl();
const actionSheet = useRef(null);
useEffect(() => {
if (comment) {
@ -119,6 +123,7 @@ const CommentView = ({
body={comment.body}
created={comment.created}
key={`key-${comment.permlink}`}
isMuted={isMuted}
/>
<Fragment>

View File

@ -8,30 +8,51 @@ import styles from './quickProfileStyles';
interface ActionPanelProps {
isFollowing:boolean,
isFavourite:boolean,
isMuted:boolean,
onFollowPress:()=>void,
onFavouritePress:()=>void
}
export const ActionPanel = ({isFollowing, isFavourite, onFavouritePress, onFollowPress}: ActionPanelProps) => {
export const ActionPanel = ({
isFollowing,
isFavourite,
isMuted,
onFavouritePress,
onFollowPress
}: ActionPanelProps) => {
const heartColor = isFavourite
? '$primaryBlue'
: '$iconColor'
: '$iconColor';
const followIcon = isFollowing
? 'user-check'
: 'user-plus'
: 'user-plus';
return (
<View style={styles.actionPanel}>
<IconButton
iconType='FontAwesome5'
name={followIcon}
size={20}
color={EStyleSheet.value('$iconColor')}
disabled={isFollowing}
onPress={onFollowPress}
/>
{
isMuted ? (
<IconButton
iconType="MaterialCommunityIcons"
name="volume-variant-off"
size={26}
color={EStyleSheet.value('$iconColor')}
disabled={true}
/>
) : (
<IconButton
iconType='FontAwesome5'
name={followIcon}
size={20}
color={EStyleSheet.value('$iconColor')}
disabled={isFollowing}
onPress={onFollowPress}
/>
)
}
<IconButton
style={{marginLeft:8}}
iconType='AntDesign'

View File

@ -266,6 +266,7 @@ export const QuickProfileContent = ({
<ActionPanel
isFollowing={isFollowing}
isFavourite={isFavourite}
isMuted={isMuted}
onFavouritePress={_onFavouritePress}
onFollowPress={_onFollowPress}
/>

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useMemo } from 'react';
import { withNavigation } from 'react-navigation';
import { connect } from 'react-redux';
import get from 'lodash/get';
@ -35,6 +35,9 @@ const PostCardContainer = ({
const [_content, setContent] = useState(content);
const [reblogs, setReblogs] = useState([]);
const activeVotes = get(_content, 'active_votes', []);
const [isMuted, setIsMuted] = useState(
currentAccount.mutes && currentAccount.mutes.indexOf(content.author) > -1,
);
useEffect(() => {
let isCancelled = false;
@ -117,12 +120,17 @@ const PostCardContainer = ({
});
};
const _handleOnUnmutePress = () => {
setIsMuted(false);
};
return (
<PostCardView
handleOnUserPress={_handleOnUserPress}
handleOnContentPress={_handleOnContentPress}
handleOnVotersPress={_handleOnVotersPress}
handleOnReblogsPress={_handleOnReblogsPress}
handleOnUnmutePress={_handleOnUnmutePress}
content={_content}
isHideImage={isHideImage}
nsfw={nsfw || '1'}
@ -130,6 +138,7 @@ const PostCardContainer = ({
activeVotes={activeVotes}
imageHeight={imageHeight}
setImageHeight={setImageHeight}
isMuted={isMuted}
fetchPost={_fetchPost}
/>
);

View File

@ -91,4 +91,18 @@ export default EStyleSheet.create({
color: '$primaryDarkGray',
marginLeft: 2,
},
revealButton: {
backgroundColor: '$primaryGrayBackground',
height: 56,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 12,
marginTop: 8,
marginHorizontal: 0,
},
revealText: {
color: '$primaryDarkText',
textAlign: 'center',
fontSize: 18,
},
});

View File

@ -18,6 +18,7 @@ import { TextWithIcon } from '../../basicUIElements';
import { Upvote } from '../../upvote';
// Styles
import styles from './postCardStyles';
import { TextButton } from '../..';
const dim = Dimensions.get('window');
const DEFAULT_IMAGE =
@ -30,6 +31,7 @@ const PostCardView = ({
handleOnContentPress,
handleOnVotersPress,
handleOnReblogsPress,
handleOnUnmutePress,
content,
reblogs,
isHideImage,
@ -39,6 +41,7 @@ const PostCardView = ({
activeVotes,
imageHeight,
setImageHeight,
isMuted,
}) => {
//local state to manage fake upvote if available
const [activeVotesCount, setActiveVotesCount] = useState(0);
@ -78,7 +81,7 @@ const PostCardView = ({
var images = { image: DEFAULT_IMAGE, thumbnail: DEFAULT_IMAGE };
if (content.thumbnail) {
if (nsfw !== '0' && content.nsfw) {
if (isMuted || (nsfw !== '0' && content.nsfw)) {
images = { image: NSFW_IMAGE, thumbnail: NSFW_IMAGE };
} else {
images = { image: content.image, thumbnail: content.thumbnail };
@ -149,10 +152,19 @@ const PostCardView = ({
}}
/>
)}
<View style={[styles.postDescripton]}>
<Text style={styles.title}>{content.title}</Text>
<Text style={styles.summary}>{content.summary}</Text>
</View>
{!isMuted ? (
<View style={[styles.postDescripton]}>
<Text style={styles.title}>{content.title}</Text>
<Text style={styles.summary}>{content.summary}</Text>
</View>
) : (
<TextButton
style={styles.revealButton}
textStyle={styles.revealText}
onPress={() => handleOnUnmutePress()}
text={intl.formatMessage({ id: 'post.reveal_muted' })}
/>
)}
</TouchableOpacity>
</View>
<View style={styles.bodyFooter}>

View File

@ -3,13 +3,13 @@ import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
revealButton: {
backgroundColor: '$iconColor',
height: 22,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 20,
minWidth: 40,
maxWidth: 170,
marginVertical: 8,
marginVertical: 12,
paddingVertical:6,
},
revealText: {
color: '$white',

View File

@ -38,6 +38,7 @@ const CommentBody = ({
commentDepth,
reputation,
dispatch,
isMuted
}) => {
const _contentWidth = WIDTH - (40 + 28 + (commentDepth > 2 ? 44 : 0))
@ -46,7 +47,7 @@ const CommentBody = ({
const [postImages, setPostImages] = useState<string[]>([]);
const [selectedImage, setSelectedImage] = useState(null);
const [selectedLink, setSelectedLink] = useState(null);
const [revealComment, setRevealComment] = useState(reputation > 0);
const [revealComment, setRevealComment] = useState(reputation > 0 && !isMuted);
const [videoUrl, setVideoUrl] = useState(null);
const [youtubeVideoId, setYoutubeVideoId] = useState(null)

View File

@ -12,6 +12,7 @@ import get from 'lodash/get';
// Constants
import FastImage from 'react-native-fast-image';
import EStyleSheet from 'react-native-extended-stylesheet';
import LIGHT_COVER_IMAGE from '../../../assets/default_cover_image.png';
import DARK_COVER_IMAGE from '../../../assets/dark_cover_image.png';
@ -28,6 +29,7 @@ import { getResizedImage } from '../../../utils/image';
// Styles
import styles from './profileSummaryStyles';
import { TextButton } from '../../buttons';
import { Icon } from '../..';
const DEVICE_WIDTH = Dimensions.get('window').width;

View File

@ -441,7 +441,8 @@
"image_saved": "Image saved to Photo Gallery",
"image_saved_error": "Error Saving Image",
"wrong_link": "Wrong link",
"in": "in"
"in": "in",
"reveal_muted":"MUTED\nTap to reveal content"
},
"drafts": {
"title": "Drafts",

View File

@ -2,7 +2,7 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { withNavigation } from 'react-navigation';
import { get, has, unionBy } from 'lodash';
import { get, has, unionBy, update } from 'lodash';
import { Alert } from 'react-native';
import { injectIntl } from 'react-intl';
import Matomo from 'react-native-matomo-sdk';
@ -28,6 +28,7 @@ import { toastNotification, setRcOffer } from '../redux/actions/uiAction';
// Constants
import { default as ROUTES } from '../constants/routeNames';
import { updateCurrentAccount } from '../redux/actions/accountAction';
class ProfileContainer extends Component {
constructor(props) {
@ -177,6 +178,17 @@ class ProfileContainer extends Component {
following,
})
.then(() => {
//means user is now being followed
if (!isFollowing) {
const mutes = currentAccount.mutes || [];
const mutedIndex = mutes.indexOf(username);
if (mutedIndex >= 0) {
mutes.splice(mutedIndex, 1);
currentAccount.mutes = mutes;
dispatch(updateCurrentAccount(currentAccount));
}
}
dispatch(
toastNotification(
intl.formatMessage({
@ -214,6 +226,18 @@ class ProfileContainer extends Component {
following,
})
.then(() => {
this.setState({
isMuted: true,
isProfileLoading: false,
});
const curMutes = currentAccount.mutes || [];
if (curMutes.indexOf(username) < 0) {
//check to avoid double entry corner case
currentAccount.mutes = [username, ...curMutes];
}
dispatch(updateCurrentAccount(currentAccount));
dispatch(
toastNotification(
intl.formatMessage({
@ -221,7 +245,6 @@ class ProfileContainer extends Component {
}),
),
);
this._profileActionDone();
})
.catch((err) => {
this._profileActionDone(err);

View File

@ -4,7 +4,7 @@ import Config from 'react-native-config';
import get from 'lodash/get';
import { Alert } from 'react-native';
import { getDigitPinCode, getUser } from './dhive';
import { getDigitPinCode, getMutes, getUser } from './dhive';
import {
setUserData,
setAuthStatus,
@ -70,6 +70,7 @@ export const login = async (username, password, isPinCodeOpen) => {
account.unread_activity_count = await getUnreadNotificationCount(
scTokens ? scTokens.access_token : '',
);
account.mutes = await getMutes(account.username);
let jsonMetadata;
try {
@ -135,6 +136,7 @@ export const loginWithSC2 = async (code, isPinCodeOpen) => {
account.unread_activity_count = await getUnreadNotificationCount(
scTokens ? scTokens.access_token : '',
);
account.mutes = await getMutes(account.username);
let jsonMetadata;
try {

View File

@ -36,6 +36,7 @@ import AUTH_TYPE from '../../constants/authType';
import { SERVER_LIST } from '../../constants/options/api';
import { b64uEnc } from '../../utils/b64';
import bugsnagInstance from '../../config/bugsnag';
import bugsnapInstance from '../../config/bugsnag';
global.Buffer = global.Buffer || require('buffer').Buffer;
@ -410,6 +411,27 @@ export const getFollowing = (follower, startFollowing, followType = 'blog', limi
export const getFollowers = (follower, startFollowing, followType = 'blog', limit = 100) =>
client.database.call('get_followers', [follower, startFollowing, followType, limit]);
export const getMutes = async (currentUsername) => {
try {
const type = 'ignore';
const limit = 1000;
const response = await client.database.call('get_following', [
currentUsername,
'',
type,
limit,
]);
if (!response) {
return [];
}
return response.map((item) => item.following);
} catch (err) {
console.warn('Failed to get muted accounts', err);
bugsnapInstance.notify(err);
return [];
}
};
export const getRelationship = (follower, following) =>
new Promise((resolve, reject) => {
if (follower) {

View File

@ -40,7 +40,7 @@ import {
getLastUpdateCheck,
setLastUpdateCheck,
} from '../../../realm/realm';
import { getUser, getPost, getDigitPinCode } from '../../../providers/hive/dhive';
import { getUser, getPost, getDigitPinCode, getMutes } from '../../../providers/hive/dhive';
import {
migrateToMasterKeyWithAccessToken,
refreshSCToken,
@ -747,6 +747,7 @@ class ApplicationContainer extends Component {
}
accountData.unread_activity_count = await getUnreadNotificationCount();
accountData.mutes = await getMutes(realmObject.username);
dispatch(updateCurrentAccount(accountData));
this._connectNotificationServer(accountData.name);
@ -928,6 +929,7 @@ class ApplicationContainer extends Component {
_currentAccount = await this._refreshAccessToken(_currentAccount);
_currentAccount.unread_activity_count = await getUnreadNotificationCount();
_currentAccount.mutes = await getMutes(_currentAccount.username);
dispatch(updateCurrentAccount(_currentAccount));
};

View File

@ -35,7 +35,7 @@ import {
setPinCodeOpen,
} from '../../../realm/realm';
import { updateCurrentAccount, removeOtherAccount } from '../../../redux/actions/accountAction';
import { getDigitPinCode, getUser } from '../../../providers/hive/dhive';
import { getDigitPinCode, getMutes, getUser } from '../../../providers/hive/dhive';
// Utils
import { encryptKey, decryptKey } from '../../../utils/crypto';
@ -318,6 +318,7 @@ class PinCodeContainer extends Component {
//get unread notifications
_currentAccount.unread_activity_count = await getUnreadNotificationCount();
_currentAccount.mutes = await getMutes(_currentAccount.username);
dispatch(updateCurrentAccount({ ..._currentAccount }));
dispatch(closePinCodeModal());
}