Implement account muting
parent
3972706c54
commit
8cd2b4a721
|
@ -13,7 +13,7 @@
|
||||||
"postinstall": "patch-package"
|
"postinstall": "patch-package"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atproto/api": "^0.0.3",
|
"@atproto/api": "^0.0.4",
|
||||||
"@bam.tech/react-native-image-resizer": "^3.0.4",
|
"@bam.tech/react-native-image-resizer": "^3.0.4",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.1.1",
|
"@fortawesome/free-regular-svg-icons": "^6.1.1",
|
||||||
|
|
|
@ -72,7 +72,6 @@ export async function resize(localUri: string, opts: ResizeOpts) {
|
||||||
undefined,
|
undefined,
|
||||||
{mode: opts.mode},
|
{mode: opts.mode},
|
||||||
)
|
)
|
||||||
console.log(quality, resizeRes)
|
|
||||||
if (resizeRes.size < opts.maxSize) {
|
if (resizeRes.size < opts.maxSize) {
|
||||||
return resizeRes
|
return resizeRes
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ export async function getLinkMeta(
|
||||||
meta.image = httpResMeta.image
|
meta.image = httpResMeta.image
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// failed
|
// failed
|
||||||
console.log(e)
|
console.error(e)
|
||||||
meta.error = 'Failed to fetch link'
|
meta.error = 'Failed to fetch link'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -256,7 +256,7 @@ export function convertBskyAppUrlIfNeeded(url: string): string {
|
||||||
const urlp = new URL(url)
|
const urlp = new URL(url)
|
||||||
return urlp.pathname
|
return urlp.pathname
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('Unexpected error in convertBskyAppUrlIfNeeded()', e)
|
console.error('Unexpected error in convertBskyAppUrlIfNeeded()', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return url
|
return url
|
||||||
|
|
|
@ -593,6 +593,5 @@ function ts(item: FeedViewPost | FeedItemModel): string {
|
||||||
// @ts-ignore need better type checks
|
// @ts-ignore need better type checks
|
||||||
return item.reason.indexedAt
|
return item.reason.indexedAt
|
||||||
}
|
}
|
||||||
console.log(item)
|
|
||||||
return item.post.indexedAt
|
return item.post.indexedAt
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ export const ACTOR_TYPE_SCENE = 'app.bsky.system.actorScene'
|
||||||
export class ProfileViewMyStateModel {
|
export class ProfileViewMyStateModel {
|
||||||
follow?: string
|
follow?: string
|
||||||
member?: string
|
member?: string
|
||||||
|
muted?: boolean
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeAutoObservable(this)
|
makeAutoObservable(this)
|
||||||
|
@ -156,6 +157,18 @@ export class ProfileViewModel {
|
||||||
await this.refresh()
|
await this.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async muteAccount() {
|
||||||
|
await this.rootStore.api.app.bsky.graph.mute({user: this.did})
|
||||||
|
this.myState.muted = true
|
||||||
|
await this.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
async unmuteAccount() {
|
||||||
|
await this.rootStore.api.app.bsky.graph.unmute({user: this.did})
|
||||||
|
this.myState.muted = false
|
||||||
|
await this.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
// state transitions
|
// state transitions
|
||||||
// =
|
// =
|
||||||
|
|
||||||
|
|
|
@ -282,7 +282,12 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
onCopyPostText={onCopyPostText}
|
onCopyPostText={onCopyPostText}
|
||||||
onDeletePost={onDeletePost}
|
onDeletePost={onDeletePost}
|
||||||
/>
|
/>
|
||||||
{record.text ? (
|
{item.post.author.viewer?.muted ? (
|
||||||
|
<View style={[styles.mutedWarning, pal.btn]}>
|
||||||
|
<FontAwesomeIcon icon={['far', 'eye-slash']} style={s.mr2} />
|
||||||
|
<Text type="body2">This post is by a muted account.</Text>
|
||||||
|
</View>
|
||||||
|
) : record.text ? (
|
||||||
<View style={styles.postTextContainer}>
|
<View style={styles.postTextContainer}>
|
||||||
<RichText
|
<RichText
|
||||||
text={record.text}
|
text={record.text}
|
||||||
|
@ -367,6 +372,14 @@ const styles = StyleSheet.create({
|
||||||
paddingRight: 5,
|
paddingRight: 5,
|
||||||
maxWidth: 240,
|
maxWidth: 240,
|
||||||
},
|
},
|
||||||
|
mutedWarning: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: 10,
|
||||||
|
marginTop: 2,
|
||||||
|
marginBottom: 6,
|
||||||
|
borderRadius: 2,
|
||||||
|
},
|
||||||
postTextContainer: {
|
postTextContainer: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|
|
@ -184,7 +184,12 @@ export const Post = observer(function Post({
|
||||||
</Link>
|
</Link>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{record.text ? (
|
{item.post.author.viewer?.muted ? (
|
||||||
|
<View style={[styles.mutedWarning, pal.btn]}>
|
||||||
|
<FontAwesomeIcon icon={['far', 'eye-slash']} style={s.mr2} />
|
||||||
|
<Text type="body2">This post is by a muted account.</Text>
|
||||||
|
</View>
|
||||||
|
) : record.text ? (
|
||||||
<View style={styles.postTextContainer}>
|
<View style={styles.postTextContainer}>
|
||||||
<RichText text={record.text} entities={record.entities} />
|
<RichText text={record.text} entities={record.entities} />
|
||||||
</View>
|
</View>
|
||||||
|
@ -222,6 +227,14 @@ const styles = StyleSheet.create({
|
||||||
layoutContent: {
|
layoutContent: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
|
mutedWarning: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: 10,
|
||||||
|
marginTop: 2,
|
||||||
|
marginBottom: 6,
|
||||||
|
borderRadius: 2,
|
||||||
|
},
|
||||||
postTextContainer: {
|
postTextContainer: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|
|
@ -106,6 +106,7 @@ export const FeedItem = observer(function ({
|
||||||
isNoTop ? styles.outerNoTop : undefined,
|
isNoTop ? styles.outerNoTop : undefined,
|
||||||
item._isThreadParent ? styles.outerNoBottom : undefined,
|
item._isThreadParent ? styles.outerNoBottom : undefined,
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isChild && !item._isThreadChild && item.replyParent ? (
|
{isChild && !item._isThreadChild && item.replyParent ? (
|
||||||
|
@ -200,7 +201,12 @@ export const FeedItem = observer(function ({
|
||||||
</Link>
|
</Link>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{record.text ? (
|
{item.post.author.viewer?.muted ? (
|
||||||
|
<View style={[styles.mutedWarning, pal.btn]}>
|
||||||
|
<FontAwesomeIcon icon={['far', 'eye-slash']} style={s.mr2} />
|
||||||
|
<Text type="body2">This post is by a muted account.</Text>
|
||||||
|
</View>
|
||||||
|
) : record.text ? (
|
||||||
<View style={styles.postTextContainer}>
|
<View style={styles.postTextContainer}>
|
||||||
<RichText
|
<RichText
|
||||||
type="body1"
|
type="body1"
|
||||||
|
@ -303,6 +309,14 @@ const styles = StyleSheet.create({
|
||||||
layoutContent: {
|
layoutContent: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
|
mutedWarning: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: 10,
|
||||||
|
marginTop: 2,
|
||||||
|
marginBottom: 6,
|
||||||
|
borderRadius: 2,
|
||||||
|
},
|
||||||
postTextContainer: {
|
postTextContainer: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|
|
@ -89,6 +89,24 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||||
}
|
}
|
||||||
onRefreshAll()
|
onRefreshAll()
|
||||||
}
|
}
|
||||||
|
const onPressMuteAccount = async () => {
|
||||||
|
try {
|
||||||
|
await view.muteAccount()
|
||||||
|
Toast.show('Account muted')
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error(e)
|
||||||
|
Toast.show(`There was an issue! ${e.toString()}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onPressUnmuteAccount = async () => {
|
||||||
|
try {
|
||||||
|
await view.unmuteAccount()
|
||||||
|
Toast.show('Account unmuted')
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error(e)
|
||||||
|
Toast.show(`There was an issue! ${e.toString()}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
const onPressReportAccount = () => {
|
const onPressReportAccount = () => {
|
||||||
store.shell.openModal(new ReportAccountModal(view.did))
|
store.shell.openModal(new ReportAccountModal(view.did))
|
||||||
}
|
}
|
||||||
|
@ -143,6 +161,10 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||||
let dropdownItems: DropdownItem[] | undefined
|
let dropdownItems: DropdownItem[] | undefined
|
||||||
if (!isMe) {
|
if (!isMe) {
|
||||||
dropdownItems = dropdownItems || []
|
dropdownItems = dropdownItems || []
|
||||||
|
dropdownItems.push({
|
||||||
|
label: view.myState.muted ? 'Unmute Account' : 'Mute Account',
|
||||||
|
onPress: view.myState.muted ? onPressUnmuteAccount : onPressMuteAccount,
|
||||||
|
})
|
||||||
dropdownItems.push({
|
dropdownItems.push({
|
||||||
label: 'Report Account',
|
label: 'Report Account',
|
||||||
onPress: onPressReportAccount,
|
onPress: onPressReportAccount,
|
||||||
|
@ -286,7 +308,7 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{view.isScene && view.creator ? (
|
{view.isScene && view.creator ? (
|
||||||
<View style={styles.relationshipsLine}>
|
<View style={styles.detailLine}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={['far', 'user']}
|
icon={['far', 'user']}
|
||||||
style={[pal.textLight, s.mr5]}
|
style={[pal.textLight, s.mr5]}
|
||||||
|
@ -304,7 +326,7 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||||
</View>
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{view.isScene && view.myState.member ? (
|
{view.isScene && view.myState.member ? (
|
||||||
<View style={styles.relationshipsLine}>
|
<View style={styles.detailLine}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={['far', 'circle-check']}
|
icon={['far', 'circle-check']}
|
||||||
style={[pal.textLight, s.mr5]}
|
style={[pal.textLight, s.mr5]}
|
||||||
|
@ -314,6 +336,17 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
{view.myState.muted ? (
|
||||||
|
<View style={[styles.detailLine, pal.btn, s.p5]}>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={['far', 'eye-slash']}
|
||||||
|
style={[pal.text, s.mr5]}
|
||||||
|
/>
|
||||||
|
<Text type="body2" style={[s.mr2, pal.text]}>
|
||||||
|
Account muted.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
) : undefined}
|
||||||
</View>
|
</View>
|
||||||
{view.isScene && view.creator === store.me.did ? (
|
{view.isScene && view.creator === store.me.did ? (
|
||||||
<View style={[styles.sceneAdminContainer, pal.border]}>
|
<View style={[styles.sceneAdminContainer, pal.border]}>
|
||||||
|
@ -421,7 +454,7 @@ const styles = StyleSheet.create({
|
||||||
marginBottom: 8,
|
marginBottom: 8,
|
||||||
},
|
},
|
||||||
|
|
||||||
relationshipsLine: {
|
detailLine: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
marginBottom: 5,
|
marginBottom: 5,
|
||||||
|
|
|
@ -30,6 +30,7 @@ import {faCompass} from '@fortawesome/free-regular-svg-icons/faCompass'
|
||||||
import {faEllipsis} from '@fortawesome/free-solid-svg-icons/faEllipsis'
|
import {faEllipsis} from '@fortawesome/free-solid-svg-icons/faEllipsis'
|
||||||
import {faEnvelope} from '@fortawesome/free-solid-svg-icons/faEnvelope'
|
import {faEnvelope} from '@fortawesome/free-solid-svg-icons/faEnvelope'
|
||||||
import {faExclamation} from '@fortawesome/free-solid-svg-icons/faExclamation'
|
import {faExclamation} from '@fortawesome/free-solid-svg-icons/faExclamation'
|
||||||
|
import {faEyeSlash as farEyeSlash} from '@fortawesome/free-regular-svg-icons/faEyeSlash'
|
||||||
import {faGear} from '@fortawesome/free-solid-svg-icons/faGear'
|
import {faGear} from '@fortawesome/free-solid-svg-icons/faGear'
|
||||||
import {faGlobe} from '@fortawesome/free-solid-svg-icons/faGlobe'
|
import {faGlobe} from '@fortawesome/free-solid-svg-icons/faGlobe'
|
||||||
import {faHeart} from '@fortawesome/free-regular-svg-icons/faHeart'
|
import {faHeart} from '@fortawesome/free-regular-svg-icons/faHeart'
|
||||||
|
@ -96,6 +97,7 @@ export function setup() {
|
||||||
faEllipsis,
|
faEllipsis,
|
||||||
faEnvelope,
|
faEnvelope,
|
||||||
faExclamation,
|
faExclamation,
|
||||||
|
farEyeSlash,
|
||||||
faGear,
|
faGear,
|
||||||
faGlobe,
|
faGlobe,
|
||||||
faHeart,
|
faHeart,
|
||||||
|
|
|
@ -19,10 +19,10 @@
|
||||||
jsonpointer "^5.0.0"
|
jsonpointer "^5.0.0"
|
||||||
leven "^3.1.0"
|
leven "^3.1.0"
|
||||||
|
|
||||||
"@atproto/api@^0.0.2":
|
"@atproto/api@^0.0.4":
|
||||||
version "0.0.2"
|
version "0.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.0.2.tgz#b6c4f5b670a04e5e79889da792518c8fb84c95bf"
|
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.0.4.tgz#f2cb17f234ea1360ebe719be244cabc28724d992"
|
||||||
integrity sha512-0ryu3M8kXCmVnRO9eb/PJ8dtwahP28tlMt0SetFQVcjUHZXkZwJGnscJOAznVP7OU1TlyUkjeDXRkUYx9hi4Lg==
|
integrity sha512-lSaww8M2R7pRi1p1CUoidiYRNgIcUrEbhk4SZ7dGYhp9M2BKXYr9PzwWDZmB/tmFLdRPzAslmg9QWKbc0mqeUQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@atproto/xrpc" "*"
|
"@atproto/xrpc" "*"
|
||||||
typed-emitter "^2.1.0"
|
typed-emitter "^2.1.0"
|
||||||
|
|
Loading…
Reference in New Issue