20d463ff2f
* Add modservice screen and profile-header-card * Drop the guidelines for now * Remove ununsed constants * Add label & label group descriptions * Not found state * Reorg, add icon * Subheader * Header * Complete header * Clean up * Add all groups * Fix scroll view * Dialogs side quest * Remove log * Add (WIP) debug mod page * Dialog solution * Add note * Clean up and reorganize localized moderation strings * Memoize * Add example * Add first ReportDialog screen * Report dialog step 2 * Submit * Integrate updates * Move moderation screen * Migrate buttons * Migrate everything * Rough sketch * Fix types * Update atoms values * Abstract ModerationServiceCard * Hook up data to settings page * Handle subscription * Rough enablement * Rough enablement * Some validation, fixes * More work on the mod debug screen * Hook up data * Update invalidation * Hook up data to ReportDialog * Fix native error * Refactor/rewrite the entire moderation-application system * Fix toggles * Add copyright and other option to report * Handle reports on profile vs content * Little cleanup * Get post hiding back in gear * Better loading flow on Mod screen * Clean up Mod screen * Clean up ProfileMod screen * Handle muting correctly * Update enablement on ProfileMod screen * Improve Moderation screen and dialog * Styling, handle disabled labelers * Rework list of labels on own content * Use moderateNotification() * ReportDialog updates * Fix button overflow * Simplify the ProfileModerationService ui * Mod screen design * Move moderation card from the profile header to a tab * Small tweaks to the moderation screen * Enable toggle on mod page * Add notifs to debugmod and dont filter notifs from followed users * Add moderator-service profile view * Wire up more of the modservice data to profiles * A bunch of speculative non-working UI * Cleanup: delete old code * Update ModerationDetailsDialog * Update ReportDialog * Update LabelsOnMe dialog * Handle ReportDialog load better * Rename LabelsOnMeDialog, fix close * Experiment to put labeling under a tab of a normal profile * Moderator variation of profile * Remove dead code and start moving toward latest modsdk * Remove a bunch of now-dead label strings * Update ModDebug to be a bit more intuitive and support custom labels * Minor ui tweaks * Improve consistency of display name blurring * Fix profile-card warning rendering * More debugmod UI tuning * Update to use new labeler semantics * Delete some dead code and do some refactoring * Update profile to pull from labeler definition * Implement new label config controls (wip) * Tweak ui * Implement preference controls on labelers * Rework label pref ui * Get moderation screen working * Add asyncstorage query persistence * Implement label handling * Small cleanup * Implement Likes dialog * Fix: remove text outside of text element * Cleanup * Fix likes dialog on mobile * Implement the label appeal flow * Get report flow working again with temporarily fixed report options * Update onboarding * Enforce limit of ten labeler subscriptions * Fix type errors * Fix lint errors * Improve types of RQ * Some work on Likes dialog, needs discussion * Bit of ReportDialog cleanup * Replace non-single-path SVG * Update nudity descriptions * Update to use new sdk updates * Add adult-content-enabled behavior to label config * Use the default setting of custom labels * Handle global moderation label prefs with the global settings * Fix missing postAuthor * Fix empty moderation page * Add mutewords control back to Mod screen * Tweak adult setting styles * Remove deprecated global labels * Handle underage users on mod screen * Adjust font sizes * Swap in RichText * Like button improvements * Tweaks to Labeler profile * Design tweaks for mod pref dialog * Add tertiary button color * Switch moderation UIs to tertiary color * Update mutewords and hiddenposts to use the new sdk * Add test-environment mod authority * Switch 'gore' to 'graphic-media' * Move nudity out of the adult content control * Remove focus styles from buttons - let the browser behavior handle it * Fixes to the adult content age-gating in moderaiton * Ditch tertiary button color, lighten secondary button * Fix some colors * Remove focused overrides from toggles * Liked by screen * Rework the moderationlabelpref * Fix optimistic like * Cleanup * Change how onboarding handles adult content enabled/disabled * Add special handling of the mod authorities * Tweaks * Update the default labeler avatar to a shield * Add route to go server * Avoid dups due to bad config * Fix attrs * Fix: dont try to detect link/label mismatches on post meta * Correctly show the label behavior when adult content is disabled * Readd the local hiddenPosts handling * WIP * Fix bad merge * Conten hider design tweaks * Fix text string breakage * Adjust source text in ContentHider * Fix link bug * Design tweaks to ContentHider and ModDetailsDialog * Adjust spacing of inform badges * Adjust spacing of embeds in posts * Style tweaks to post/profile alerts * Labels on me and dialog * Remove bad focus styles from post dropdown * Better spacing solution * Tune moderation UIs * Moderation UI tweaks for mobile * Move labelers query on Mod screen * Update to use new SDK appLabelers semantics * Implement report submission * Replace the report modal entirely with the report dialog * Add @ to mod details dialog handle * Bump SDK package * Remove silly type * Add to AWS build CI * Fix ToggleButton overflow * Clean up ModServiceCard, rename to LabelingServiceCard * Hackfix to translate gore labels to graphic-media * Tune content hider sizing on web desktop * Handle self labels * Fix spacing below text-only posts * Fix: send appeals to the right labeler * Give mod page links interactive states * Fix references * Remove focus handling * Remove remnant * Remove the like count from the subscribed labeler listing * Bump @atproto/api@0.11.1 * Remove extra @ * Fix: persist labels to local storage to reduce coverage gaps * update dipendencies * revert dipendencies * Add some explainers on how blocking affects labelers * Tweak copy * Fix underline color in header * Fix profile menu * Handle card overflow * Remove metrics from header * Mute 'account' not 'user' * Show metrics if self * Show the labels tab on logged out view * Fix bad merge * Use purple theming on labelers * Tighten space on LabelerCard * Set staleTime to 6hrs for labeler details * Memoize the memoizers * Drop staleTime to 60s * Move label defs into a context to reduce recomputes * Submit view tweaks * Move labeler fetch below auth * Mitigation: hardcode the bluesky moderation labeler name * Bump sdk * Add missing translated string Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com> * Add missing translated string Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com> * Hailey's fix for incorrect profile tabs Co-authored-by: Hailey <me@haileyok.com> * Feedback * Fix borders, add bottom space * Hailey's fix pt 2 Co-authored-by: Hailey <me@haileyok.com> * Fix post tabs * Integrate feedback pt 1 Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com> * Integrate feedback pt 2 Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com> * Integrate feedback pt 3 Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com> * Integrate feedback pt 4 Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com> * Integrate feedback pt 5 Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com> * Integrate feedback pt 6 Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com> * Integrate feedback pt 7 Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com> * Integrate feedback pt 8 Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com> * Format * Integrate new bday modal * Use public agent for getServices * Update casing --------- Co-authored-by: Eric Bailey <git@esb.lol> Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com> Co-authored-by: Hailey <me@haileyok.com>
203 lines
5.9 KiB
TypeScript
203 lines
5.9 KiB
TypeScript
import React from 'react'
|
|
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
|
import {ModerationUI} from '@atproto/api'
|
|
import {Image} from 'expo-image'
|
|
import {useLingui} from '@lingui/react'
|
|
import {msg, Trans} from '@lingui/macro'
|
|
|
|
import {colors} from 'lib/styles'
|
|
import {useTheme} from 'lib/ThemeContext'
|
|
import {useTheme as useAlfTheme, tokens} from '#/alf'
|
|
import {openCamera, openCropper, openPicker} from '../../../lib/media/picker'
|
|
import {
|
|
usePhotoLibraryPermission,
|
|
useCameraPermission,
|
|
} from 'lib/hooks/usePermissions'
|
|
import {usePalette} from 'lib/hooks/usePalette'
|
|
import {isAndroid, isNative} from 'platform/detection'
|
|
import {Image as RNImage} from 'react-native-image-crop-picker'
|
|
import {EventStopper} from 'view/com/util/EventStopper'
|
|
import * as Menu from '#/components/Menu'
|
|
import {
|
|
Camera_Filled_Stroke2_Corner0_Rounded as CameraFilled,
|
|
Camera_Stroke2_Corner0_Rounded as Camera,
|
|
} from '#/components/icons/Camera'
|
|
import {StreamingLive_Stroke2_Corner0_Rounded as Library} from '#/components/icons/StreamingLive'
|
|
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
|
|
|
|
export function UserBanner({
|
|
type,
|
|
banner,
|
|
moderation,
|
|
onSelectNewBanner,
|
|
}: {
|
|
type?: 'labeler' | 'default'
|
|
banner?: string | null
|
|
moderation?: ModerationUI
|
|
onSelectNewBanner?: (img: RNImage | null) => void
|
|
}) {
|
|
const pal = usePalette('default')
|
|
const theme = useTheme()
|
|
const t = useAlfTheme()
|
|
const {_} = useLingui()
|
|
const {requestCameraAccessIfNeeded} = useCameraPermission()
|
|
const {requestPhotoAccessIfNeeded} = usePhotoLibraryPermission()
|
|
|
|
const onOpenCamera = React.useCallback(async () => {
|
|
if (!(await requestCameraAccessIfNeeded())) {
|
|
return
|
|
}
|
|
onSelectNewBanner?.(
|
|
await openCamera({
|
|
width: 3000,
|
|
height: 1000,
|
|
}),
|
|
)
|
|
}, [onSelectNewBanner, requestCameraAccessIfNeeded])
|
|
|
|
const onOpenLibrary = React.useCallback(async () => {
|
|
if (!(await requestPhotoAccessIfNeeded())) {
|
|
return
|
|
}
|
|
const items = await openPicker()
|
|
if (!items[0]) {
|
|
return
|
|
}
|
|
|
|
onSelectNewBanner?.(
|
|
await openCropper({
|
|
mediaType: 'photo',
|
|
path: items[0].path,
|
|
width: 3000,
|
|
height: 1000,
|
|
}),
|
|
)
|
|
}, [onSelectNewBanner, requestPhotoAccessIfNeeded])
|
|
|
|
const onRemoveBanner = React.useCallback(() => {
|
|
onSelectNewBanner?.(null)
|
|
}, [onSelectNewBanner])
|
|
|
|
// setUserBanner is only passed as prop on the EditProfile component
|
|
return onSelectNewBanner ? (
|
|
<EventStopper onKeyDown={false}>
|
|
<Menu.Root>
|
|
<Menu.Trigger label={_(msg`Edit avatar`)}>
|
|
{({props}) => (
|
|
<TouchableOpacity {...props} activeOpacity={0.8}>
|
|
{banner ? (
|
|
<Image
|
|
testID="userBannerImage"
|
|
style={styles.bannerImage}
|
|
source={{uri: banner}}
|
|
accessible={true}
|
|
accessibilityIgnoresInvertColors
|
|
/>
|
|
) : (
|
|
<View
|
|
testID="userBannerFallback"
|
|
style={[styles.bannerImage, styles.defaultBanner]}
|
|
/>
|
|
)}
|
|
<View style={[styles.editButtonContainer, pal.btn]}>
|
|
<CameraFilled height={14} width={14} style={t.atoms.text} />
|
|
</View>
|
|
</TouchableOpacity>
|
|
)}
|
|
</Menu.Trigger>
|
|
<Menu.Outer showCancel>
|
|
<Menu.Group>
|
|
{isNative && (
|
|
<Menu.Item
|
|
testID="changeBannerCameraBtn"
|
|
label={_(msg`Upload from Camera`)}
|
|
onPress={onOpenCamera}>
|
|
<Menu.ItemText>
|
|
<Trans>Upload from Camera</Trans>
|
|
</Menu.ItemText>
|
|
<Menu.ItemIcon icon={Camera} />
|
|
</Menu.Item>
|
|
)}
|
|
|
|
<Menu.Item
|
|
testID="changeBannerLibraryBtn"
|
|
label={_(msg`Upload from Library`)}
|
|
onPress={onOpenLibrary}>
|
|
<Menu.ItemText>
|
|
{isNative ? (
|
|
<Trans>Upload from Library</Trans>
|
|
) : (
|
|
<Trans>Upload from Files</Trans>
|
|
)}
|
|
</Menu.ItemText>
|
|
<Menu.ItemIcon icon={Library} />
|
|
</Menu.Item>
|
|
</Menu.Group>
|
|
{!!banner && (
|
|
<>
|
|
<Menu.Divider />
|
|
<Menu.Group>
|
|
<Menu.Item
|
|
testID="changeBannerRemoveBtn"
|
|
label={_(`Remove Banner`)}
|
|
onPress={onRemoveBanner}>
|
|
<Menu.ItemText>
|
|
<Trans>Remove Banner</Trans>
|
|
</Menu.ItemText>
|
|
<Menu.ItemIcon icon={Trash} />
|
|
</Menu.Item>
|
|
</Menu.Group>
|
|
</>
|
|
)}
|
|
</Menu.Outer>
|
|
</Menu.Root>
|
|
</EventStopper>
|
|
) : banner &&
|
|
!((moderation?.blur && isAndroid) /* android crashes with blur */) ? (
|
|
<Image
|
|
testID="userBannerImage"
|
|
style={[
|
|
styles.bannerImage,
|
|
{backgroundColor: theme.palette.default.backgroundLight},
|
|
]}
|
|
resizeMode="cover"
|
|
source={{uri: banner}}
|
|
blurRadius={moderation?.blur ? 100 : 0}
|
|
accessible={true}
|
|
accessibilityIgnoresInvertColors
|
|
/>
|
|
) : (
|
|
<View
|
|
testID="userBannerFallback"
|
|
style={[
|
|
styles.bannerImage,
|
|
type === 'labeler' ? styles.labelerBanner : styles.defaultBanner,
|
|
]}
|
|
/>
|
|
)
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
editButtonContainer: {
|
|
position: 'absolute',
|
|
width: 24,
|
|
height: 24,
|
|
bottom: 8,
|
|
right: 24,
|
|
borderRadius: 12,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
backgroundColor: colors.gray5,
|
|
},
|
|
bannerImage: {
|
|
width: '100%',
|
|
height: 150,
|
|
},
|
|
defaultBanner: {
|
|
backgroundColor: '#0070ff',
|
|
},
|
|
labelerBanner: {
|
|
backgroundColor: tokens.color.temp_purple,
|
|
},
|
|
})
|