Skip to content

Commit

Permalink
follow up pr to instant onboarding & add as second device scanner imp…
Browse files Browse the repository at this point in the history
…rovements (#3801)

* refactor a bit to fix dc login
also fixes opening chat after secure join

* fix lint

* update changelog

* fix login with default instance

* custom dialog for setup second device (add steps)

to address #3178

* fix fmt and changelog entry

* add troublehooting button

* fix lint

* fix import name issue

* fix test

* change how the add as second device steps are shown and go back to multiclient anchor

* fix help not opening for languages that have no localised help

closes #3803

* Update CHANGELOG.md

Co-authored-by: bjoern <r10s@b44t.com>

* Update src/renderer/hooks/useInstantOnboarding.ts

Co-authored-by: bjoern <r10s@b44t.com>

---------

Co-authored-by: bjoern <r10s@b44t.com>
  • Loading branch information
Simon-Laux and r10s committed May 2, 2024
1 parent 7689c48 commit 69f3a76
Show file tree
Hide file tree
Showing 19 changed files with 303 additions and 267 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
- 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
- Instant Onboarding #3773 #3801
- Add instructions and troubleshooting button to "Add as Second Device" dialog #3801

### Changed
- Update translations (2024-05-01) #3746 #3802
Expand Down Expand Up @@ -38,6 +39,7 @@
- Close reactions bar on emoji selection #3788
- fix Clicking notification does not bring Delta Chat to foreground on Windows #3793
- Prevent re-rendering of account sidebar when switching account #3789
- fix help not opening for languages that have no localized help

### Removed
- remove disabled composer reason, now composer is just always hidden when `chat.canSend` is `false` #3791
Expand Down
18 changes: 9 additions & 9 deletions src/main/windows/help.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { app as rawApp, BrowserWindow, Menu, shell } from 'electron'
import { BrowserWindow, Menu, shell } from 'electron'
import { appIcon, htmlDistDir } from '../application-constants'
import { getLogger } from '../../shared/logger'
import { ExtendedAppMainProcess } from '../types'
import { join } from 'path'
import { stat } from 'fs/promises'
import { platform } from 'os'
Expand All @@ -16,15 +15,16 @@ import {
} from '../menu'

const log = getLogger('main/help')
const app = rawApp as ExtendedAppMainProcess

async function getHelpFileForLang(locale: string) {
const appPath = app.getAppPath()

const contentFilePath = join(appPath, `/html-dist/help/${locale}/help.html`)
if ((await stat(contentFilePath)).isFile()) {
return join(htmlDistDir(), `help/${locale}/help.html`)
} else {
const contentFilePath = join(htmlDistDir(), `help/${locale}/help.html`)
try {
if (!(await stat(join(contentFilePath))).isFile()) {
log.warn('contentFilePath not a file')
throw new Error('contentFilePath not a file')
}
return contentFilePath
} catch (error) {
log.warn(
`Did not find help file for language ${locale}, falling back to english`
)
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/ScreenController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export default class ScreenController extends Component {
this.userFeedback = this.userFeedback.bind(this)
this.userFeedbackClick = this.userFeedbackClick.bind(this)
this.changeScreen = this.changeScreen.bind(this)
this.addAndSelectAccount = this.addAndSelectAccount.bind(this)
this.selectAccount = this.selectAccount.bind(this)
this.unSelectAccount = this.unSelectAccount.bind(this)
this.openAccountDeletionScreen = this.openAccountDeletionScreen.bind(this)
Expand Down Expand Up @@ -296,6 +297,7 @@ export default class ScreenController extends Component {
userFeedback: this.userFeedback,
changeScreen: this.changeScreen,
screen: this.state.screen,
addAndSelectAccount: this.addAndSelectAccount,
}}
>
<InstantOnboardingProvider>
Expand All @@ -310,7 +312,7 @@ export default class ScreenController extends Component {
<div className='main-container'>
<AccountListSidebar
selectedAccountId={this.selectedAccountId}
onAddAccount={this.addAndSelectAccount.bind(this)}
onAddAccount={this.addAndSelectAccount}
onSelectAccount={this.selectAccount.bind(this)}
openAccountDeletionScreen={this.openAccountDeletionScreen.bind(
this
Expand Down
5 changes: 0 additions & 5 deletions src/renderer/backend/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,3 @@ export async function getConfiguredAccounts(): Promise<T.Account[]> {
return account.kind === 'Configured'
})
}

export async function isAccountConfigured(accountId: number): Promise<boolean> {
const account = await BackendRemote.rpc.getAccountInfo(accountId)
return account.kind === 'Configured'
}
21 changes: 8 additions & 13 deletions src/renderer/components/dialogs/QrCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ import { BackendRemote } from '../../backend-com'
import { getLogger } from '../../../shared/logger'
import { runtime } from '../../runtime'
import { ScreenContext } from '../../contexts/ScreenContext'
import useChat from '../../hooks/chat/useChat'
import useContextMenu from '../../hooks/useContextMenu'
import useProcessQr from '../../hooks/useProcessQr'
import useTranslationFunction from '../../hooks/useTranslationFunction'
import { qrCodeToInviteUrl } from '../../utils/invite'
import { selectedAccountId } from '../../ScreenController'

import type { DialogProps } from '../../contexts/DialogContext'
import useAlertDialog from '../../hooks/dialog/useAlertDialog'

const log = getLogger('renderer/dialogs/QrCode')

Expand Down Expand Up @@ -206,37 +206,32 @@ export function QrCodeScanQrInner({
const tx = useTranslationFunction()
const accountId = selectedAccountId()
const processQr = useProcessQr()
const { selectChat } = useChat()
const processingQrCode = useRef(false)
const openAlertDialog = useAlertDialog()

const onDone = useCallback(() => {
onClose()
processingQrCode.current = false
}, [onClose])

const handleScanResult = useCallback(
(chatId: number | null = null) => {
chatId && selectChat(accountId, chatId)
onDone()
},
[onDone, selectChat, accountId]
)

const handleScan = useCallback(
async (data: string) => {
if (data && !processingQrCode.current) {
processingQrCode.current = true
try {
await processQr(accountId, data, handleScanResult)
await processQr(accountId, data, onDone)
} catch (error: any) {
handleError(error)
log.errorWithoutStackTrace('QrReader process error: ', error)
openAlertDialog({
message: error.message || error.toString(),
})
}
processingQrCode.current = false
} else if (processingQrCode.current === true) {
log.debug('Already processing a qr code')
}
},
[accountId, handleScanResult, processQr]
[accountId, processQr, onDone, openAlertDialog]
)

const handleError = (err: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ import useTranslationFunction from '../../hooks/useTranslationFunction'

import type { DialogProps } from '../../contexts/DialogContext'

type Props = {
subtitle: string
}

export default function ImportQrCode({ onClose }: Props & DialogProps) {
export default function QrCodeScanner({ onClose }: DialogProps) {
const tx = useTranslationFunction()

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,77 +1,87 @@
import { Intent } from '@blueprintjs/core'
import { DcEventType } from '@deltachat/jsonrpc-client'
import React, { useEffect, useState } from 'react'
import React, { useRef, useCallback } from 'react'

import { getLogger } from '../../../../shared/logger'
import { BackendRemote } from '../../../backend-com'
import { DialogBody, DialogFooter, FooterActions } from '../../Dialog'
import FooterActionButton from '../../Dialog/FooterActionButton'
import QrReader from '../../QrReader'
import useProcessQr from '../../../hooks/useProcessQr'
import { selectedAccountId } from '../../../ScreenController'
import { DeltaProgressBar } from '../../Login-Styles'
import { DialogBody, DialogContent, DialogWithHeader } from '../../Dialog'
import { DialogWithHeader } from '../../Dialog'
import useTranslationFunction from '../../../hooks/useTranslationFunction'
import { getLogger } from '../../../../shared/logger'

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

import type { DialogProps } from '../../../contexts/DialogContext'
import useAlertDialog from '../../../hooks/dialog/useAlertDialog'
import { runtime } from '../../../runtime'

const log = getLogger('renderer/receive_backup')
const log = getLogger('renderer/dialogs/SetupMultiDevice/ReceiveBackup')

type Props = {
QrWithToken: string
subtitle: string
}

export function ReceiveBackupDialog({
onClose,
QrWithToken,
}: Props & DialogProps) {
const [importProgress, setImportProgress] = useState(0.0)
const [error, setError] = useState<string | null>(null)
export function ReceiveBackupDialog({ onClose }: Props & DialogProps) {
const tx = useTranslationFunction()

const onImexProgress = ({ progress }: DcEventType<'ImexProgress'>) => {
setImportProgress(progress)
}

const accountId = selectedAccountId()
const processQr = useProcessQr()
const processingQrCode = useRef(false)
const openAlertDialog = useAlertDialog()

useEffect(() => {
;(async () => {
try {
log.debug(`Starting remote backup import of ${QrWithToken}`)
await BackendRemote.rpc.getBackup(accountId, QrWithToken)
} catch (err) {
if (err instanceof Error) {
setError(err.message)
const onDone = useCallback(() => {
onClose()
processingQrCode.current = false
}, [onClose])

const handleScan = useCallback(
async (data: string) => {
if (data && !processingQrCode.current) {
processingQrCode.current = true
try {
await processQr(accountId, data, onDone)
} catch (error: any) {
log.errorWithoutStackTrace('QrReader process error: ', error)
openAlertDialog({
message: error.message || error.toString(),
})
}
return
processingQrCode.current = false
} else if (processingQrCode.current === true) {
log.debug('Already processing a qr code')
}
onClose()
window.__selectAccount(accountId)
window.__updateAccountListSidebar?.()
})()
},
[accountId, processQr, onDone, openAlertDialog]
)

const emitter = BackendRemote.getContextEvents(accountId)
emitter.on('ImexProgress', onImexProgress)
return () => {
emitter.off('ImexProgress', onImexProgress)
}
}, [QrWithToken, onClose, accountId])
const handleError = (err: string) => {
log.error('QrReader error: ' + err)
}

return (
<DialogWithHeader
onClose={onClose}
title={tx('multidevice_receiver_title')}
onClose={onClose}
>
<DialogBody>
<DialogContent>
{error && (
<p>
{tx('error')}: {error}
</p>
)}
<DeltaProgressBar
progress={importProgress}
intent={!error ? Intent.SUCCESS : Intent.DANGER}
/>
</DialogContent>
<p className={styles.receiveSteps}>
{tx('multidevice_open_settings_on_other_device')}
<br />
{tx('multidevice_experimental_hint')}
</p>
<QrReader onScan={handleScan} onError={handleError} />
</DialogBody>
<DialogFooter>
<FooterActions align='spaceBetween'>
<FooterActionButton
onClick={() => runtime.openHelpWindow('multiclient')}
>
{tx('troubleshooting')}
</FooterActionButton>
<FooterActionButton onClick={onClose}>
{tx('close')}
</FooterActionButton>
</FooterActions>
</DialogFooter>
</DialogWithHeader>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Intent } from '@blueprintjs/core'
import { DcEventType } from '@deltachat/jsonrpc-client'
import React, { useEffect, useState } from 'react'

import { getLogger } from '../../../../shared/logger'
import { BackendRemote } from '../../../backend-com'
import { selectedAccountId } from '../../../ScreenController'
import { DeltaProgressBar } from '../../Login-Styles'
import { DialogBody, DialogContent, DialogWithHeader } from '../../Dialog'
import useTranslationFunction from '../../../hooks/useTranslationFunction'

import type { DialogProps } from '../../../contexts/DialogContext'

const log = getLogger('renderer/receive_backup')

type Props = {
QrWithToken: string
}

export function ReceiveBackupProgressDialog({
onClose,
QrWithToken,
}: Props & DialogProps) {
const [importProgress, setImportProgress] = useState(0.0)
const [error, setError] = useState<string | null>(null)
const tx = useTranslationFunction()

const onImexProgress = ({ progress }: DcEventType<'ImexProgress'>) => {
setImportProgress(progress)
}

const accountId = selectedAccountId()

useEffect(() => {
;(async () => {
try {
log.debug(`Starting remote backup import of ${QrWithToken}`)
await BackendRemote.rpc.getBackup(accountId, QrWithToken)
} catch (err) {
if (err instanceof Error) {
setError(err.message)
}
return
}
onClose()
window.__selectAccount(accountId)
window.__updateAccountListSidebar?.()
})()

const emitter = BackendRemote.getContextEvents(accountId)
emitter.on('ImexProgress', onImexProgress)
return () => {
emitter.off('ImexProgress', onImexProgress)
}
}, [QrWithToken, onClose, accountId])

return (
<DialogWithHeader
onClose={onClose}
title={tx('multidevice_receiver_title')}
>
<DialogBody>
<DialogContent>
{error && (
<p>
{tx('error')}: {error}
</p>
)}
<DeltaProgressBar
progress={importProgress}
intent={!error ? Intent.SUCCESS : Intent.DANGER}
/>
</DialogContent>
</DialogBody>
</DialogWithHeader>
)
}
Loading

0 comments on commit 69f3a76

Please sign in to comment.