mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-11 07:57:33 +00:00
fix: modified universal link (#7094)
This commit is contained in:
parent
dfe994b341
commit
3190eebf6e
@ -1,25 +1 @@
|
|||||||
{
|
{"applinks":{"apps":[],"details":[{"appIDs":["VHB67HRSZG.com.appflowy.appflowy.flutter"],"paths":["/download","/download/*"],"components":[{"/":"/download","comment":"Matches any URL whose path starts with /download"},{"/":"/download/*","comment":"Matches any URL whose path starts with /download/"}]}]},"webcredentials":{"apps":["VHB67HRSZG.com.appflowy.appflowy.flutter"]}}
|
||||||
"applinks": {
|
|
||||||
"apps": [],
|
|
||||||
"details": [
|
|
||||||
{
|
|
||||||
"appIDs": [
|
|
||||||
"VHB67HRSZG.com.appflowy.appflowy.flutter"
|
|
||||||
],
|
|
||||||
"paths": [
|
|
||||||
"*"
|
|
||||||
],
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"/": "/*"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"webcredentials": {
|
|
||||||
"apps": [
|
|
||||||
"VHB67HRSZG.com.appflowy.appflowy.flutter"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -8,7 +8,8 @@
|
|||||||
"package_name": "io.appflowy.appflowy",
|
"package_name": "io.appflowy.appflowy",
|
||||||
"sha256_cert_fingerprints": [
|
"sha256_cert_fingerprints": [
|
||||||
"19:13:85:33:DB:B3:A2:FD:65:2F:61:D7:F2:35:95:79:FE:6E:CC:B5:AC:94:AA:02:9E:BE:E7:0E:02:6B:45:FF"
|
"19:13:85:33:DB:B3:A2:FD:65:2F:61:D7:F2:35:95:79:FE:6E:CC:B5:AC:94:AA:02:9E:BE:E7:0E:02:6B:45:FF"
|
||||||
]
|
],
|
||||||
|
"path_prefix": "/download"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -27,6 +27,7 @@ describe('Markdown editing', () => {
|
|||||||
// Test `Bold`
|
// Test `Bold`
|
||||||
cy.get('@editor').type('**bold');
|
cy.get('@editor').type('**bold');
|
||||||
cy.get('@editor').realPress(['*', '*']);
|
cy.get('@editor').realPress(['*', '*']);
|
||||||
|
cy.wait(50);
|
||||||
expectedJson = [{
|
expectedJson = [{
|
||||||
type: 'paragraph',
|
type: 'paragraph',
|
||||||
data: {},
|
data: {},
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import React from 'react';
|
|||||||
import { ReactComponent as Logo } from '@/assets/logo.svg';
|
import { ReactComponent as Logo } from '@/assets/logo.svg';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export function Login({ redirectTo }: { redirectTo: string }) {
|
export function Login ({ redirectTo }: { redirectTo: string }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -27,11 +27,19 @@ export function Login({ redirectTo }: { redirectTo: string }) {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span>{t('web.signInAgreement')} </span>
|
<span>{t('web.signInAgreement')} </span>
|
||||||
<a href={'https://appflowy.io/terms'} target={'_blank'} className={'text-fill-default underline'}>
|
<a
|
||||||
|
href={'https://appflowy.io/terms'}
|
||||||
|
target={'_blank'}
|
||||||
|
className={'text-fill-default underline'}
|
||||||
|
>
|
||||||
{t('web.termOfUse')}
|
{t('web.termOfUse')}
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
{t('web.and')}{' '}
|
{t('web.and')}{' '}
|
||||||
<a href={'https://appflowy.io/privacy'} target={'_blank'} className={'text-fill-default underline'}>
|
<a
|
||||||
|
href={'https://appflowy.io/privacy'}
|
||||||
|
target={'_blank'}
|
||||||
|
className={'text-fill-default underline'}
|
||||||
|
>
|
||||||
{t('web.privacyPolicy')}
|
{t('web.privacyPolicy')}
|
||||||
</a>
|
</a>
|
||||||
.
|
.
|
||||||
|
|||||||
@ -20,35 +20,35 @@ const AppMain = withAppWrapper(() => {
|
|||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
path={'/:namespace/:publishName'}
|
path={'/:namespace/:publishName'}
|
||||||
element={<PublishPage/>}
|
element={<PublishPage />}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={'/login'}
|
path={'/login'}
|
||||||
element={<Suspense><LoginPage/></Suspense>}
|
element={<Suspense><LoginPage /></Suspense>}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={AUTH_CALLBACK_PATH}
|
path={AUTH_CALLBACK_PATH}
|
||||||
element={<LoginAuth/>}
|
element={<LoginAuth />}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/404"
|
path="/404"
|
||||||
element={<NotFound/>}
|
element={<NotFound />}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/after-payment"
|
path="/after-payment"
|
||||||
element={<Suspense><AfterPaymentPage/></Suspense>}
|
element={<Suspense><AfterPaymentPage /></Suspense>}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/as-template"
|
path="/as-template"
|
||||||
element={<Suspense><AsTemplatePage/></Suspense>}
|
element={<Suspense><AsTemplatePage /></Suspense>}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/accept-invitation"
|
path="/accept-invitation"
|
||||||
element={<Suspense><AcceptInvitationPage/></Suspense>}
|
element={<Suspense><AcceptInvitationPage /></Suspense>}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={'/import'}
|
path={'/import'}
|
||||||
element={<Suspense><ImportPage/></Suspense>}
|
element={<Suspense><ImportPage /></Suspense>}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/"
|
path="/"
|
||||||
@ -61,28 +61,23 @@ const AppMain = withAppWrapper(() => {
|
|||||||
path="/app/*"
|
path="/app/*"
|
||||||
element={
|
element={
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<AppRouter/>
|
<AppRouter />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="*"
|
path="*"
|
||||||
element={<NotFound/>}
|
element={<NotFound />}
|
||||||
/>
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
function App() {
|
function App () {
|
||||||
const path = window.location.pathname;
|
|
||||||
|
|
||||||
if (path.startsWith('/.well-known')) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<AppMain/>
|
<AppMain />
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { QuickNote } from '@/application/types';
|
|||||||
import { Button, CircularProgress } from '@mui/material';
|
import { Button, CircularProgress } from '@mui/material';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
function AddNote({
|
function AddNote ({
|
||||||
onEnterNote,
|
onEnterNote,
|
||||||
onAdd,
|
onAdd,
|
||||||
}: {
|
}: {
|
||||||
@ -27,9 +27,10 @@ function AddNote({
|
|||||||
<Button
|
<Button
|
||||||
size={'small'}
|
size={'small'}
|
||||||
color={'inherit'}
|
color={'inherit'}
|
||||||
startIcon={loading ? <CircularProgress className={'w-4 h-4'}/> : <AddIcon className={'w-4 h-4'}/>}
|
startIcon={loading ? <CircularProgress size={16} /> : <AddIcon className={'w-4 h-4'} />}
|
||||||
onClick={handleAdd}
|
onClick={handleAdd}
|
||||||
className={'justify-start w-full'}>
|
className={'justify-start w-full'}
|
||||||
|
>
|
||||||
{t('quickNote.addNote')}
|
{t('quickNote.addNote')}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import CircularProgress from '@mui/material/CircularProgress';
|
||||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||||
import { IconButton, Tooltip, Zoom, Snackbar, Portal } from '@mui/material';
|
import { IconButton, Tooltip, Zoom, Snackbar, Portal } from '@mui/material';
|
||||||
import { ReactComponent as EditIcon } from '@/assets/edit.svg';
|
import { ReactComponent as EditIcon } from '@/assets/edit.svg';
|
||||||
@ -16,7 +17,7 @@ import { getPopoverPosition, setPopoverPosition } from '@/components/quick-note/
|
|||||||
import Note from '@/components/quick-note/Note';
|
import Note from '@/components/quick-note/Note';
|
||||||
|
|
||||||
const PAPER_SIZE = [480, 396];
|
const PAPER_SIZE = [480, 396];
|
||||||
const Transition = React.forwardRef(function Transition(
|
const Transition = React.forwardRef(function Transition (
|
||||||
props: TransitionProps & {
|
props: TransitionProps & {
|
||||||
children: React.ReactElement;
|
children: React.ReactElement;
|
||||||
},
|
},
|
||||||
@ -33,7 +34,7 @@ enum QuickNoteRoute {
|
|||||||
LIST = 'list',
|
LIST = 'list',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function QuickNote() {
|
export function QuickNote () {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const modifier = useMemo(() => createHotKeyLabel(HOT_KEY_NAME.QUICK_NOTE), []);
|
const modifier = useMemo(() => createHotKeyLabel(HOT_KEY_NAME.QUICK_NOTE), []);
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
@ -197,6 +198,7 @@ export function QuickNote() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
resetPosition();
|
resetPosition();
|
||||||
}, [resetPosition]);
|
}, [resetPosition]);
|
||||||
|
const [loading, setLoading] = React.useState(false);
|
||||||
|
|
||||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||||
const handleOpen = useCallback(async (forceCreate?: boolean) => {
|
const handleOpen = useCallback(async (forceCreate?: boolean) => {
|
||||||
@ -217,7 +219,7 @@ export function QuickNote() {
|
|||||||
} : prev);
|
} : prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
await initNoteList();
|
void initNoteList();
|
||||||
|
|
||||||
if (route === QuickNoteRoute.LIST || forceCreate) {
|
if (route === QuickNoteRoute.LIST || forceCreate) {
|
||||||
await handleAdd();
|
await handleAdd();
|
||||||
@ -232,7 +234,9 @@ export function QuickNote() {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (loading) return;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
await handleOpen(true);
|
await handleOpen(true);
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
@ -240,6 +244,8 @@ export function QuickNote() {
|
|||||||
console.error(e);
|
console.error(e);
|
||||||
handleOpenToast(e.message);
|
handleOpenToast(e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
})();
|
})();
|
||||||
} else if (createHotkey(HOT_KEY_NAME.ESCAPE)(e)) {
|
} else if (createHotkey(HOT_KEY_NAME.ESCAPE)(e)) {
|
||||||
handleClose();
|
handleClose();
|
||||||
@ -251,7 +257,7 @@ export function QuickNote() {
|
|||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handleKeyDown);
|
document.removeEventListener('keydown', handleKeyDown);
|
||||||
};
|
};
|
||||||
}, [handleOpen, handleOpenToast]);
|
}, [handleOpen, handleOpenToast, loading]);
|
||||||
|
|
||||||
const handleMouseDown = (event: React.MouseEvent) => {
|
const handleMouseDown = (event: React.MouseEvent) => {
|
||||||
if (!position) return;
|
if (!position) return;
|
||||||
@ -393,7 +399,8 @@ export function QuickNote() {
|
|||||||
expand={expand}
|
expand={expand}
|
||||||
onToggleExpand={handleToggleExpand}
|
onToggleExpand={handleToggleExpand}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
onBack={handleBackList}/>
|
onBack={handleBackList}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,26 +430,40 @@ export function QuickNote() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tooltip title={
|
<Tooltip
|
||||||
<>
|
title={
|
||||||
<div>{t('quickNote.label')}</div>
|
<>
|
||||||
<div className={'text-xs text-text-caption'}>{modifier}</div>
|
<div>{t('quickNote.label')}</div>
|
||||||
</>
|
<div className={'text-xs text-text-caption'}>{modifier}</div>
|
||||||
}>
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
ref={buttonRef}
|
ref={buttonRef}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
onClick={e => {
|
onClick={async (e) => {
|
||||||
e.currentTarget.blur();
|
e.currentTarget.blur();
|
||||||
if (open) {
|
if (open) {
|
||||||
handleClose();
|
handleClose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleOpen();
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
await handleOpen();
|
||||||
|
// eslint-disable-next-line
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error(e);
|
||||||
|
handleOpenToast(e.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<EditIcon/>
|
{loading ? <CircularProgress size={16} /> :
|
||||||
|
<EditIcon />}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Popover
|
<Popover
|
||||||
@ -481,21 +502,24 @@ export function QuickNote() {
|
|||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
keepMounted={true}
|
keepMounted={true}
|
||||||
>
|
>
|
||||||
<ToastContext.Provider value={{
|
<ToastContext.Provider
|
||||||
onOpen: handleOpenToast,
|
value={{
|
||||||
onClose: () => {
|
onOpen: handleOpenToast,
|
||||||
setToastMessage('');
|
onClose: () => {
|
||||||
setOpenToast(false);
|
setToastMessage('');
|
||||||
},
|
setOpenToast(false);
|
||||||
open: openToast,
|
},
|
||||||
}}>
|
open: openToast,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
onMouseDown={handleMouseDown}
|
onMouseDown={handleMouseDown}
|
||||||
style={{
|
style={{
|
||||||
cursor: isDragging ? 'grabbing' : 'grab',
|
cursor: isDragging ? 'grabbing' : 'grab',
|
||||||
}}
|
}}
|
||||||
|
|
||||||
className={'bg-note-header py-2 px-5 flex items-center justify-between gap-5 h-[44px] w-full'}>
|
className={'bg-note-header py-2 px-5 flex items-center justify-between gap-5 h-[44px] w-full'}
|
||||||
|
>
|
||||||
<div className={'flex-1 overflow-hidden w-full'}>{renderHeader()}</div>
|
<div className={'flex-1 overflow-hidden w-full'}>{renderHeader()}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -506,10 +530,12 @@ export function QuickNote() {
|
|||||||
<>
|
<>
|
||||||
<Note
|
<Note
|
||||||
onAdd={handleAddedNote}
|
onAdd={handleAddedNote}
|
||||||
onEnterNote={handleEnterNote} note={currentNote}
|
onEnterNote={handleEnterNote}
|
||||||
|
note={currentNote}
|
||||||
onUpdateData={(data) => {
|
onUpdateData={(data) => {
|
||||||
handleUpdateNodeData(currentNote.id, data);
|
handleUpdateNodeData(currentNote.id, data);
|
||||||
}}/>
|
}}
|
||||||
|
/>
|
||||||
</> : <NoteList
|
</> : <NoteList
|
||||||
onAdd={handleAddedNote}
|
onAdd={handleAddedNote}
|
||||||
onScroll={handleScrollList}
|
onScroll={handleScrollList}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { androidDownloadLink, desktopDownloadLink, iosDownloadLink, openAppFlowySchema } from '@/utils/url';
|
import { androidDownloadLink, desktopDownloadLink, openAppFlowySchema } from '@/utils/url';
|
||||||
|
|
||||||
type OS = 'ios' | 'android' | 'other';
|
type OS = 'ios' | 'android' | 'other';
|
||||||
|
|
||||||
@ -101,20 +101,30 @@ export const openAppOrDownload = (config: AppConfig): void => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function openOnly(schema?: string) {
|
export function openOnly (schema?: string) {
|
||||||
|
|
||||||
return openAppOrDownload({
|
return openAppOrDownload({
|
||||||
appScheme: schema || openAppFlowySchema,
|
appScheme: schema || openAppFlowySchema,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openOrDownload(schema?: string) {
|
export function openOrDownload (schema?: string) {
|
||||||
const os = getOS();
|
const os = getOS();
|
||||||
|
|
||||||
const downloadUrl = os === 'ios' ? iosDownloadLink : os === 'android' ? androidDownloadLink : desktopDownloadLink;
|
if (os === 'ios' || os === 'android') {
|
||||||
|
const universalLink = 'https://appflowy.io/download';
|
||||||
|
const intentUrl = `intent://appflowy.io/download#Intent;` +
|
||||||
|
'scheme=https;' +
|
||||||
|
'package=io.appflowy.app;' +
|
||||||
|
`S.browser_fallback_url=${encodeURIComponent(androidDownloadLink)};` +
|
||||||
|
'end';
|
||||||
|
|
||||||
|
window.location.href = os === 'ios' ? universalLink : intentUrl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return openAppOrDownload({
|
return openAppOrDownload({
|
||||||
appScheme: schema || openAppFlowySchema,
|
appScheme: schema || openAppFlowySchema,
|
||||||
downloadUrl,
|
downloadUrl: desktopDownloadLink,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2962,16 +2962,16 @@
|
|||||||
"emails": "Email"
|
"emails": "Email"
|
||||||
},
|
},
|
||||||
"quickNote": {
|
"quickNote": {
|
||||||
"label": "Quick note",
|
"label": "Quick Note",
|
||||||
"quickNotes": "Quick notes",
|
"quickNotes": "Quick Notes",
|
||||||
"search": "Search quick notes",
|
"search": "Search Quick Notes",
|
||||||
"collapseFullView": "Collapse full view",
|
"collapseFullView": "Collapse full view",
|
||||||
"expandFullView": "Expand full view",
|
"expandFullView": "Expand full view",
|
||||||
"createFailed": "Failed to create quick note",
|
"createFailed": "Failed to create Quick Note",
|
||||||
"quickNotesEmpty": "No quick notes",
|
"quickNotesEmpty": "No Quick Notes",
|
||||||
"emptyNote": "Empty note",
|
"emptyNote": "Empty note",
|
||||||
"deleteNotePrompt": "The selected note will be deleted permanently. Are you sure you want to delete it?",
|
"deleteNotePrompt": "The selected note will be deleted permanently. Are you sure you want to delete it?",
|
||||||
"addNote": "New note",
|
"addNote": "New Note",
|
||||||
"noAdditionalText": "No additional text"
|
"noAdditionalText": "No additional text"
|
||||||
},
|
},
|
||||||
"subscribe": {
|
"subscribe": {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user