diff --git a/_locales/en/messages.json b/_locales/en/messages.json index fc61fa2abc5..3256dc88821 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -5272,6 +5272,30 @@ "message": "next", "description": "Generic next label" }, + "BadgeDialog__become-a-sustainer-button": { + "message": "Become a Sustainer", + "description": "In the badge dialog. This button is shown under sustainer badges, taking users to some instructions" + }, + "BadgeSustainerInstructions__header": { + "message": "Become a Sustainer", + "description": "In the instructions for becoming a sustainer. The heading." + }, + "BadgeSustainerInstructions__subheader": { + "message": "Signal is powered by people like you. Contribute and receive a badge.", + "description": "In the instructions for becoming a sustainer. The subheading." + }, + "BadgeSustainerInstructions__instructions__1": { + "message": "Open Signal on your phone", + "description": "In the instructions for becoming a sustainer. First instruction." + }, + "BadgeSustainerInstructions__instructions__2": { + "message": "Tap on your profile photo in the top left to open Settings", + "description": "In the instructions for becoming a sustainer. Second instruction." + }, + "BadgeSustainerInstructions__instructions__3": { + "message": "Tap on \"Become a Sustainer\" and subscribe", + "description": "In the instructions for becoming a sustainer. Third instruction." + }, "CompositionArea--expand": { "message": "Expand", "description": "Aria label for expanding composition area" diff --git a/images/mobile-settings-dark.svg b/images/mobile-settings-dark.svg new file mode 100644 index 00000000000..20c58c04189 --- /dev/null +++ b/images/mobile-settings-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/mobile-settings-light.svg b/images/mobile-settings-light.svg new file mode 100644 index 00000000000..76ff934d06d --- /dev/null +++ b/images/mobile-settings-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/stylesheets/components/BadgeDialog.scss b/stylesheets/components/BadgeDialog.scss index 3dd7b90dcf3..2d62542fb5c 100644 --- a/stylesheets/components/BadgeDialog.scss +++ b/stylesheets/components/BadgeDialog.scss @@ -14,7 +14,7 @@ max-width: 420px; } - &__body { + &__contents { display: flex; align-items: center; } @@ -110,5 +110,17 @@ &__description { @include font-body-1; @include fixed-height(5.5em); + margin-bottom: 12px; + } + + &__instructions-button { + width: 100%; + &--hidden { + visibility: hidden; + } + } + + .BadgeCarouselIndex { + margin-top: 24px; } } diff --git a/stylesheets/components/BadgeSustainerInstructionsDialog.scss b/stylesheets/components/BadgeSustainerInstructionsDialog.scss new file mode 100644 index 00000000000..11784b1275a --- /dev/null +++ b/stylesheets/components/BadgeSustainerInstructionsDialog.scss @@ -0,0 +1,52 @@ +// Copyright 2021 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +.BadgeSustainerInstructionsDialog { + user-select: none; + + // We use this selector for specificity. + &.module-Modal { + max-width: 420px; + } + + &__header { + @include font-title-2; + text-align: center; + } + + &__subheader { + @include font-body-1; + font-weight: normal; + text-align: center; + } + + &__instructions { + @include font-body-2; + padding: 0; + list-style-position: inside; + + &::before { + background-size: contain; + content: ''; + display: block; + height: 160px; + margin: 24px auto; + width: 146px; + + @include light-theme { + background-image: url('../images/mobile-settings-light.svg'); + } + @include dark-theme { + background-image: url('../images/mobile-settings-dark.svg'); + } + } + + > li { + margin-top: 1em; + + &:first-child { + margin-top: 0; + } + } + } +} diff --git a/stylesheets/components/Button.scss b/stylesheets/components/Button.scss index 76f5dd622a1..96c48f2568d 100644 --- a/stylesheets/components/Button.scss +++ b/stylesheets/components/Button.scss @@ -35,6 +35,11 @@ cursor: not-allowed; } + &--large { + @include font-title-2; + font-weight: bold; + } + &--medium { @include font-body-1-bold; } diff --git a/stylesheets/manifest.scss b/stylesheets/manifest.scss index 78b8e29108a..148b593027f 100644 --- a/stylesheets/manifest.scss +++ b/stylesheets/manifest.scss @@ -34,6 +34,7 @@ @import './components/AvatarTextEditor.scss'; @import './components/BadgeCarouselIndex.scss'; @import './components/BadgeDialog.scss'; +@import './components/BadgeSustainerInstructionsDialog.scss'; @import './components/BetterAvatarBubble.scss'; @import './components/Button.scss'; @import './components/CallingLobby.scss'; diff --git a/ts/components/BadgeDialog.tsx b/ts/components/BadgeDialog.tsx index d09142305db..3ead43b005e 100644 --- a/ts/components/BadgeDialog.tsx +++ b/ts/components/BadgeDialog.tsx @@ -2,14 +2,18 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useEffect, useState } from 'react'; +import classNames from 'classnames'; import { strictAssert } from '../util/assert'; import type { LocalizerType } from '../types/Util'; import type { BadgeType } from '../badges/types'; +import { BadgeCategory } from '../badges/BadgeCategory'; import { Modal } from './Modal'; +import { Button, ButtonSize } from './Button'; import { BadgeDescription } from './BadgeDescription'; import { BadgeImage } from './BadgeImage'; import { BadgeCarouselIndex } from './BadgeCarouselIndex'; +import { BadgeSustainerInstructionsDialog } from './BadgeSustainerInstructionsDialog'; type PropsType = Readonly<{ badges: ReadonlyArray; @@ -20,16 +24,32 @@ type PropsType = Readonly<{ }>; export function BadgeDialog(props: PropsType): null | JSX.Element { - const { badges, onClose } = props; + const { badges, i18n, onClose } = props; + + const [isShowingInstructions, setIsShowingInstructions] = useState(false); const hasBadges = badges.length > 0; useEffect(() => { - if (!hasBadges) { + if (!hasBadges && !isShowingInstructions) { onClose(); } - }, [hasBadges, onClose]); + }, [hasBadges, isShowingInstructions, onClose]); + + if (isShowingInstructions) { + return ( + setIsShowingInstructions(false)} + /> + ); + } - return hasBadges ? : null; + return hasBadges ? ( + setIsShowingInstructions(true)} + /> + ) : null; } function BadgeDialogWithBadges({ @@ -37,8 +57,9 @@ function BadgeDialogWithBadges({ firstName, i18n, onClose, + onShowInstructions, title, -}: PropsType): JSX.Element { +}: PropsType & { onShowInstructions: () => unknown }): JSX.Element { const firstBadge = badges[0]; strictAssert( firstBadge, @@ -75,35 +96,48 @@ function BadgeDialogWithBadges({ i18n={i18n} onClose={onClose} > - + - navigate(1)} + type="button" /> -