diff options
author | Paul Frazee <pfrazee@gmail.com> | 2023-08-30 15:19:19 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-30 15:19:19 -0700 |
commit | a29f10aefe6fa67848ca281a0a7dffc43e292ec6 (patch) | |
tree | 7f1a534953eb515fd4a7f358885c4c1c5e2de42c /src | |
parent | 3a90b479fd42883a624b3c3e5d7ba36b510ca6fa (diff) | |
download | voidsky-a29f10aefe6fa67848ca281a0a7dffc43e292ec6.tar.zst |
Moderation settings fixes (#1336)
* Default isAdultContentEnabled to false on all devices. The original intent of setting the default based on the device was to make the maximally-permissive choice. It turns out this was a mistake as it created sync issues between devices; users would be confused by the lack of congruity between them. We have to go with false by default to ensure sync is retained. * Update preferences model to use new sdk api * Delete dead code * Dont show the iOS adult content warning in content filtering settings if adult content is enabled * Bump @atproto/api@0.6.8 * Codebase style consistency
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/labeling/helpers.ts | 436 | ||||
-rw-r--r-- | src/lib/labeling/types.ts | 53 | ||||
-rw-r--r-- | src/state/models/ui/preferences.ts | 234 | ||||
-rw-r--r-- | src/view/com/modals/ContentFilteringSettings.tsx | 22 |
4 files changed, 67 insertions, 678 deletions
diff --git a/src/lib/labeling/helpers.ts b/src/lib/labeling/helpers.ts deleted file mode 100644 index 447b0a99a..000000000 --- a/src/lib/labeling/helpers.ts +++ /dev/null @@ -1,436 +0,0 @@ -import { - AppBskyActorDefs, - AppBskyGraphDefs, - AppBskyEmbedRecordWithMedia, - AppBskyEmbedRecord, - AppBskyEmbedImages, - AppBskyEmbedExternal, -} from '@atproto/api' -import { - CONFIGURABLE_LABEL_GROUPS, - ILLEGAL_LABEL_GROUP, - ALWAYS_FILTER_LABEL_GROUP, - ALWAYS_WARN_LABEL_GROUP, - UNKNOWN_LABEL_GROUP, -} from './const' -import { - Label, - LabelValGroup, - ModerationBehaviorCode, - ModerationBehavior, - PostModeration, - ProfileModeration, - PostLabelInfo, - ProfileLabelInfo, -} from './types' -import {RootStoreModel} from 'state/index' - -type Embed = - | AppBskyEmbedRecord.View - | AppBskyEmbedImages.View - | AppBskyEmbedExternal.View - | AppBskyEmbedRecordWithMedia.View - | {$type: string; [k: string]: unknown} - -export function getLabelValueGroup(labelVal: string): LabelValGroup { - let id: keyof typeof CONFIGURABLE_LABEL_GROUPS - for (id in CONFIGURABLE_LABEL_GROUPS) { - if (ILLEGAL_LABEL_GROUP.values.includes(labelVal)) { - return ILLEGAL_LABEL_GROUP - } - if (ALWAYS_FILTER_LABEL_GROUP.values.includes(labelVal)) { - return ALWAYS_FILTER_LABEL_GROUP - } - if (ALWAYS_WARN_LABEL_GROUP.values.includes(labelVal)) { - return ALWAYS_WARN_LABEL_GROUP - } - if (CONFIGURABLE_LABEL_GROUPS[id].values.includes(labelVal)) { - return CONFIGURABLE_LABEL_GROUPS[id] - } - } - return UNKNOWN_LABEL_GROUP -} - -export function getPostModeration( - store: RootStoreModel, - postInfo: PostLabelInfo, -): PostModeration { - const accountPref = store.preferences.getLabelPreference( - postInfo.accountLabels, - ) - const profilePref = store.preferences.getLabelPreference( - postInfo.profileLabels, - ) - const postPref = store.preferences.getLabelPreference(postInfo.postLabels) - - // avatar - let avatar = { - warn: accountPref.pref === 'hide' || accountPref.pref === 'warn', - blur: - postInfo.isBlocking || - accountPref.pref === 'hide' || - accountPref.pref === 'warn' || - profilePref.pref === 'hide' || - profilePref.pref === 'warn', - } - - // hide no-override cases - if (accountPref.pref === 'hide' && accountPref.desc.id === 'illegal') { - return hidePostNoOverride(accountPref.desc.warning) - } - if (profilePref.pref === 'hide' && profilePref.desc.id === 'illegal') { - return hidePostNoOverride(profilePref.desc.warning) - } - if (postPref.pref === 'hide' && postPref.desc.id === 'illegal') { - return hidePostNoOverride(postPref.desc.warning) - } - - // hide cases - if (postInfo.isBlocking) { - return { - avatar, - list: hide('Post from an account you blocked.'), - thread: hide('Post from an account you blocked.'), - view: warn('Post from an account you blocked.'), - } - } - if (postInfo.isBlockedBy) { - return { - avatar, - list: hide('Post from an account that has blocked you.'), - thread: hide('Post from an account that has blocked you.'), - view: warn('Post from an account that has blocked you.'), - } - } - if (accountPref.pref === 'hide') { - return { - avatar, - list: hide(accountPref.desc.warning), - thread: hide(accountPref.desc.warning), - view: warn(accountPref.desc.warning), - } - } - if (profilePref.pref === 'hide') { - return { - avatar, - list: hide(profilePref.desc.warning), - thread: hide(profilePref.desc.warning), - view: warn(profilePref.desc.warning), - } - } - if (postPref.pref === 'hide') { - return { - avatar, - list: hide(postPref.desc.warning), - thread: hide(postPref.desc.warning), - view: warn(postPref.desc.warning), - } - } - - // muting - if (postInfo.isMuted) { - let msg = 'Post from an account you muted.' - if (postInfo.mutedByList) { - msg = `Muted by ${postInfo.mutedByList.name}` - } - return { - avatar, - list: isMute(hide(msg)), - thread: isMute(warn(msg)), - view: isMute(warn(msg)), - } - } - - // warning cases - if (postPref.pref === 'warn') { - if (postPref.desc.isAdultImagery) { - return { - avatar, - list: warnImages(postPref.desc.warning), - thread: warnImages(postPref.desc.warning), - view: warnImages(postPref.desc.warning), - } - } - return { - avatar, - list: warnContent(postPref.desc.warning), - thread: warnContent(postPref.desc.warning), - view: warnContent(postPref.desc.warning), - } - } - if (accountPref.pref === 'warn') { - return { - avatar, - list: warnContent(accountPref.desc.warning), - thread: warnContent(accountPref.desc.warning), - view: warnContent(accountPref.desc.warning), - } - } - - return { - avatar, - list: show(), - thread: show(), - view: show(), - } -} - -export function mergePostModerations( - moderations: PostModeration[], -): PostModeration { - const merged: PostModeration = { - avatar: {warn: false, blur: false}, - list: show(), - thread: show(), - view: show(), - } - for (const mod of moderations) { - if (mod.list.behavior === ModerationBehaviorCode.Hide) { - merged.list = mod.list - } - if (mod.thread.behavior === ModerationBehaviorCode.Hide) { - merged.thread = mod.thread - } - if (mod.view.behavior === ModerationBehaviorCode.Hide) { - merged.view = mod.view - } - } - return merged -} - -export function getProfileModeration( - store: RootStoreModel, - profileInfo: ProfileLabelInfo, -): ProfileModeration { - const accountPref = store.preferences.getLabelPreference( - profileInfo.accountLabels, - ) - const profilePref = store.preferences.getLabelPreference( - profileInfo.profileLabels, - ) - - // avatar - let avatar = { - warn: accountPref.pref === 'hide' || accountPref.pref === 'warn', - blur: - profileInfo.isBlocking || - accountPref.pref === 'hide' || - accountPref.pref === 'warn' || - profilePref.pref === 'hide' || - profilePref.pref === 'warn', - } - - // hide no-override cases - if (accountPref.pref === 'hide' && accountPref.desc.id === 'illegal') { - return hideProfileNoOverride(accountPref.desc.warning) - } - if (profilePref.pref === 'hide' && profilePref.desc.id === 'illegal') { - return hideProfileNoOverride(profilePref.desc.warning) - } - - // hide cases - if (accountPref.pref === 'hide') { - return { - avatar, - list: hide(accountPref.desc.warning), - view: hide(accountPref.desc.warning), - } - } - if (profilePref.pref === 'hide') { - return { - avatar, - list: hide(profilePref.desc.warning), - view: hide(profilePref.desc.warning), - } - } - - // warn cases - if (accountPref.pref === 'warn') { - return { - avatar, - list: - profileInfo.isBlocking || profileInfo.isBlockedBy - ? hide('Blocked account') - : warn(accountPref.desc.warning), - view: warn(accountPref.desc.warning), - } - } - // we don't warn for this - // if (profilePref.pref === 'warn') { - // return { - // avatar, - // list: warn(profilePref.desc.warning), - // view: warn(profilePref.desc.warning), - // } - // } - - return { - avatar, - list: profileInfo.isBlocking ? hide('Blocked account') : show(), - view: show(), - } -} - -export function getProfileViewBasicLabelInfo( - profile: AppBskyActorDefs.ProfileViewBasic, -): ProfileLabelInfo { - return { - accountLabels: filterAccountLabels(profile.labels), - profileLabels: filterProfileLabels(profile.labels), - isMuted: profile.viewer?.muted || false, - isBlocking: !!profile.viewer?.blocking || false, - isBlockedBy: !!profile.viewer?.blockedBy || false, - } -} - -export function getEmbedLabels(embed?: Embed): Label[] { - if (!embed) { - return [] - } - if ( - AppBskyEmbedRecord.isView(embed) && - AppBskyEmbedRecord.isViewRecord(embed.record) - ) { - return embed.record.labels || [] - } - return [] -} - -export function getEmbedMuted(embed?: Embed): boolean { - if (!embed) { - return false - } - if ( - AppBskyEmbedRecord.isView(embed) && - AppBskyEmbedRecord.isViewRecord(embed.record) - ) { - return !!embed.record.author.viewer?.muted - } - return false -} - -export function getEmbedMutedByList( - embed?: Embed, -): AppBskyGraphDefs.ListViewBasic | undefined { - if (!embed) { - return undefined - } - if ( - AppBskyEmbedRecord.isView(embed) && - AppBskyEmbedRecord.isViewRecord(embed.record) - ) { - return embed.record.author.viewer?.mutedByList - } - return undefined -} - -export function getEmbedBlocking(embed?: Embed): boolean { - if (!embed) { - return false - } - if ( - AppBskyEmbedRecord.isView(embed) && - AppBskyEmbedRecord.isViewRecord(embed.record) - ) { - return !!embed.record.author.viewer?.blocking - } - return false -} - -export function getEmbedBlockedBy(embed?: Embed): boolean { - if (!embed) { - return false - } - if ( - AppBskyEmbedRecord.isView(embed) && - AppBskyEmbedRecord.isViewRecord(embed.record) - ) { - return !!embed.record.author.viewer?.blockedBy - } - return false -} - -export function filterAccountLabels(labels?: Label[]): Label[] { - if (!labels) { - return [] - } - return labels.filter( - label => !label.uri.endsWith('/app.bsky.actor.profile/self'), - ) -} - -export function filterProfileLabels(labels?: Label[]): Label[] { - if (!labels) { - return [] - } - return labels.filter(label => - label.uri.endsWith('/app.bsky.actor.profile/self'), - ) -} - -// internal methods -// = - -function show() { - return { - behavior: ModerationBehaviorCode.Show, - } -} - -function hidePostNoOverride(reason: string) { - return { - avatar: {warn: true, blur: true}, - list: hideNoOverride(reason), - thread: hideNoOverride(reason), - view: hideNoOverride(reason), - } -} - -function hideProfileNoOverride(reason: string) { - return { - avatar: {warn: true, blur: true}, - list: hideNoOverride(reason), - view: hideNoOverride(reason), - } -} - -function hideNoOverride(reason: string) { - return { - behavior: ModerationBehaviorCode.Hide, - reason, - noOverride: true, - } -} - -function hide(reason: string) { - return { - behavior: ModerationBehaviorCode.Hide, - reason, - } -} - -function warn(reason: string) { - return { - behavior: ModerationBehaviorCode.Warn, - reason, - } -} - -function warnContent(reason: string) { - return { - behavior: ModerationBehaviorCode.WarnContent, - reason, - } -} - -function isMute(behavior: ModerationBehavior): ModerationBehavior { - behavior.isMute = true - return behavior -} - -function warnImages(reason: string) { - return { - behavior: ModerationBehaviorCode.WarnImages, - reason, - } -} diff --git a/src/lib/labeling/types.ts b/src/lib/labeling/types.ts index 1ee058024..84d59be7f 100644 --- a/src/lib/labeling/types.ts +++ b/src/lib/labeling/types.ts @@ -1,4 +1,4 @@ -import {ComAtprotoLabelDefs, AppBskyGraphDefs} from '@atproto/api' +import {ComAtprotoLabelDefs} from '@atproto/api' import {LabelPreferencesModel} from 'state/models/ui/preferences' export type Label = ComAtprotoLabelDefs.Label @@ -16,54 +16,3 @@ export interface LabelValGroup { warning: string values: string[] } - -export interface PostLabelInfo { - postLabels: Label[] - accountLabels: Label[] - profileLabels: Label[] - isMuted: boolean - mutedByList?: AppBskyGraphDefs.ListViewBasic - isBlocking: boolean - isBlockedBy: boolean -} - -export interface ProfileLabelInfo { - accountLabels: Label[] - profileLabels: Label[] - isMuted: boolean - isBlocking: boolean - isBlockedBy: boolean -} - -export enum ModerationBehaviorCode { - Show, - Hide, - Warn, - WarnContent, - WarnImages, -} - -export interface ModerationBehavior { - behavior: ModerationBehaviorCode - isMute?: boolean - noOverride?: boolean - reason?: string -} - -export interface AvatarModeration { - warn: boolean - blur: boolean -} - -export interface PostModeration { - avatar: AvatarModeration - list: ModerationBehavior - thread: ModerationBehavior - view: ModerationBehavior -} - -export interface ProfileModeration { - avatar: AvatarModeration - list: ModerationBehavior - view: ModerationBehavior -} diff --git a/src/state/models/ui/preferences.ts b/src/state/models/ui/preferences.ts index e9ffe28c2..3b03cdca1 100644 --- a/src/state/models/ui/preferences.ts +++ b/src/state/models/ui/preferences.ts @@ -4,21 +4,9 @@ import AwaitLock from 'await-lock' import isEqual from 'lodash.isequal' import {isObj, hasProp} from 'lib/type-guards' import {RootStoreModel} from '../root-store' -import { - ComAtprotoLabelDefs, - AppBskyActorDefs, - ModerationOpts, -} from '@atproto/api' -import {LabelValGroup} from 'lib/labeling/types' -import {getLabelValueGroup} from 'lib/labeling/helpers' -import { - UNKNOWN_LABEL_GROUP, - ILLEGAL_LABEL_GROUP, - ALWAYS_FILTER_LABEL_GROUP, - ALWAYS_WARN_LABEL_GROUP, -} from 'lib/labeling/const' +import {ModerationOpts} from '@atproto/api' import {DEFAULT_FEEDS} from 'lib/constants' -import {isIOS, deviceLocales} from 'platform/detection' +import {deviceLocales} from 'platform/detection' import {LANGUAGES} from '../../../locale/languages' // TEMP we need to permanently convert 'show' to 'ignore', for now we manually convert -prf @@ -32,7 +20,7 @@ const LABEL_GROUPS = [ 'spam', 'impersonation', ] -const VISIBILITY_VALUES = ['show', 'warn', 'hide'] +const VISIBILITY_VALUES = ['ignore', 'warn', 'hide'] const DEFAULT_LANG_CODES = (deviceLocales || []) .concat(['en', 'ja', 'pt', 'de']) .slice(0, 6) @@ -52,7 +40,7 @@ export class LabelPreferencesModel { } export class PreferencesModel { - adultContentEnabled = !isIOS + adultContentEnabled = false contentLanguages: string[] = deviceLocales || [] postLanguage: string = deviceLocales[0] || 'en' postLanguageHistory: string[] = DEFAULT_LANG_CODES @@ -189,43 +177,32 @@ export class PreferencesModel { await this.lock.acquireAsync() try { // fetch preferences - let hasSavedFeedsPref = false - const res = await this.rootStore.agent.app.bsky.actor.getPreferences({}) + const prefs = await this.rootStore.agent.getPreferences() + runInAction(() => { - for (const pref of res.data.preferences) { + this.adultContentEnabled = prefs.adultContentEnabled + for (const label in prefs.contentLabels) { if ( - AppBskyActorDefs.isAdultContentPref(pref) && - AppBskyActorDefs.validateAdultContentPref(pref).success - ) { - this.adultContentEnabled = pref.enabled - } else if ( - AppBskyActorDefs.isContentLabelPref(pref) && - AppBskyActorDefs.validateAdultContentPref(pref).success + LABEL_GROUPS.includes(label) && + VISIBILITY_VALUES.includes(prefs.contentLabels[label]) ) { - if ( - LABEL_GROUPS.includes(pref.label) && - VISIBILITY_VALUES.includes(pref.visibility) - ) { - this.contentLabels[pref.label as keyof LabelPreferencesModel] = - pref.visibility as LabelPreference - } - } else if ( - AppBskyActorDefs.isSavedFeedsPref(pref) && - AppBskyActorDefs.validateSavedFeedsPref(pref).success - ) { - if (!isEqual(this.savedFeeds, pref.saved)) { - this.savedFeeds = pref.saved - } - if (!isEqual(this.pinnedFeeds, pref.pinned)) { - this.pinnedFeeds = pref.pinned - } - hasSavedFeedsPref = true + this.contentLabels[label as keyof LabelPreferencesModel] = + prefs.contentLabels[label] } } + if (prefs.feeds.saved && !isEqual(this.savedFeeds, prefs.feeds.saved)) { + this.savedFeeds = prefs.feeds.saved + } + if ( + prefs.feeds.pinned && + !isEqual(this.pinnedFeeds, prefs.feeds.pinned) + ) { + this.pinnedFeeds = prefs.feeds.pinned + } }) // set defaults on missing items - if (!hasSavedFeedsPref) { + if (typeof prefs.feeds.saved === 'undefined') { const {saved, pinned} = await DEFAULT_FEEDS( this.rootStore.agent.service.toString(), (handle: string) => @@ -237,14 +214,7 @@ export class PreferencesModel { this.savedFeeds = saved this.pinnedFeeds = pinned }) - res.data.preferences.push({ - $type: 'app.bsky.actor.defs#savedFeedsPref', - saved, - pinned, - }) - await this.rootStore.agent.app.bsky.actor.putPreferences({ - preferences: res.data.preferences, - }) + await this.rootStore.agent.setSavedFeeds(saved, pinned) } } finally { this.lock.release() @@ -254,35 +224,6 @@ export class PreferencesModel { } /** - * This function updates the preferences of a user and allows for a callback function to be executed - * before the update. - * @param cb - cb is a callback function that takes in a single parameter of type - * AppBskyActorDefs.Preferences and returns either a boolean or void. This callback function is used to - * update the preferences of the user. The function is called with the current preferences as an - * argument and if the callback returns false, the preferences are not updated. - * @returns void - */ - async update( - cb: ( - prefs: AppBskyActorDefs.Preferences, - ) => AppBskyActorDefs.Preferences | false, - ) { - await this.lock.acquireAsync() - try { - const res = await this.rootStore.agent.app.bsky.actor.getPreferences({}) - const newPrefs = cb(res.data.preferences) - if (newPrefs === false) { - return - } - await this.rootStore.agent.app.bsky.actor.putPreferences({ - preferences: newPrefs, - }) - } finally { - this.lock.release() - } - } - - /** * This function resets the preferences to an empty array of no preferences. */ async reset() { @@ -381,84 +322,12 @@ export class PreferencesModel { value: LabelPreference, ) { this.contentLabels[key] = value - - await this.update((prefs: AppBskyActorDefs.Preferences) => { - const existing = prefs.find( - pref => - AppBskyActorDefs.isContentLabelPref(pref) && - AppBskyActorDefs.validateAdultContentPref(pref).success && - pref.label === key, - ) - if (existing) { - existing.visibility = value - } else { - prefs.push({ - $type: 'app.bsky.actor.defs#contentLabelPref', - label: key, - visibility: value, - }) - } - return prefs - }) + await this.rootStore.agent.setContentLabelPref(key, value) } async setAdultContentEnabled(v: boolean) { this.adultContentEnabled = v - await this.update((prefs: AppBskyActorDefs.Preferences) => { - const existing = prefs.find( - pref => - AppBskyActorDefs.isAdultContentPref(pref) && - AppBskyActorDefs.validateAdultContentPref(pref).success, - ) - if (existing) { - existing.enabled = v - } else { - prefs.push({ - $type: 'app.bsky.actor.defs#adultContentPref', - enabled: v, - }) - } - return prefs - }) - } - - getLabelPreference(labels: ComAtprotoLabelDefs.Label[] | undefined): { - pref: LabelPreference - desc: LabelValGroup - } { - let res: {pref: LabelPreference; desc: LabelValGroup} = { - pref: 'show', - desc: UNKNOWN_LABEL_GROUP, - } - if (!labels?.length) { - return res - } - for (const label of labels) { - const group = getLabelValueGroup(label.val) - if (group.id === 'illegal') { - return {pref: 'hide', desc: ILLEGAL_LABEL_GROUP} - } else if (group.id === 'always-filter') { - return {pref: 'hide', desc: ALWAYS_FILTER_LABEL_GROUP} - } else if (group.id === 'always-warn') { - res.pref = 'warn' - res.desc = ALWAYS_WARN_LABEL_GROUP - continue - } else if (group.id === 'unknown') { - continue - } - let pref = this.contentLabels[group.id] - if (pref === 'hide') { - res.pref = 'hide' - res.desc = group - } else if (pref === 'warn' && res.pref === 'show') { - res.pref = 'warn' - res.desc = group - } - } - if (res.desc.isAdultImagery && !this.adultContentEnabled) { - res.pref = 'hide' - } - return res + await this.rootStore.agent.setAdultContentEnabled(v) } get moderationOpts(): ModerationOpts { @@ -499,31 +368,20 @@ export class PreferencesModel { } } - async setSavedFeeds(saved: string[], pinned: string[]) { + async _optimisticUpdateSavedFeeds( + saved: string[], + pinned: string[], + cb: () => Promise<{saved: string[]; pinned: string[]}>, + ) { const oldSaved = this.savedFeeds const oldPinned = this.pinnedFeeds this.savedFeeds = saved this.pinnedFeeds = pinned try { - await this.update((prefs: AppBskyActorDefs.Preferences) => { - let feedsPref = prefs.find( - pref => - AppBskyActorDefs.isSavedFeedsPref(pref) && - AppBskyActorDefs.validateSavedFeedsPref(pref).success, - ) - if (feedsPref) { - feedsPref.saved = saved - feedsPref.pinned = pinned - } else { - feedsPref = { - $type: 'app.bsky.actor.defs#savedFeedsPref', - saved, - pinned, - } - } - return prefs - .filter(pref => !AppBskyActorDefs.isSavedFeedsPref(pref)) - .concat([feedsPref]) + const res = await cb() + runInAction(() => { + this.savedFeeds = res.saved + this.pinnedFeeds = res.pinned }) } catch (e) { runInAction(() => { @@ -534,25 +392,41 @@ export class PreferencesModel { } } + async setSavedFeeds(saved: string[], pinned: string[]) { + return this._optimisticUpdateSavedFeeds(saved, pinned, () => + this.rootStore.agent.setSavedFeeds(saved, pinned), + ) + } + async addSavedFeed(v: string) { - return this.setSavedFeeds([...this.savedFeeds, v], this.pinnedFeeds) + return this._optimisticUpdateSavedFeeds( + [...this.savedFeeds, v], + this.pinnedFeeds, + () => this.rootStore.agent.addSavedFeed(v), + ) } async removeSavedFeed(v: string) { - return this.setSavedFeeds( + return this._optimisticUpdateSavedFeeds( this.savedFeeds.filter(uri => uri !== v), this.pinnedFeeds.filter(uri => uri !== v), + () => this.rootStore.agent.removeSavedFeed(v), ) } async addPinnedFeed(v: string) { - return this.setSavedFeeds(this.savedFeeds, [...this.pinnedFeeds, v]) + return this._optimisticUpdateSavedFeeds( + this.savedFeeds, + [...this.pinnedFeeds, v], + () => this.rootStore.agent.addPinnedFeed(v), + ) } async removePinnedFeed(v: string) { - return this.setSavedFeeds( + return this._optimisticUpdateSavedFeeds( this.savedFeeds, this.pinnedFeeds.filter(uri => uri !== v), + () => this.rootStore.agent.removePinnedFeed(v), ) } diff --git a/src/view/com/modals/ContentFilteringSettings.tsx b/src/view/com/modals/ContentFilteringSettings.tsx index 5215c9cb4..f39351feb 100644 --- a/src/view/com/modals/ContentFilteringSettings.tsx +++ b/src/view/com/modals/ContentFilteringSettings.tsx @@ -48,15 +48,17 @@ export const Component = observer(({}: {}) => { <ScrollView style={styles.scrollContainer}> <View style={s.mb10}> {isIOS ? ( - <Text type="md" style={pal.textLight}> - Adult content can only be enabled via the Web at{' '} - <TextLink - style={pal.link} - href="https://bsky.app" - text="bsky.app" - /> - . - </Text> + store.preferences.adultContentEnabled ? null : ( + <Text type="md" style={pal.textLight}> + Adult content can only be enabled via the Web at{' '} + <TextLink + style={pal.link} + href="https://bsky.app" + text="bsky.app" + /> + . + </Text> + ) ) : ( <ToggleButton type="default-light" @@ -188,7 +190,7 @@ function SelectGroup({current, onChange, group}: SelectGroupProps) { /> <SelectableBtn current={current} - value="show" + value="ignore" label="Show" right onChange={onChange} |