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/Modal.tsx4
-rw-r--r--src/view/com/modals/Modal.web.tsx3
-rw-r--r--src/view/com/modals/ModerationDetails.tsx8
-rw-r--r--src/view/com/modals/SelfLabel.tsx167
4 files changed, 178 insertions, 4 deletions
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index 469492971..ce5dc40e0 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -15,6 +15,7 @@ import * as ProfilePreviewModal from './ProfilePreview'
 import * as ServerInputModal from './ServerInput'
 import * as ReportPostModal from './report/ReportPost'
 import * as RepostModal from './Repost'
+import * as SelfLabelModal from './SelfLabel'
 import * as CreateOrEditMuteListModal from './CreateOrEditMuteList'
 import * as ListAddRemoveUserModal from './ListAddRemoveUser'
 import * as AltImageModal from './AltImage'
@@ -104,6 +105,9 @@ export const ModalsContainer = observer(function ModalsContainer() {
   } else if (activeModal?.name === 'repost') {
     snapPoints = RepostModal.snapPoints
     element = <RepostModal.Component {...activeModal} />
+  } else if (activeModal?.name === 'self-label') {
+    snapPoints = SelfLabelModal.snapPoints
+    element = <SelfLabelModal.Component {...activeModal} />
   } else if (activeModal?.name === 'alt-text-image') {
     snapPoints = AltImageModal.snapPoints
     element = <AltImageModal.Component {...activeModal} />
diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx
index df13dfed2..0f6247822 100644
--- a/src/view/com/modals/Modal.web.tsx
+++ b/src/view/com/modals/Modal.web.tsx
@@ -16,6 +16,7 @@ import * as CreateOrEditMuteListModal from './CreateOrEditMuteList'
 import * as ListAddRemoveUserModal from './ListAddRemoveUser'
 import * as DeleteAccountModal from './DeleteAccount'
 import * as RepostModal from './Repost'
+import * as SelfLabelModal from './SelfLabel'
 import * as CropImageModal from './crop-image/CropImage.web'
 import * as AltTextImageModal from './AltImage'
 import * as EditImageModal from './EditImage'
@@ -89,6 +90,8 @@ function Modal({modal}: {modal: ModalIface}) {
     element = <DeleteAccountModal.Component />
   } else if (modal.name === 'repost') {
     element = <RepostModal.Component {...modal} />
+  } else if (modal.name === 'self-label') {
+    element = <SelfLabelModal.Component {...modal} />
   } else if (modal.name === 'change-handle') {
     element = <ChangeHandleModal.Component {...modal} />
   } else if (modal.name === 'waitlist') {
diff --git a/src/view/com/modals/ModerationDetails.tsx b/src/view/com/modals/ModerationDetails.tsx
index abeb2fdf4..598d26924 100644
--- a/src/view/com/modals/ModerationDetails.tsx
+++ b/src/view/com/modals/ModerationDetails.tsx
@@ -35,10 +35,7 @@ export function Component({
     name = 'Account Blocks You'
     description = 'This user has blocked you. You cannot view their content.'
   } else if (moderation.cause.type === 'muted') {
-    if (moderation.cause.source.type === 'user') {
-      name = 'Account Muted'
-      description = 'You have muted this user.'
-    } else {
+    if (moderation.cause.source.type === 'list') {
       const list = moderation.cause.source.list
       name = <>Account Muted by List</>
       description = (
@@ -53,6 +50,9 @@ export function Component({
           list which you have muted.
         </>
       )
+    } else {
+      name = 'Account Muted'
+      description = 'You have muted this user.'
     }
   } else {
     name = moderation.cause.labelDef.strings[context].en.name
diff --git a/src/view/com/modals/SelfLabel.tsx b/src/view/com/modals/SelfLabel.tsx
new file mode 100644
index 000000000..cb78f3f15
--- /dev/null
+++ b/src/view/com/modals/SelfLabel.tsx
@@ -0,0 +1,167 @@
+import React, {useState} from 'react'
+import {StyleSheet, TouchableOpacity, View} from 'react-native'
+import {observer} from 'mobx-react-lite'
+import {Text} from '../util/text/Text'
+import {useStores} from 'state/index'
+import {s, colors} from 'lib/styles'
+import {usePalette} from 'lib/hooks/usePalette'
+import {isDesktopWeb} from 'platform/detection'
+import {SelectableBtn} from '../util/forms/SelectableBtn'
+import {ScrollView} from 'view/com/modals/util'
+
+const ADULT_CONTENT_LABELS = ['sexual', 'nudity', 'porn']
+
+export const snapPoints = ['50%']
+
+export const Component = observer(function Component({
+  labels,
+  onChange,
+}: {
+  labels: string[]
+  onChange: (labels: string[]) => void
+}) {
+  const pal = usePalette('default')
+  const store = useStores()
+  const [selected, setSelected] = useState(labels)
+
+  const toggleAdultContent = (label: string) => {
+    const hadLabel = selected.includes(label)
+    const stripped = selected.filter(l => !ADULT_CONTENT_LABELS.includes(l))
+    const final = !hadLabel ? stripped.concat([label]) : stripped
+    setSelected(final)
+    onChange(final)
+  }
+
+  return (
+    <View testID="selfLabelModal" style={[pal.view, styles.container]}>
+      <View style={styles.titleSection}>
+        <Text type="title-lg" style={[pal.text, styles.title]}>
+          Add a content warning
+        </Text>
+      </View>
+
+      <ScrollView>
+        <View style={[styles.section, pal.border, {borderBottomWidth: 1}]}>
+          <View
+            style={{
+              flexDirection: 'row',
+              alignItems: 'center',
+              justifyContent: 'space-between',
+              paddingBottom: 8,
+            }}>
+            <Text type="title" style={pal.text}>
+              Adult Content
+            </Text>
+
+            <Text type="lg" style={pal.text}>
+              {selected.includes('sexual') ? (
+                <>😏</>
+              ) : selected.includes('nudity') ? (
+                <>🫣</>
+              ) : selected.includes('porn') ? (
+                <>🥵</>
+              ) : (
+                <></>
+              )}
+            </Text>
+          </View>
+          <View style={s.flexRow}>
+            <SelectableBtn
+              testID="sexualLabelBtn"
+              selected={selected.includes('sexual')}
+              left
+              label="Suggestive"
+              onSelect={() => toggleAdultContent('sexual')}
+              accessibilityHint=""
+              style={s.flex1}
+            />
+            <SelectableBtn
+              testID="nudityLabelBtn"
+              selected={selected.includes('nudity')}
+              label="Nudity"
+              onSelect={() => toggleAdultContent('nudity')}
+              accessibilityHint=""
+              style={s.flex1}
+            />
+            <SelectableBtn
+              testID="pornLabelBtn"
+              selected={selected.includes('porn')}
+              label="Porn"
+              right
+              onSelect={() => toggleAdultContent('porn')}
+              accessibilityHint=""
+              style={s.flex1}
+            />
+          </View>
+
+          <Text style={[pal.text, styles.adultExplainer]}>
+            {selected.includes('sexual') ? (
+              <>Pictures meant for adults.</>
+            ) : selected.includes('nudity') ? (
+              <>Artistic or non-erotic nudity.</>
+            ) : selected.includes('porn') ? (
+              <>Sexual activity or erotic nudity.</>
+            ) : (
+              <>If none are selected, suitable for all ages.</>
+            )}
+          </Text>
+        </View>
+      </ScrollView>
+
+      <View style={[styles.btnContainer, pal.borderDark]}>
+        <TouchableOpacity
+          testID="confirmBtn"
+          onPress={() => {
+            store.shell.closeModal()
+          }}
+          style={styles.btn}
+          accessibilityRole="button"
+          accessibilityLabel="Confirm"
+          accessibilityHint="">
+          <Text style={[s.white, s.bold, s.f18]}>Done</Text>
+        </TouchableOpacity>
+      </View>
+    </View>
+  )
+})
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    paddingBottom: isDesktopWeb ? 0 : 40,
+  },
+  titleSection: {
+    paddingTop: isDesktopWeb ? 0 : 4,
+    paddingBottom: isDesktopWeb ? 14 : 10,
+  },
+  title: {
+    textAlign: 'center',
+    fontWeight: '600',
+    marginBottom: 5,
+  },
+  description: {
+    textAlign: 'center',
+    paddingHorizontal: 32,
+  },
+  section: {
+    borderTopWidth: 1,
+    paddingVertical: 20,
+    paddingHorizontal: isDesktopWeb ? 0 : 20,
+  },
+  adultExplainer: {
+    paddingLeft: 5,
+    paddingTop: 10,
+  },
+  btn: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'center',
+    borderRadius: 32,
+    padding: 14,
+    backgroundColor: colors.blue3,
+  },
+  btnContainer: {
+    paddingTop: 20,
+    paddingHorizontal: 20,
+  },
+})