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

follow up pr to instant onboarding & add as second device scanner improvements #3801

Merged
merged 14 commits into from
May 2, 2024
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-04-04) #3746
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
Loading