about summary refs log tree commit diff
path: root/src/view/com/modals
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/modals')
-rw-r--r--src/view/com/modals/CreateOrEditList.tsx (renamed from src/view/com/modals/CreateOrEditMuteList.tsx)58
-rw-r--r--src/view/com/modals/ListAddUser.tsx281
-rw-r--r--src/view/com/modals/Modal.tsx20
-rw-r--r--src/view/com/modals/Modal.web.tsx15
-rw-r--r--src/view/com/modals/ModerationDetails.tsx21
-rw-r--r--src/view/com/modals/UserAddRemoveLists.tsx (renamed from src/view/com/modals/ListAddRemoveUser.tsx)67
6 files changed, 394 insertions, 68 deletions
diff --git a/src/view/com/modals/CreateOrEditMuteList.tsx b/src/view/com/modals/CreateOrEditList.tsx
index 4a440afeb..1ea12695f 100644
--- a/src/view/com/modals/CreateOrEditMuteList.tsx
+++ b/src/view/com/modals/CreateOrEditList.tsx
@@ -1,4 +1,4 @@
-import React, {useState, useCallback} from 'react'
+import React, {useState, useCallback, useMemo} from 'react'
 import * as Toast from '../util/Toast'
 import {
   ActivityIndicator,
@@ -31,9 +31,11 @@ const MAX_DESCRIPTION = 300 // todo
 export const snapPoints = ['fullscreen']
 
 export function Component({
+  purpose,
   onSave,
   list,
 }: {
+  purpose?: string
   onSave?: (uri: string) => void
   list?: ListModel
 }) {
@@ -44,12 +46,24 @@ export function Component({
   const theme = useTheme()
   const {track} = useAnalytics()
 
+  const activePurpose = useMemo(() => {
+    if (list?.data?.purpose) {
+      return list.data.purpose
+    }
+    if (purpose) {
+      return purpose
+    }
+    return 'app.bsky.graph.defs#curatelist'
+  }, [list, purpose])
+  const isCurateList = activePurpose === 'app.bsky.graph.defs#curatelist'
+  const purposeLabel = isCurateList ? 'User' : 'Moderation'
+
   const [isProcessing, setProcessing] = useState<boolean>(false)
-  const [name, setName] = useState<string>(list?.list?.name || '')
+  const [name, setName] = useState<string>(list?.data?.name || '')
   const [description, setDescription] = useState<string>(
-    list?.list?.description || '',
+    list?.data?.description || '',
   )
-  const [avatar, setAvatar] = useState<string | undefined>(list?.list?.avatar)
+  const [avatar, setAvatar] = useState<string | undefined>(list?.data?.avatar)
   const [newAvatar, setNewAvatar] = useState<RNImage | undefined | null>()
 
   const onPressCancel = useCallback(() => {
@@ -63,7 +77,7 @@ export function Component({
         setAvatar(undefined)
         return
       }
-      track('CreateMuteList:AvatarSelected')
+      track('CreateList:AvatarSelected')
       try {
         const finalImg = await compressIfNeeded(img, 1000000)
         setNewAvatar(finalImg)
@@ -76,7 +90,11 @@ export function Component({
   )
 
   const onPressSave = useCallback(async () => {
-    track('CreateMuteList:Save')
+    if (isCurateList) {
+      track('CreateList:SaveCurateList')
+    } else {
+      track('CreateList:SaveModList')
+    }
     const nameTrimmed = name.trim()
     if (!nameTrimmed) {
       setError('Name is required')
@@ -93,22 +111,23 @@ export function Component({
           description: description.trim(),
           avatar: newAvatar,
         })
-        Toast.show('Mute list updated')
+        Toast.show(`${purposeLabel} list updated`)
         onSave?.(list.uri)
       } else {
-        const res = await ListModel.createModList(store, {
+        const res = await ListModel.createList(store, {
+          purpose: activePurpose,
           name,
           description,
           avatar: newAvatar,
         })
-        Toast.show('Mute list created')
+        Toast.show(`${purposeLabel} list created`)
         onSave?.(res.uri)
       }
       store.shell.closeModal()
     } catch (e: any) {
       if (isNetworkError(e)) {
         setError(
-          'Failed to create the mute list. Check your internet connection and try again.',
+          'Failed to create the list. Check your internet connection and try again.',
         )
       } else {
         setError(cleanError(e))
@@ -122,6 +141,9 @@ export function Component({
     error,
     onSave,
     store,
+    activePurpose,
+    isCurateList,
+    purposeLabel,
     name,
     description,
     newAvatar,
@@ -137,9 +159,9 @@ export function Component({
             paddingHorizontal: isMobile ? 16 : 0,
           },
         ]}
-        testID="createOrEditMuteListModal">
+        testID="createOrEditListModal">
         <Text style={[styles.title, pal.text]}>
-          {list ? 'Edit Mute List' : 'New Mute List'}
+          {list ? 'Edit' : 'New'} {purposeLabel} List
         </Text>
         {error !== '' && (
           <View style={styles.errorContainer}>
@@ -163,7 +185,9 @@ export function Component({
             <TextInput
               testID="editNameInput"
               style={[styles.textInput, pal.border, pal.text]}
-              placeholder="e.g. spammers"
+              placeholder={
+                isCurateList ? 'e.g. Great Posters' : 'e.g. Spammers'
+              }
               placeholderTextColor={colors.gray4}
               value={name}
               onChangeText={v => setName(enforceLen(v, MAX_NAME))}
@@ -180,7 +204,11 @@ export function Component({
             <TextInput
               testID="editDescriptionInput"
               style={[styles.textArea, pal.border, pal.text]}
-              placeholder="e.g. users that repeatedly reply with ads."
+              placeholder={
+                isCurateList
+                  ? 'e.g. The posters who never miss.'
+                  : 'e.g. Users that repeatedly reply with ads.'
+              }
               placeholderTextColor={colors.gray4}
               keyboardAppearance={theme.colorScheme}
               multiline
@@ -203,7 +231,7 @@ export function Component({
               onPress={onPressSave}
               accessibilityRole="button"
               accessibilityLabel="Save"
-              accessibilityHint="Creates the mute list">
+              accessibilityHint="">
               <LinearGradient
                 colors={[gradients.blueLight.start, gradients.blueLight.end]}
                 start={{x: 0, y: 0}}
diff --git a/src/view/com/modals/ListAddUser.tsx b/src/view/com/modals/ListAddUser.tsx
new file mode 100644
index 000000000..6ee20ff13
--- /dev/null
+++ b/src/view/com/modals/ListAddUser.tsx
@@ -0,0 +1,281 @@
+import React, {useEffect, useCallback, useState, useMemo} from 'react'
+import {
+  ActivityIndicator,
+  Pressable,
+  SafeAreaView,
+  StyleSheet,
+  View,
+} from 'react-native'
+import {AppBskyActorDefs} from '@atproto/api'
+import {ScrollView, TextInput} from './util'
+import {observer} from 'mobx-react-lite'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {Text} from '../util/text/Text'
+import {Button} from '../util/forms/Button'
+import {UserAvatar} from '../util/UserAvatar'
+import * as Toast from '../util/Toast'
+import {useStores} from 'state/index'
+import {ListModel} from 'state/models/content/list'
+import {UserAutocompleteModel} from 'state/models/discovery/user-autocomplete'
+import {s, colors} from 'lib/styles'
+import {usePalette} from 'lib/hooks/usePalette'
+import {isWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {cleanError} from 'lib/strings/errors'
+import {sanitizeDisplayName} from 'lib/strings/display-names'
+import {sanitizeHandle} from 'lib/strings/handles'
+
+export const snapPoints = ['90%']
+
+export const Component = observer(function Component({
+  list,
+  onAdd,
+}: {
+  list: ListModel
+  onAdd?: (profile: AppBskyActorDefs.ProfileViewBasic) => void
+}) {
+  const pal = usePalette('default')
+  const store = useStores()
+  const {isMobile} = useWebMediaQueries()
+  const [query, setQuery] = useState('')
+  const autocompleteView = useMemo<UserAutocompleteModel>(
+    () => new UserAutocompleteModel(store),
+    [store],
+  )
+
+  // initial setup
+  useEffect(() => {
+    autocompleteView.setup().then(() => {
+      autocompleteView.setPrefix('')
+    })
+    autocompleteView.setActive(true)
+    list.loadAll()
+  }, [autocompleteView, list])
+
+  const onChangeQuery = useCallback(
+    (text: string) => {
+      setQuery(text)
+      autocompleteView.setPrefix(text)
+    },
+    [setQuery, autocompleteView],
+  )
+
+  const onPressCancelSearch = useCallback(
+    () => onChangeQuery(''),
+    [onChangeQuery],
+  )
+
+  return (
+    <SafeAreaView
+      testID="listAddUserModal"
+      style={[pal.view, isWeb ? styles.fixedHeight : s.flex1]}>
+      <View
+        style={[
+          s.flex1,
+          isMobile && {paddingHorizontal: 18, paddingBottom: 40},
+        ]}>
+        <View style={styles.titleSection}>
+          <Text type="title-lg" style={[pal.text, styles.title]}>
+            Add User to List
+          </Text>
+        </View>
+        <View style={[styles.searchContainer, pal.border]}>
+          <FontAwesomeIcon icon="search" size={16} />
+          <TextInput
+            testID="searchInput"
+            style={[styles.searchInput, pal.border, pal.text]}
+            placeholder="Search for users"
+            placeholderTextColor={pal.colors.textLight}
+            value={query}
+            onChangeText={onChangeQuery}
+            accessible={true}
+            accessibilityLabel="Search"
+            accessibilityHint=""
+            autoCapitalize="none"
+            autoComplete="off"
+            autoCorrect={false}
+          />
+          {query ? (
+            <Pressable
+              onPress={onPressCancelSearch}
+              accessibilityRole="button"
+              accessibilityLabel="Cancel search"
+              accessibilityHint="Exits inputting search query"
+              onAccessibilityEscape={onPressCancelSearch}>
+              <FontAwesomeIcon
+                icon="xmark"
+                size={16}
+                color={pal.colors.textLight}
+              />
+            </Pressable>
+          ) : undefined}
+        </View>
+        <ScrollView style={[s.flex1]}>
+          {autocompleteView.suggestions.length ? (
+            <>
+              {autocompleteView.suggestions.slice(0, 40).map((item, i) => (
+                <UserResult
+                  key={item.did}
+                  list={list}
+                  profile={item}
+                  noBorder={i === 0}
+                  onAdd={onAdd}
+                />
+              ))}
+            </>
+          ) : (
+            <Text
+              type="xl"
+              style={[
+                pal.textLight,
+                {paddingHorizontal: 12, paddingVertical: 16},
+              ]}>
+              No results found for {autocompleteView.prefix}
+            </Text>
+          )}
+        </ScrollView>
+        <View style={[styles.btnContainer]}>
+          <Button
+            testID="doneBtn"
+            type="primary"
+            onPress={() => store.shell.closeModal()}
+            accessibilityLabel="Done"
+            accessibilityHint=""
+            label="Done"
+            labelContainerStyle={{justifyContent: 'center', padding: 4}}
+            labelStyle={[s.f18]}
+          />
+        </View>
+      </View>
+    </SafeAreaView>
+  )
+})
+
+function UserResult({
+  profile,
+  list,
+  noBorder,
+  onAdd,
+}: {
+  profile: AppBskyActorDefs.ProfileViewBasic
+  list: ListModel
+  noBorder: boolean
+  onAdd?: (profile: AppBskyActorDefs.ProfileViewBasic) => void | undefined
+}) {
+  const pal = usePalette('default')
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [isAdded, setIsAdded] = useState(list.isMember(profile.did))
+
+  const onPressAdd = useCallback(async () => {
+    setIsProcessing(true)
+    try {
+      await list.addMember(profile)
+      Toast.show('Added to list')
+      setIsAdded(true)
+      onAdd?.(profile)
+    } catch (e) {
+      Toast.show(cleanError(e))
+    } finally {
+      setIsProcessing(false)
+    }
+  }, [list, profile, setIsProcessing, setIsAdded, onAdd])
+
+  return (
+    <View
+      style={[
+        pal.border,
+        {
+          flexDirection: 'row',
+          alignItems: 'center',
+          borderTopWidth: noBorder ? 0 : 1,
+          paddingVertical: 8,
+          paddingHorizontal: 8,
+        },
+      ]}>
+      <View
+        style={{
+          alignSelf: 'baseline',
+          width: 54,
+          paddingLeft: 4,
+          paddingTop: 10,
+        }}>
+        <UserAvatar size={40} avatar={profile.avatar} />
+      </View>
+      <View
+        style={{
+          flex: 1,
+          paddingRight: 10,
+          paddingTop: 10,
+          paddingBottom: 10,
+        }}>
+        <Text
+          type="lg"
+          style={[s.bold, pal.text]}
+          numberOfLines={1}
+          lineHeight={1.2}>
+          {sanitizeDisplayName(
+            profile.displayName || sanitizeHandle(profile.handle),
+          )}
+        </Text>
+        <Text type="md" style={[pal.textLight]} numberOfLines={1}>
+          {sanitizeHandle(profile.handle, '@')}
+        </Text>
+        {!!profile.viewer?.followedBy && <View style={s.flexRow} />}
+      </View>
+      <View>
+        {isAdded ? (
+          <FontAwesomeIcon icon="check" />
+        ) : isProcessing ? (
+          <ActivityIndicator />
+        ) : (
+          <Button
+            testID={`user-${profile.handle}-addBtn`}
+            type="default"
+            label="Add"
+            onPress={onPressAdd}
+          />
+        )}
+      </View>
+    </View>
+  )
+}
+
+const styles = StyleSheet.create({
+  fixedHeight: {
+    // @ts-ignore web only -prf
+    height: '80vh',
+  },
+  titleSection: {
+    paddingTop: isWeb ? 0 : 4,
+    paddingBottom: isWeb ? 14 : 10,
+  },
+  title: {
+    textAlign: 'center',
+    fontWeight: '600',
+    marginBottom: 5,
+  },
+  searchContainer: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    gap: 8,
+    borderWidth: 1,
+    borderRadius: 24,
+    paddingHorizontal: 16,
+    paddingVertical: 10,
+  },
+  searchInput: {
+    fontSize: 16,
+    flex: 1,
+  },
+  btn: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'center',
+    borderRadius: 32,
+    padding: 14,
+    backgroundColor: colors.blue3,
+  },
+  btnContainer: {
+    paddingTop: 20,
+  },
+})
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index 1fe1299d7..5aaa09e87 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -16,8 +16,9 @@ import * as ProfilePreviewModal from './ProfilePreview'
 import * as ServerInputModal from './ServerInput'
 import * as RepostModal from './Repost'
 import * as SelfLabelModal from './SelfLabel'
-import * as CreateOrEditMuteListModal from './CreateOrEditMuteList'
-import * as ListAddRemoveUserModal from './ListAddRemoveUser'
+import * as CreateOrEditListModal from './CreateOrEditList'
+import * as UserAddRemoveListsModal from './UserAddRemoveLists'
+import * as ListAddUserModal from './ListAddUser'
 import * as AltImageModal from './AltImage'
 import * as EditImageModal from './AltImage'
 import * as ReportModal from './report/Modal'
@@ -101,12 +102,15 @@ export const ModalsContainer = observer(function ModalsContainer() {
   } else if (activeModal?.name === 'report') {
     snapPoints = ReportModal.snapPoints
     element = <ReportModal.Component {...activeModal} />
-  } else if (activeModal?.name === 'create-or-edit-mute-list') {
-    snapPoints = CreateOrEditMuteListModal.snapPoints
-    element = <CreateOrEditMuteListModal.Component {...activeModal} />
-  } else if (activeModal?.name === 'list-add-remove-user') {
-    snapPoints = ListAddRemoveUserModal.snapPoints
-    element = <ListAddRemoveUserModal.Component {...activeModal} />
+  } else if (activeModal?.name === 'create-or-edit-list') {
+    snapPoints = CreateOrEditListModal.snapPoints
+    element = <CreateOrEditListModal.Component {...activeModal} />
+  } else if (activeModal?.name === 'user-add-remove-lists') {
+    snapPoints = UserAddRemoveListsModal.snapPoints
+    element = <UserAddRemoveListsModal.Component {...activeModal} />
+  } else if (activeModal?.name === 'list-add-user') {
+    snapPoints = ListAddUserModal.snapPoints
+    element = <ListAddUserModal.Component {...activeModal} />
   } else if (activeModal?.name === 'delete-account') {
     snapPoints = DeleteAccountModal.snapPoints
     element = <DeleteAccountModal.Component />
diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx
index ee778d17d..ede845378 100644
--- a/src/view/com/modals/Modal.web.tsx
+++ b/src/view/com/modals/Modal.web.tsx
@@ -11,8 +11,9 @@ import * as EditProfileModal from './EditProfile'
 import * as ProfilePreviewModal from './ProfilePreview'
 import * as ServerInputModal from './ServerInput'
 import * as ReportModal from './report/Modal'
-import * as CreateOrEditMuteListModal from './CreateOrEditMuteList'
-import * as ListAddRemoveUserModal from './ListAddRemoveUser'
+import * as CreateOrEditListModal from './CreateOrEditList'
+import * as UserAddRemoveLists from './UserAddRemoveLists'
+import * as ListAddUserModal from './ListAddUser'
 import * as DeleteAccountModal from './DeleteAccount'
 import * as RepostModal from './Repost'
 import * as SelfLabelModal from './SelfLabel'
@@ -79,10 +80,12 @@ function Modal({modal}: {modal: ModalIface}) {
     element = <ServerInputModal.Component {...modal} />
   } else if (modal.name === 'report') {
     element = <ReportModal.Component {...modal} />
-  } else if (modal.name === 'create-or-edit-mute-list') {
-    element = <CreateOrEditMuteListModal.Component {...modal} />
-  } else if (modal.name === 'list-add-remove-user') {
-    element = <ListAddRemoveUserModal.Component {...modal} />
+  } else if (modal.name === 'create-or-edit-list') {
+    element = <CreateOrEditListModal.Component {...modal} />
+  } else if (modal.name === 'user-add-remove-lists') {
+    element = <UserAddRemoveLists.Component {...modal} />
+  } else if (modal.name === 'list-add-user') {
+    element = <ListAddUserModal.Component {...modal} />
   } else if (modal.name === 'crop-image') {
     element = <CropImageModal.Component {...modal} />
   } else if (modal.name === 'delete-account') {
diff --git a/src/view/com/modals/ModerationDetails.tsx b/src/view/com/modals/ModerationDetails.tsx
index bd51845c6..c01312d69 100644
--- a/src/view/com/modals/ModerationDetails.tsx
+++ b/src/view/com/modals/ModerationDetails.tsx
@@ -31,8 +31,25 @@ export function Component({
     description =
       'Moderator has chosen to set a general warning on the content.'
   } else if (moderation.cause.type === 'blocking') {
-    name = 'User Blocked'
-    description = 'You have blocked this user. You cannot view their content.'
+    if (moderation.cause.source.type === 'list') {
+      const list = moderation.cause.source.list
+      name = 'User Blocked by List'
+      description = (
+        <>
+          This user is included in the{' '}
+          <TextLink
+            type="2xl"
+            href={listUriToHref(list.uri)}
+            text={list.name}
+            style={pal.link}
+          />{' '}
+          list which you have blocked.
+        </>
+      )
+    } else {
+      name = 'User Blocked'
+      description = 'You have blocked this user. You cannot view their content.'
+    }
   } else if (moderation.cause.type === 'blocked-by') {
     name = 'User Blocks You'
     description = 'This user has blocked you. You cannot view their content.'
diff --git a/src/view/com/modals/ListAddRemoveUser.tsx b/src/view/com/modals/UserAddRemoveLists.tsx
index 58d6a529c..ff048ca29 100644
--- a/src/view/com/modals/ListAddRemoveUser.tsx
+++ b/src/view/com/modals/UserAddRemoveLists.tsx
@@ -1,6 +1,6 @@
 import React, {useCallback} from 'react'
 import {observer} from 'mobx-react-lite'
-import {Pressable, StyleSheet, View, ActivityIndicator} from 'react-native'
+import {ActivityIndicator, Pressable, StyleSheet, View} from 'react-native'
 import {AppBskyGraphDefs as GraphDefs} from '@atproto/api'
 import {
   FontAwesomeIcon,
@@ -11,7 +11,6 @@ import {UserAvatar} from '../util/UserAvatar'
 import {ListsList} from '../lists/ListsList'
 import {ListsListModel} from 'state/models/lists/lists-list'
 import {ListMembershipModel} from 'state/models/content/list-membership'
-import {EmptyStateWithButton} from '../util/EmptyStateWithButton'
 import {Button} from '../util/forms/Button'
 import * as Toast from '../util/Toast'
 import {useStores} from 'state/index'
@@ -24,14 +23,16 @@ import isEqual from 'lodash.isequal'
 
 export const snapPoints = ['fullscreen']
 
-export const Component = observer(function ListAddRemoveUserImpl({
+export const Component = observer(function UserAddRemoveListsImpl({
   subject,
   displayName,
-  onUpdate,
+  onAdd,
+  onRemove,
 }: {
   subject: string
   displayName: string
-  onUpdate?: () => void
+  onAdd?: (listUri: string) => void
+  onRemove?: (listUri: string) => void
 }) {
   const store = useStores()
   const pal = usePalette('default')
@@ -71,25 +72,22 @@ export const Component = observer(function ListAddRemoveUserImpl({
   }, [store])
 
   const onPressSave = useCallback(async () => {
+    let changes
     try {
-      await memberships.updateTo(selected)
+      changes = await memberships.updateTo(selected)
     } catch (err) {
       store.log.error('Failed to update memberships', {err})
       return
     }
     Toast.show('Lists updated')
-    onUpdate?.()
+    for (const uri of changes.added) {
+      onAdd?.(uri)
+    }
+    for (const uri of changes.removed) {
+      onRemove?.(uri)
+    }
     store.shell.closeModal()
-  }, [store, selected, memberships, onUpdate])
-
-  const onPressNewMuteList = useCallback(() => {
-    store.shell.openModal({
-      name: 'create-or-edit-mute-list',
-      onSave: (_uri: string) => {
-        listsList.refresh()
-      },
-    })
-  }, [store, listsList])
+  }, [store, selected, memberships, onAdd, onRemove])
 
   const onToggleSelected = useCallback(
     (uri: string) => {
@@ -103,7 +101,7 @@ export const Component = observer(function ListAddRemoveUserImpl({
   )
 
   const renderItem = useCallback(
-    (list: GraphDefs.ListView) => {
+    (list: GraphDefs.ListView, index: number) => {
       const isSelected = selected.includes(list.uri)
       return (
         <Pressable
@@ -111,7 +109,10 @@ export const Component = observer(function ListAddRemoveUserImpl({
           style={[
             styles.listItem,
             pal.border,
-            {opacity: membershipsLoaded ? 1 : 0.5},
+            {
+              opacity: membershipsLoaded ? 1 : 0.5,
+              borderTopWidth: index === 0 ? 0 : 1,
+            },
           ]}
           accessibilityLabel={`${isSelected ? 'Remove from' : 'Add to'} ${
             list.name
@@ -131,7 +132,11 @@ export const Component = observer(function ListAddRemoveUserImpl({
               {sanitizeDisplayName(list.name)}
             </Text>
             <Text type="md" style={[pal.textLight]} numberOfLines={1}>
-              {list.purpose === 'app.bsky.graph.defs#modlist' && 'Mute list'} by{' '}
+              {list.purpose === 'app.bsky.graph.defs#curatelist' &&
+                'User list '}
+              {list.purpose === 'app.bsky.graph.defs#modlist' &&
+                'Moderation list '}
+              by{' '}
               {list.creator.did === store.me.did
                 ? 'you'
                 : sanitizeHandle(list.creator.handle, '@')}
@@ -166,30 +171,19 @@ export const Component = observer(function ListAddRemoveUserImpl({
     ],
   )
 
-  const renderEmptyState = React.useCallback(() => {
-    return (
-      <EmptyStateWithButton
-        icon="users-slash"
-        message="You can subscribe to mute lists to automatically mute all of the users they include. Mute lists are public but your subscription to a mute list is private."
-        buttonLabel="New Mute List"
-        onPress={onPressNewMuteList}
-      />
-    )
-  }, [onPressNewMuteList])
-
   // Only show changes button if there are some items on the list to choose from AND user has made changes in selection
   const canSaveChanges =
     !listsList.isEmpty && !isEqual(selected, originalSelections)
 
   return (
-    <View testID="listAddRemoveUserModal" style={s.hContentRegion}>
-      <Text style={[styles.title, pal.text]}>Add {displayName} to Lists</Text>
+    <View testID="userAddRemoveListsModal" style={s.hContentRegion}>
+      <Text style={[styles.title, pal.text]}>
+        Update {displayName} in Lists
+      </Text>
       <ListsList
         listsList={listsList}
-        showAddBtns
-        onPressCreateNew={onPressNewMuteList}
+        inline
         renderItem={renderItem}
-        renderEmptyState={renderEmptyState}
         style={[styles.list, pal.border]}
       />
       <View style={[styles.btns, pal.border]}>
@@ -258,7 +252,6 @@ const styles = StyleSheet.create({
   listItem: {
     flexDirection: 'row',
     alignItems: 'center',
-    borderTopWidth: 1,
     paddingHorizontal: 14,
     paddingVertical: 10,
   },