Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New "Instant Onboarding" UX flow to create accounts #3773

Merged
merged 86 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
52e1bd7
Separate components in welcome screen
adzialocha Apr 15, 2024
1e0a6ed
Separate Props
adzialocha Apr 15, 2024
65b8921
Separate alternative setup methods into external dialog
adzialocha Apr 15, 2024
51c5f66
Introduce new screen to create account in next step
adzialocha Apr 15, 2024
48cc504
Make color and address optional for image selector
adzialocha Apr 15, 2024
b324067
Add display name and profile image selector
adzialocha Apr 15, 2024
4cdcb5c
Create random account via chatmail
adzialocha Apr 15, 2024
513da4a
Use scan QR flow
adzialocha Apr 15, 2024
c06e534
Clean up a little
adzialocha Apr 15, 2024
3a12d3a
Make setting credentials optional
adzialocha Apr 15, 2024
63c519c
Add some comments
adzialocha Apr 15, 2024
ef0a3db
Configure image and name after configure got called
adzialocha Apr 15, 2024
fe2d46c
Rename to InstantAccountScreen
adzialocha Apr 15, 2024
a6a7de3
Introduce context and hook to organise instant onboarding state
adzialocha Apr 15, 2024
d69b8e1
Integrate new instant onboarding flow in process QR hook
adzialocha Apr 15, 2024
f802f45
Remove unused askForName state
adzialocha Apr 15, 2024
863acd9
Use new instant onboarding context
adzialocha Apr 15, 2024
bf42af1
Refactor welcome screen to use instant onboarding hook
adzialocha Apr 15, 2024
3c5efb7
Improve image selector styles
adzialocha Apr 15, 2024
edc2776
Bring back confirmation dialog
adzialocha Apr 15, 2024
05af52d
Allow secure join with instant onboarding
adzialocha Apr 15, 2024
db2bf1c
Fix hook paths
adzialocha Apr 18, 2024
de03246
Ask for confirmation in secure join flows before creating account
adzialocha Apr 18, 2024
da863dd
Move redirects into component
adzialocha Apr 18, 2024
f0ea599
Basic styling
adzialocha Apr 18, 2024
32fafb4
Remove unused type
adzialocha Apr 18, 2024
204ef82
Bring back loading settings store, otherwise composer breaks
adzialocha Apr 18, 2024
22203fc
Fix styling issues
adzialocha Apr 18, 2024
40ca56c
Give more info instant onboarding screen
adzialocha Apr 18, 2024
753a9ac
Minor color change
adzialocha Apr 18, 2024
ea88552
Always show info where account will be created
adzialocha Apr 19, 2024
05315e2
Prepare all translation strings
adzialocha Apr 19, 2024
98c83c4
Fix disabled button style
adzialocha Apr 19, 2024
482a346
Disable button when display name is not set
adzialocha Apr 19, 2024
9c2050e
Add help icon
adzialocha Apr 19, 2024
f84537d
Show an icon as default for image selector
adzialocha Apr 19, 2024
f308c37
Show secure join info separated from the instance info
adzialocha Apr 22, 2024
081135c
Update translation strings
adzialocha Apr 22, 2024
6ced33d
Bring back login flow
adzialocha Apr 22, 2024
292be7d
Improve button styling
adzialocha Apr 22, 2024
2361b71
Better person icon for large profile image default
adzialocha Apr 22, 2024
8e2e992
Improve help icon position
adzialocha Apr 22, 2024
8faf81c
Alternative login dialog styling
adzialocha Apr 22, 2024
11ce5d0
Use layout effect to prevent flicker
adzialocha Apr 22, 2024
185bef5
Move state to parent to prevent more flicker
adzialocha Apr 22, 2024
b108cff
Do not show instances link when using secure join QR
adzialocha Apr 22, 2024
4f1f009
Clean up a little bit
adzialocha Apr 22, 2024
3ffb91f
Remove unused file
adzialocha Apr 22, 2024
992afe5
Add entry to CHANGELOG.md
adzialocha Apr 22, 2024
eb23dc2
Fix default back button state
adzialocha Apr 22, 2024
8367be8
Adjust translation strings
adzialocha Apr 22, 2024
690fa36
Fix after rebase
adzialocha Apr 23, 2024
a810704
QR code will always be set
adzialocha Apr 23, 2024
2cc7b68
Clean up and add more comments to QR scanning flows
adzialocha Apr 23, 2024
1564429
Fix path
adzialocha Apr 23, 2024
ad279b9
Update comments
adzialocha Apr 23, 2024
2a638cf
Rename to InstantOnboardingScreen
adzialocha Apr 24, 2024
5c972a8
Add user agreement checkbox, move QR scan button
adzialocha Apr 24, 2024
2097482
Put QR scan button in dialog headers
adzialocha Apr 24, 2024
723630e
Make linter happy
adzialocha Apr 24, 2024
edade0e
Use random link for now
adzialocha Apr 24, 2024
067930e
Remove QR scan button from header
adzialocha Apr 24, 2024
fa4854c
Use switch instead of checkbox
adzialocha Apr 24, 2024
a8ea1fd
Remove help button
adzialocha Apr 24, 2024
d9019a7
Add https to chatmail links
adzialocha Apr 24, 2024
2309ab5
Correct link
adzialocha Apr 24, 2024
fbc560c
Clean up, better footer styling
adzialocha Apr 24, 2024
f4357e9
More space between footer and login
adzialocha Apr 24, 2024
fd1c456
Update translation strings
adzialocha Apr 24, 2024
f2051f8
Remove switch and use only links instead to privacy policy
adzialocha Apr 24, 2024
3362888
remove gmail, outloook etc. from welcome screen's intro1.png
r10s Apr 24, 2024
0b0c1f6
privacy url
Simon-Laux Apr 26, 2024
30d43e3
fix error handling
Simon-Laux Apr 26, 2024
a37996a
use `ImageBackdrop` also for `AccountDeletionScreen`
Simon-Laux Apr 26, 2024
4f2cffb
Clean up const variables
adzialocha Apr 29, 2024
4d4878d
Set profile image and display name before calling configure
adzialocha Apr 29, 2024
983386a
Check if accounts are configured
adzialocha Apr 29, 2024
35c35f5
Restore former DCLOGIN flow
adzialocha Apr 29, 2024
ece0a39
Check for logged in state here as well
adzialocha Apr 29, 2024
efe5456
Make sure to log user out before processing DCLOGIN
adzialocha Apr 30, 2024
e63fa49
Better variable naming
adzialocha Apr 30, 2024
3bf84ba
Specialize type for welcome qr
adzialocha Apr 30, 2024
e51657a
Safer typechecking of qr code kinds
adzialocha Apr 30, 2024
be0c1a6
add exhaustively check
Simon-Laux Apr 30, 2024
781e121
rename `switchToInstantOnboarding` to `startInstantOnboardingFlow`
Simon-Laux Apr 30, 2024
6919869
clarify `showInstantOnboarding` comment
Simon-Laux Apr 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- add quick key `Cmd+W`/`Ctrl+W` to close webxdc-, html_email- and help-window #3770 #3778
- Accept images from clipboard in QR reader #3762
- Introduce new `Spinner` component #3786
- Instant Onboarding #3773

### Changed
- Update translations (2024-04-04) #3746
Expand Down
36 changes: 36 additions & 0 deletions _locales/_untranslated_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,41 @@
},
"camera_access_failed": {
"message": "Could not access video camera. You might want to check your video permissions or if the camera is used already by another program"
},
"onboarding_create_instant_account": {
"message": "Let's Get Started!"
},
"onboarding_alternative_logins": {
"message": "I Already Have a Login"
},
"manual_account_setup_option": {
"message": "Manual Login"
},
"instant_onboarding_title": {
"message": "Your Profile"
},
"instant_onboarding_agree_default": {
"message": "Read the Privacy Policy"
},
"instant_onboarding_agree_instance": {
"message": "About profiles on %1$s"
},
"instant_onboarding_create": {
"message": "Agree & Create Profile"
},
"instant_onboarding_show_more_instances": {
"message": "Explore Other Options"
},
"instant_onboarding_group_info": {
"message": "Create a profile to join the group \"%1$s\"."
},
"instant_onboarding_contact_info": {
"message": "Create a profile to chat with %1$s."
},
"instant_onboarding_confirm_contact": {
"message": "Do you want to create a new DeltaChat profile and start chatting with %1?"
},
"instant_onboarding_confirm_group": {
"message": "Do you want to create a new DeltaChat profile and join the \"%1\" chat group?"
}
}
1 change: 1 addition & 0 deletions images/icons/person-filled.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/intro1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 0 additions & 80 deletions scss/login/_login.scss
Original file line number Diff line number Diff line change
Expand Up @@ -70,55 +70,6 @@
}
}

.login-screen {
flex-grow: 1;
li.login-item {
display: flex;
justify-content: space-between;

&:hover {
button.bp4-intent-danger {
display: inline-flex;
}
}

button.bp4-intent-danger {
display: none;
}

button.bp4-large {
width: 90%;
}
}

.window {
background-size: cover;
background-image: url('../images/backgrounds/petito-moreno.webp');
height: 100vh;
margin-top: 0px;
}

div.delta-blue-button {
-webkit-appearance: button-bevel;
background-color: transparent;
color: var(--loginButtonText);
font-size: 16px;
display: block;
width: 100%;
margin-top: 30px;
&:hover {
cursor: pointer;
}
p {
display: -webkit-inline-box;
position: relative;
font-size: 18px;
margin-bottom: 0px;
bottom: 3px;
}
}
}

div.delta-form-group {
div.label {
height: 13px;
Expand Down Expand Up @@ -228,34 +179,3 @@ div.delta-form-group {
}
}
}

.welcome-deltachat {
display: flex;
justify-content: center;
flex-direction: column;
text-align: center;
align-items: center;

.delta-icon {
width: 90%;
margin: 0 auto;
height: auto;
@media (max-height: 700px) {
display: none;
}
}

.f1 {
margin-top: 40px;
margin-bottom: 30px;
font-size: x-large;
color: var(--colorNone);
}

.f2 {
margin-top: 10px;
padding: 0px 20px;
color: var(--colorNone);
font-size: larger;
}
}
57 changes: 30 additions & 27 deletions src/renderer/ScreenController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import AccountDeletionScreen from './components/screens/AccountDeletionScreen/Ac
import RuntimeAdapter from './components/RuntimeAdapter'
import { ChatProvider } from './contexts/ChatContext'
import { ContextMenuProvider } from './contexts/ContextMenuContext'
import { InstantOnboardingProvider } from './contexts/InstantOnboardingContext'

const log = getLogger('renderer/ScreenController')

Expand Down Expand Up @@ -290,33 +291,35 @@ export default class ScreenController extends Component {
screen: this.state.screen,
}}
>
{/*
The key attribute here forces a clean re-rendering when the
account changes. We needs this to reset the chat context state.
*/}
<ChatProvider
key={this.selectedAccountId}
accountId={this.selectedAccountId}
>
<ContextMenuProvider>
<DialogContextProvider>
<RuntimeAdapter accountId={this.selectedAccountId} />
<KeybindingsContextProvider>
<div className='main-container'>
<AccountListSidebar
selectedAccountId={this.selectedAccountId}
onAddAccount={this.addAndSelectAccount.bind(this)}
onSelectAccount={this.selectAccount.bind(this)}
openAccountDeletionScreen={this.openAccountDeletionScreen.bind(
this
)}
/>
{this.renderScreen()}
</div>
</KeybindingsContextProvider>
</DialogContextProvider>
</ContextMenuProvider>
</ChatProvider>
<InstantOnboardingProvider>
{/*
The key attribute here forces a clean re-rendering when the
account changes. We needs this to reset the chat context state.
*/}
<ChatProvider
key={this.selectedAccountId}
accountId={this.selectedAccountId}
>
<ContextMenuProvider>
<DialogContextProvider>
<RuntimeAdapter accountId={this.selectedAccountId} />
<KeybindingsContextProvider>
<div className='main-container'>
<AccountListSidebar
selectedAccountId={this.selectedAccountId}
onAddAccount={this.addAndSelectAccount.bind(this)}
onSelectAccount={this.selectAccount.bind(this)}
openAccountDeletionScreen={this.openAccountDeletionScreen.bind(
this
)}
/>
{this.renderScreen()}
</div>
</KeybindingsContextProvider>
</DialogContextProvider>
</ContextMenuProvider>
</ChatProvider>
</InstantOnboardingProvider>
</ScreenContext.Provider>
</div>
)
Expand Down
15 changes: 15 additions & 0 deletions src/renderer/backend/account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { BackendRemote } from '../backend-com'

import type { T } from '@deltachat/jsonrpc-client'

export async function getConfiguredAccounts(): Promise<T.Account[]> {
const accounts = await BackendRemote.rpc.getAllAccounts()
return accounts.filter(account => {
return account.kind === 'Configured'
})
}

export async function isAccountConfigured(accountId: number): Promise<boolean> {
const account = await BackendRemote.rpc.getAccountInfo(accountId)
return account.kind === 'Configured'
}
40 changes: 40 additions & 0 deletions src/renderer/backend/qr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { BackendRemote } from '../backend-com'

import type { T } from '@deltachat/jsonrpc-client'

export type AccountQr = Extract<T.Qr, { kind: 'account' }>

export type VerifyContactQr = Extract<T.Qr, { kind: 'askVerifyContact' }>

export type VerifyGroupQr = Extract<T.Qr, { kind: 'askVerifyGroup' }>

export type LoginQr = Extract<T.Qr, { kind: 'login' }>

export type QrWithUrl<Q = T.Qr> = {
qr: Q
url: string
}

/**
* Processes an unchecked string which was scanned from a QR code and returns
* a parsed result when it was valid, throws an error if string is invalid.
*
* See list of supported DeltaChat URI-schemes here:
* - https://github.com/deltachat/interface/blob/master/uri-schemes.md
* - https://c.delta.chat/classdc__context__t.html#a34a865a52127ed2cc8c2f016f085086c
*/
export async function processQr(
accountId: number,
url: string
): Promise<QrWithUrl> {
const qr = await BackendRemote.rpc.checkQr(accountId, url)

if (!qr) {
throw new Error('Could not parse string')
}

return {
qr,
url,
}
}
2 changes: 1 addition & 1 deletion src/renderer/components/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function QRAvatar() {
export function avatarInitial(name: string, addr?: string) {
const nameOrAddr = name || addr
const codepoint = nameOrAddr && nameOrAddr.codePointAt(0)
return codepoint ? String.fromCodePoint(codepoint).toUpperCase() : '#'
return codepoint ? String.fromCodePoint(codepoint).toUpperCase() : ''
}

type htmlDivProps = React.HTMLAttributes<HTMLDivElement>
Expand Down
38 changes: 15 additions & 23 deletions src/renderer/components/Button/style.module.scss
Original file line number Diff line number Diff line change
@@ -1,47 +1,39 @@
.button {
align-items: center;
background-color: transparent;
border-radius: 5px;
border-radius: 10px;
border: 0;
color: var(--colorPrimary);
color: var(--buttonText);
cursor: pointer;
display: flex;
font-size: 16px;
font-weight: bold;
justify-content: center;
padding: 10px 15px;
padding: 12px 15px;
text-align: center;
text-transform: uppercase;

&:hover {
background-color: var(--chatListItemBgHover);
}

&:disabled {
background-color: rgba(206, 217, 224, 0.5);
border-color: rgba(206, 217, 224, 0.5);
color: var(--globalText);
cursor: not-allowed;

&:hover {
background-color: rgba(206, 217, 224, 0.5);
}
background-color: var(--buttonHover);
}

&.primary {
background-color: var(--bp4-input-focused);
color: white;
background-color: var(--buttonPrimaryBackground);
color: var(--buttonPrimaryText);
}

&.secondary {
background-color: var(--bp4ButtonBg);
border-color: var(--bp4ButtonText);
border-style: solid;
border-width: 1.5px;
color: var(--bp4ButtonText);
background-color: var(--buttonSecondaryBackground);
color: var(--buttonSecondaryText);
}

&.danger {
color: var(--colorDanger);
color: var(--buttonDangerText);
}

&:disabled {
background-color: var(--buttonDisabledBackground);
color: var(--buttonDisabledText);
cursor: not-allowed;
}
}
12 changes: 10 additions & 2 deletions src/renderer/components/Callout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import React from 'react'
import classNames from 'classnames'

import type { PropsWithChildren } from 'react'

import styles from './styles.module.scss'

export default function Callout({ children }: PropsWithChildren<{}>) {
return <div className={styles.callout}>{children}</div>
type Props = {
className?: string
}

export default function Callout({
children,
className,
}: PropsWithChildren<Props>) {
return <div className={classNames(styles.callout, className)}>{children}</div>
}
1 change: 1 addition & 0 deletions src/renderer/components/Icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type IconName =
| 'more'
| 'open_in_new'
| 'person'
| 'person-filled'
| 'qr'
| 'question_mark'
| 'reaction'
Expand Down
21 changes: 21 additions & 0 deletions src/renderer/components/ImageBackdrop/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react'
import classNames from 'classnames'

import type { PropsWithChildren } from 'react'

import styles from './styles.module.scss'

type Props = {
variant: 'welcome' | 'deletion'
}

export default function ImageBackdrop({
children,
variant = 'welcome',
}: PropsWithChildren<Props>) {
return (
<div className={classNames(styles.imageBackdrop, styles[variant])}>
{children}
</div>
)
}
Loading
Loading