Skip to content

Commit

Permalink
feat: new setup that allow user to specify username
Browse files Browse the repository at this point in the history
  • Loading branch information
Jack-Works committed Nov 29, 2019
1 parent 73655c6 commit 815931c
Show file tree
Hide file tree
Showing 12 changed files with 204 additions and 169 deletions.
18 changes: 9 additions & 9 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@
"decrypted_postbox_add_recipients": {
"message": "View / add recipients"
},
"click_to_setup": {
"message": "Click here to setup your Maskbook account!"
},
"decrypted_postbox_verified": {
"message": "Signature verified ✔"
},
Expand Down Expand Up @@ -375,19 +372,22 @@
"message": "Welcome to Maskbook"
},
"banner_preparing_setup": {
"message": "Maskbook is identifying how to setup your account..."
"message": "Maskbook needs your username to set up your account."
},
"banner_get_started": {
"message": "Get started"
"message": "Continue"
},
"banner_empty_username": {
"message": "If not filled automatically, you may fill it."
},
"banner_dismiss_aria": {
"message": "Dismiss the banner"
"banner_invalid_username": {
"message": "This does not seem like a valid username."
},
"service_invalid_backup_file": {
"message": "This does not seems like Maskbook's backup."
"message": "This does not seems like a backup of Maskbook."
},
"service_others_key_not_found": {
"message": "$1's public key not found!"
"message": "Public key of $1 can not be found!"
},
"service_not_setup_yet": {
"message": "You have not set up Maskbook yet!"
Expand Down
14 changes: 7 additions & 7 deletions src/_locales/zh/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@
"decrypted_postbox_add_recipients": {
"message": "查看或添加收件人"
},
"click_to_setup": {
"message": "點此開始配置"
},
"decrypted_postbox_verified": {
"message": "數字簽名驗證成功 ✔"
},
Expand Down Expand Up @@ -376,13 +373,16 @@
"message": "歡迎使用 Maskbook"
},
"banner_preparing_setup": {
"message": "Maskbook 正在準備向導過程……"
"message": "Maskbook 需要你的用戶名來設定你的賬號。"
},
"banner_get_started": {
"message": "開始使用"
"message": "繼續設定 Maskbook"
},
"banner_empty_username": {
"message": "如果自動探測用戶名沒有成功,請手動在此輸入"
},
"banner_dismiss_aria": {
"message": "關閉消息"
"banner_invalid_username": {
"message": "這看起來不像正確的用戶名"
},
"service_invalid_backup_file": {
"message": "這貌似不是 Maskbook 的備份。"
Expand Down
5 changes: 3 additions & 2 deletions src/components/InjectedComponents/AdditionalPostBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import { geti18nString } from '../../utils/i18n'
import { makeStyles } from '@material-ui/styles'
import { Box, Button, Card, CardHeader, Divider, InputBase, Paper, Typography } from '@material-ui/core'
import { Group, Person } from '../../database'
import { NotSetupYetPrompt, NotSetupYetPromptProps } from '../shared/NotSetupYetPrompt'
import { NotSetupYetPrompt } from '../shared/NotSetupYetPrompt'
import { useCurrentIdentity, useFriendsList, useGroupsList, useMyIdentities } from '../DataSource/useActivatedUI'
import { getActivatedUI } from '../../social-network/ui'
import { ChooseIdentity, ChooseIdentityProps } from '../shared/ChooseIdentity'
import { useAsync } from '../../utils/components/AsyncComponent'
import { useStylesExtends, or } from '../custom-ui-helper'
import { steganographyModeSetting } from '../shared-settings/settings'
import { useValueRef } from '../../utils/hooks/useValueRef'
import { BannerProps } from '../Welcomes/Banner'

interface Props {
availableTarget: Array<Person | Group>
Expand Down Expand Up @@ -108,7 +109,7 @@ export interface AdditionalPostBoxProps extends Partial<AdditionalPostBoxUIProps
identities?: Person[]
onRequestPost?: (target: (Person | Group)[], text: string) => void
onRequestReset?: () => void
NotSetupYetPromptProps?: Partial<NotSetupYetPromptProps>
NotSetupYetPromptProps?: Partial<BannerProps>
}

/**
Expand Down
7 changes: 4 additions & 3 deletions src/components/InjectedComponents/DecryptedPost.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { sleep } from '../../utils/utils'
import { ServicesWithProgress } from '../../extension/service'
import { geti18nString } from '../../utils/i18n'
import { makeStyles } from '@material-ui/styles'
import { Box, Link, useMediaQuery, useTheme, Theme } from '@material-ui/core'
import { Box, Link, useMediaQuery, useTheme } from '@material-ui/core'
import { Person } from '../../database'
import { Identifier, PersonIdentifier } from '../../database/type'
import { NotSetupYetPrompt, NotSetupYetPromptProps } from '../shared/NotSetupYetPrompt'
import { NotSetupYetPrompt } from '../shared/NotSetupYetPrompt'
import {
DecryptionProgress,
FailureDecryption,
Expand All @@ -22,6 +22,7 @@ import { GetContext } from '@holoflows/kit/es'
import { deconstructPayload } from '../../utils/type-transform/Payload'
import { DebugList } from '../DebugModeUI/DebugList'
import { useStylesExtends } from '../custom-ui-helper'
import { BannerProps } from '../Welcomes/Banner'

export interface DecryptPostSuccessProps extends withClasses<KeysInferFromUseStyles<typeof useSuccessStyles>> {
data: { signatureVerifyResult: boolean; content: string }
Expand Down Expand Up @@ -102,7 +103,7 @@ export const DecryptPostAwaiting = React.memo(function DecryptPostAwaiting(props
export interface DecryptPostFailedProps {
error: Error
AdditionalContentProps?: Partial<AdditionalContentProps>
NotSetupYetPromptProps?: Partial<NotSetupYetPromptProps>
NotSetupYetPromptProps?: Partial<BannerProps>
}
export const DecryptPostFailed = React.memo(function DecryptPostFailed({ error, ...props }: DecryptPostFailedProps) {
if (error && error.message === geti18nString('service_not_setup_yet')) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/MobileImportExport/Export.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function ExportData() {
if (id.length === 0) {
return (
<main className={classes.root}>
<NotSetupYetPrompt />
<NotSetupYetPrompt username="hidden" close="hidden" />
</main>
)
}
Expand Down
181 changes: 129 additions & 52 deletions src/components/Welcomes/Banner.tsx
Original file line number Diff line number Diff line change
@@ -1,95 +1,172 @@
import * as React from 'react'
import { useCallback } from 'react'
import CloseIcon from '@material-ui/icons/Close'
import { geti18nString } from '../../utils/i18n'
import { makeStyles } from '@material-ui/styles'
import { AppBar, Button, Hidden, IconButton, SnackbarContent, Theme, Typography } from '@material-ui/core'
import {
AppBar,
Button,
Theme,
TextField,
InputAdornment,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions,
} from '@material-ui/core'
import { useLastRecognizedIdentity } from '../DataSource/useActivatedUI'
import Services from '../../extension/service'
import { getActivatedUI, SocialNetworkUI } from '../../social-network/ui'
import { env } from '../../social-network/shared'
import { setStorage } from '../../utils/browser.storage'
import { useStylesExtends } from '../custom-ui-helper'
import { useCapturedInput } from '../../utils/hooks/useCapturedEvents'
import { PersonIdentifier } from '../../database/type'

interface Props {
getStarted(): void
close(): void
disabled?: boolean
interface Props extends withClasses<KeysInferFromUseStyles<typeof useStyles>> {
nextStep: { onClick(): void }
close: 'hidden' | { onClose(): void }
title?: string
description?: string
username:
| 'hidden'
| {
isValid(username: string): boolean
value: string
defaultValue: string
onChange(nextValue: string): void
}
}
const useStyles = makeStyles<Theme>(theme => ({
const useStyles = makeStyles((theme: Theme) => ({
root: {
border: '1px solid #ccc',
borderRadius: 4,
marginBottom: 10,
},
snackbar: {
backgroundColor: theme.palette.background.default,
color: theme.palette.text.primary,
boxShadow: 'none',
},
button: {
padding: '4px 3em',
},
close: {
margin: 6,
padding: 6,
title: {
paddingBottom: 0,
},
}))
export function BannerUI(props: Props) {
const classes = useStyles()
const Title = (
<Typography variant="subtitle1" color="inherit">
{props.disabled ? geti18nString('banner_preparing_setup') : geti18nString('banner_title')}
</Typography>
const classes = useStylesExtends(useStyles(), props)

const Title = props.title ?? geti18nString('banner_title')
const Description = props.description ?? geti18nString('banner_preparing_setup')

const emptyUsernameHelperText = geti18nString('banner_empty_username')
const invalidUsernameHelperText = geti18nString('banner_invalid_username')

const { username } = props

const [touched, isTouched] = React.useState(false)
const usedValue = username === 'hidden' ? '' : touched ? username.value : username.defaultValue
const isInvalid = username === 'hidden' ? false : touched ? !username.isValid(usedValue) : false
const helperText =
username === 'hidden'
? ''
: isInvalid
? (username.value + username.defaultValue).length
? invalidUsernameHelperText
: emptyUsernameHelperText
: ' '
const ref = React.useRef<HTMLInputElement>()
useCapturedInput(
ref,
e => {
if (username === 'hidden') return
isTouched(true)
username.onChange(e)
},
[username],
)
const UserNameInput =
username === 'hidden' ? null : (
<TextField
label="Username"
onChange={() => {}}
value={usedValue}
error={isInvalid}
helperText={helperText}
fullWidth
InputProps={{
startAdornment: <InputAdornment position="start">@</InputAdornment>,
inputRef: ref,
}}
margin="dense"
variant="standard"
/>
)
const GetStarted = (
<Button
onClick={props.getStarted}
classes={{ root: classes.button }}
disabled={username === 'hidden' ? false : !username.isValid(usedValue)}
onClick={props.nextStep.onClick}
variant="contained"
disabled={props.disabled}
color="primary">
{geti18nString('banner_get_started')}
</Button>
)
const DismissIcon = (
<IconButton
aria-label={geti18nString('banner_dismiss_aria')}
onClick={props.close}
classes={{ root: classes.close }}>
<CloseIcon />
</IconButton>
)
const DismissButton =
props.close !== 'hidden' ? (
<Button onClick={props.close.onClose} color="primary">
{geti18nString('cancel')}
</Button>
) : null
return (
<AppBar position="static" color="default" elevation={0} classes={{ root: classes.root }}>
<SnackbarContent
classes={{ root: classes.snackbar }}
message={Title}
action={
<>
{GetStarted}
<Hidden smDown>{DismissIcon}</Hidden>
</>
}
/>
<AppBar position="static" color="inherit" elevation={0} classes={{ root: classes.root }}>
<DialogTitle classes={{ root: classes.title }}>{Title}</DialogTitle>
<DialogContent>
<DialogContentText>{Description}</DialogContentText>
{UserNameInput}
</DialogContent>
<DialogActions>
{DismissButton}
{GetStarted}
</DialogActions>
</AppBar>
)
}

export function Banner(props: { networkIdentifier: SocialNetworkUI['networkIdentifier'] } & Partial<Props>) {
type networkIdentifier = { networkIdentifier: SocialNetworkUI['networkIdentifier'] }
export type BannerProps = Partial<Props> &
Partial<networkIdentifier> &
(networkIdentifier | Required<Pick<Props, 'nextStep'>>)
export function Banner(props: BannerProps) {
const lastRecognizedIdentity = useLastRecognizedIdentity()
const closeDefault = useCallback(() => {
getActivatedUI().ignoreSetupAccount(env, {})
}, [])
const getStartedDefault = useCallback(() => {
const [value, onChange] = React.useState('')
const getStartDefault = useCallback(() => {
if (!props.networkIdentifier)
return (
props.nextStep?.onClick() ??
(() => console.warn('You must provide one of networkIdentifier or nextStep.onClick'))
)
setStorage(props.networkIdentifier, { forceDisplayWelcome: false })
Services.Welcome.openWelcomePage(lastRecognizedIdentity)
}, [lastRecognizedIdentity, props.networkIdentifier])
const id = { ...lastRecognizedIdentity }
id.identifier =
value === '' ? lastRecognizedIdentity.identifier : new PersonIdentifier(props.networkIdentifier, value)
Services.Welcome.openWelcomePage(id)
}, [lastRecognizedIdentity, props.networkIdentifier, props.nextStep, value])

return (
<BannerUI
disabled={lastRecognizedIdentity.identifier.isUnknown}
close={closeDefault}
getStarted={getStartedDefault}
{...props}
username={
props.username ?? {
defaultValue: lastRecognizedIdentity.identifier.isUnknown
? ''
: lastRecognizedIdentity.identifier.userId,
value,
onChange,
isValid: getActivatedUI().isValidUsername,
}
}
close={props.close ?? { onClose: closeDefault }}
nextStep={
props.nextStep ?? {
onClick: getStartDefault,
}
}
/>
)
}
Loading

0 comments on commit 815931c

Please sign in to comment.