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

chore: Add PDF viewer #2796

Merged
merged 11 commits into from
Feb 9, 2024
1 change: 0 additions & 1 deletion .nvmrc

This file was deleted.

29 changes: 29 additions & 0 deletions src/documentViewer/ipc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { handle } from '../ipc/main';
import { SERVER_DOCUMENT_VIEWER_OPEN_URL } from '../servers/actions';
import { dispatch, select } from '../store';

export const startDocumentViewerHandler = (): void => {
handle(
'document-viewer/open-window',
async (event, url, _format, _options) => {
const validUrl = new URL(url);
const allowedProtocols = ['http:', 'https:'];
if (!allowedProtocols.includes(validUrl.protocol)) {
return;
}
const server = select(({ servers }) =>
servers.find(
(s) => new URL(s.url).origin === new URL(event.getURL()).origin
)
);
if (!server) {
return;
}

dispatch({
type: SERVER_DOCUMENT_VIEWER_OPEN_URL,
payload: { server: server.url, documentUrl: url },
});
}
);
};
15 changes: 15 additions & 0 deletions src/injected.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,21 @@ const start = async () => {
window.RocketChatDesktop.setGitCommitHash(gitCommitHash);
});

Tracker.autorun(() => {
const uid = Meteor.userId();
if (!uid) return;
const themeAppearance: string = getUserPreference(uid, 'themeAppearence');
if (
['dark', 'light', 'auto', 'high-contrast'].includes(
themeAppearance as any
)
) {
window.RocketChatDesktop.setUserThemeAppearance(
themeAppearance as 'auto' | 'dark' | 'light' | 'high-contrast'
);
}
});

Tracker.autorun(() => {
const uid = Meteor.userId();
if (!uid) return;
Expand Down
5 changes: 5 additions & 0 deletions src/ipc/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ type ChannelToArgsMap = {
'outlook-calendar/has-credentials': () => Promise<boolean>;
'outlook-calendar/clear-credentials': () => void;
'outlook-calendar/set-user-token': (token: string, userId: string) => void;
'document-viewer/open-window': (
url: string,
format: string,
options: any
) => void;
};

export type Channel = keyof ChannelToArgsMap;
Expand Down
2 changes: 2 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from './app/main/data';
import { setUserDataDirectory } from './app/main/dev';
import { setupDeepLinks, processDeepLinksInArgs } from './deepLinks/main';
import { startDocumentViewerHandler } from './documentViewer/ipc';
import { setupDownloads } from './downloads/main';
import { setupMainErrorHandling } from './errors';
import i18n from './i18n/main';
Expand Down Expand Up @@ -98,6 +99,7 @@ const start = async (): Promise<void> => {
handleJitsiDesktopCapturerGetSources();
handleDesktopCapturerGetSources();
startOutlookCalendarUrlHandler();
startDocumentViewerHandler();
checkSupportedVersionServers();

await processDeepLinksInArgs();
Expand Down
3 changes: 1 addition & 2 deletions src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ declare global {
}

contextBridge.exposeInMainWorld('JitsiMeetElectron', JitsiMeetElectron);
contextBridge.exposeInMainWorld('RocketChatDesktop', RocketChatDesktop);

const start = async (): Promise<void> => {
console.log('[Rocket.Chat Desktop] preload.ts start');
Expand All @@ -36,8 +37,6 @@ const start = async (): Promise<void> => {

window.removeEventListener('load', start);

contextBridge.exposeInMainWorld('RocketChatDesktop', RocketChatDesktop);

setServerUrl(serverUrl);

await whenReady();
Expand Down
6 changes: 6 additions & 0 deletions src/servers/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const SERVERS_LOADED = 'servers/loaded';
export const SERVER_URL_RESOLUTION_REQUESTED =
'server/url-resolution-requested';
export const SERVER_URL_RESOLVED = 'server/url-resolved';
export const SERVER_DOCUMENT_VIEWER_OPEN_URL =
'server/document-viewer/open-url';

export type ServersActionTypeToPayloadMap = {
[SERVERS_LOADED]: {
Expand All @@ -12,4 +14,8 @@ export type ServersActionTypeToPayloadMap = {
};
[SERVER_URL_RESOLUTION_REQUESTED]: Server['url'];
[SERVER_URL_RESOLVED]: ServerUrlResolutionResult;
[SERVER_DOCUMENT_VIEWER_OPEN_URL]: {
server: Server['url'];
documentUrl: string;
};
};
2 changes: 2 additions & 0 deletions src/servers/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export type Server = {
supportedVersionsSource?: 'server' | 'cloud' | 'builtin';
supportedVersions?: SupportedVersions;
expirationMessageLastTimeShown?: Date;
documentViewerOpenUrl?: string;
themeAppearance?: 'dark' | 'light' | 'auto' | 'high-contrast';
};

export const enum ServerUrlResolutionStatus {
Expand Down
6 changes: 6 additions & 0 deletions src/servers/preload/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { setUserPresenceDetection } from '../../userPresence/preload';
import type { Server } from '../common';
import { setBadge } from './badge';
import { writeTextToClipboard } from './clipboard';
import { openDocumentViewer } from './documentViewer';
import { setFavicon } from './favicon';
import { setGitCommitHash } from './gitCommitHash';
import type { videoCallWindowOptions } from './internalVideoChatWindow';
Expand All @@ -26,6 +27,7 @@ import {
setServerVersionToSidebar,
setSidebarCustomTheme,
} from './sidebar';
import { setUserThemeAppearance } from './themeAppearance';
import { setTitle } from './title';
import { setUrlResolver } from './urls';
import { setUserLoggedIn } from './userLoggedIn';
Expand All @@ -52,6 +54,7 @@ export type RocketChatDesktopAPI = {
idleThreshold: number | null;
setUserOnline: (online: boolean) => void;
}) => void;
setUserThemeAppearance: (themeAppearance: Server['themeAppearance']) => void;
createNotification: (
options: NotificationOptions & {
canReply?: boolean;
Expand All @@ -72,6 +75,7 @@ export type RocketChatDesktopAPI = {
hasOutlookCredentials: () => Promise<boolean>;
clearOutlookCredentials: () => void;
setUserToken: (token: string, userId: string) => void;
openDocumentViewer: (url: string, format: string, options: any) => void;
};

export const RocketChatDesktop: RocketChatDesktopAPI = {
Expand All @@ -93,6 +97,7 @@ export const RocketChatDesktop: RocketChatDesktopAPI = {
setTitle,
setUserPresenceDetection,
setUserLoggedIn,
setUserThemeAppearance,
createNotification,
destroyNotification,
getInternalVideoChatWindowEnabled,
Expand All @@ -105,4 +110,5 @@ export const RocketChatDesktop: RocketChatDesktopAPI = {
clearOutlookCredentials,
setUserToken,
setSidebarCustomTheme,
openDocumentViewer,
};
9 changes: 9 additions & 0 deletions src/servers/preload/documentViewer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ipcRenderer } from 'electron';

export const openDocumentViewer = (
url: string,
format: string,
options: any
): void => {
ipcRenderer.invoke('document-viewer/open-window', url, format, options);
};
16 changes: 16 additions & 0 deletions src/servers/preload/themeAppearance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { dispatch } from '../../store';
import { WEBVIEW_USER_THEME_APPEARANCE_CHANGED } from '../../ui/actions';
import type { Server } from '../common';
import { getServerUrl } from './urls';

export const setUserThemeAppearance = (
themeAppearance: Server['themeAppearance']
): void => {
dispatch({
type: WEBVIEW_USER_THEME_APPEARANCE_CHANGED,
payload: {
url: getServerUrl(),
themeAppearance,
},
});
};
22 changes: 18 additions & 4 deletions src/servers/reducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import {
WEBVIEW_SERVER_VERSION_UPDATED,
SUPPORTED_VERSION_DIALOG_DISMISS,
WEBVIEW_SIDEBAR_CUSTOM_THEME_CHANGED,
WEBVIEW_USER_THEME_APPEARANCE_CHANGED,
} from '../ui/actions';
import { SERVERS_LOADED } from './actions';
import { SERVERS_LOADED, SERVER_DOCUMENT_VIEWER_OPEN_URL } from './actions';
import type { Server } from './common';

const ensureUrlFormat = (serverUrl: string | null): string => {
Expand Down Expand Up @@ -63,7 +64,9 @@ type ServersActionTypes =
| ActionOf<typeof WEBVIEW_SERVER_UNIQUE_ID_UPDATED>
| ActionOf<typeof WEBVIEW_SERVER_IS_SUPPORTED_VERSION>
| ActionOf<typeof WEBVIEW_SERVER_VERSION_UPDATED>
| ActionOf<typeof SUPPORTED_VERSION_DIALOG_DISMISS>;
| ActionOf<typeof SUPPORTED_VERSION_DIALOG_DISMISS>
| ActionOf<typeof SERVER_DOCUMENT_VIEWER_OPEN_URL>
| ActionOf<typeof WEBVIEW_USER_THEME_APPEARANCE_CHANGED>;

const upsert = (state: Server[], server: Server): Server[] => {
const index = state.findIndex(({ url }) => url === server.url);
Expand Down Expand Up @@ -136,6 +139,11 @@ export const servers: Reducer<Server[], ServersActionTypes> = (
return upsert(state, { url, uniqueID });
}

case WEBVIEW_USER_THEME_APPEARANCE_CHANGED: {
const { url, themeAppearance } = action.payload;
return upsert(state, { url, themeAppearance });
}

case WEBVIEW_SERVER_IS_SUPPORTED_VERSION: {
const { url, isSupportedVersion } = action.payload;
return upsert(state, { url, isSupportedVersion });
Expand Down Expand Up @@ -206,17 +214,18 @@ export const servers: Reducer<Server[], ServersActionTypes> = (

case SERVERS_LOADED: {
const { servers = state } = action.payload;
return servers.map((server) => ({
return servers.map((server: Server) => ({
...server,
url: ensureUrlFormat(server.url),
}));
}

case APP_SETTINGS_LOADED: {
const { servers = state } = action.payload;
return servers.map((server) => ({
return servers.map((server: Server) => ({
...server,
url: ensureUrlFormat(server.url),
documentViewerOpenUrl: '',
}));
}

Expand All @@ -235,6 +244,11 @@ export const servers: Reducer<Server[], ServersActionTypes> = (
return upsert(state, { url, outlookCredentials });
}

case SERVER_DOCUMENT_VIEWER_OPEN_URL: {
const { server, documentUrl } = action.payload;
return upsert(state, { url: server, documentViewerOpenUrl: documentUrl });
}

default:
return state;
}
Expand Down
6 changes: 6 additions & 0 deletions src/ui/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export const WEBVIEW_GIT_COMMIT_HASH_CHECK = 'webview/git-commit-hash-check';
export const WEBVIEW_TITLE_CHANGED = 'webview/title-changed';
export const WEBVIEW_UNREAD_CHANGED = 'webview/unread-changed';
export const WEBVIEW_USER_LOGGED_IN = 'webview/user-loggedin';
export const WEBVIEW_USER_THEME_APPEARANCE_CHANGED =
'webview/user-theme-appearance-changed';
export const WEBVIEW_ALLOWED_REDIRECTS_CHANGED =
'webview/allowed-redirects-changed';
export const SETTINGS_SET_REPORT_OPT_IN_CHANGED =
Expand Down Expand Up @@ -159,6 +161,10 @@ export type UiActionTypeToPayloadMap = {
url: Server['url'];
userLoggedIn: Server['userLoggedIn'];
};
[WEBVIEW_USER_THEME_APPEARANCE_CHANGED]: {
url: Server['url'];
themeAppearance: Server['themeAppearance'];
};
[WEBVIEW_GIT_COMMIT_HASH_CHECK]: {
url: Server['url'];
gitCommitHash: Server['gitCommitHash'];
Expand Down
65 changes: 65 additions & 0 deletions src/ui/components/ServersView/DocumentViewer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Box, IconButton } from '@rocket.chat/fuselage';
import { useDarkMode } from '@rocket.chat/fuselage-hooks';

const DocumentViewer = ({
url,
partition,
closeDocumentViewer,
themeAppearance,
}: {
url: string;
partition: string;
themeAppearance: string | undefined;
closeDocumentViewer: () => void;
}) => {
const theme = useDarkMode(
themeAppearance === 'auto' ? undefined : themeAppearance === 'dark'
)
? 'dark'
: 'light';
return (
<>
<Box
bg={theme}
width='100%'
height='100%'
position='absolute'
content='center'
alignItems='center'
>
<Box
content='center'
alignItems='center'
display='flex'
color={theme === 'dark' ? 'font-white' : 'font-text'}
>
<IconButton
icon='arrow-back'
onClick={closeDocumentViewer}
mi='x8'
color={theme === 'dark' ? 'white' : 'default'}
/>
<h2>PDF Viewer</h2>
</Box>

<Box>
<webview
src={url}
style={{
width: '100%',
height: '100%',
position: 'absolute',
left: 0,
top: 50,
right: 0,
bottom: 0,
}}
partition={partition}
/>
</Box>
</Box>
</>
);
};

export default DocumentViewer;
Loading
Loading