diff options
11 files changed, 250 insertions, 1 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/AppRouter.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/AppRouter.tsx index 3541c095d6..6ad0a9e199 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/components/AppRouter.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/components/AppRouter.tsx @@ -38,6 +38,7 @@ import TooManyDevices from './TooManyDevices'; import TransitionContainer, { TransitionView } from './TransitionContainer'; import UdpOverTcp from './UdpOverTcp'; import UserInterfaceSettings from './UserInterfaceSettings'; +import { AppInfoView, ChangelogView } from './views'; import VpnSettings from './VpnSettings'; import WireguardSettings from './WireguardSettings'; @@ -103,6 +104,8 @@ export default function AppRouter() { <Route exact path={RoutePath.selectLocation} component={SelectLocation} /> <Route exact path={RoutePath.editCustomBridge} component={EditCustomBridge} /> <Route exact path={RoutePath.filter} component={Filter} /> + <Route exact path={RoutePath.appInfo} component={AppInfoView} /> + <Route exact path={RoutePath.changelog} component={ChangelogView} /> </Switch> </TransitionView> </TransitionContainer> diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/AppInfoView.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/AppInfoView.tsx new file mode 100644 index 0000000000..41671c46a9 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/AppInfoView.tsx @@ -0,0 +1,48 @@ +import { messages } from '../../../../shared/gettext'; +import { useHistory } from '../../../lib/history'; +import { BackAction } from '../../KeyboardNavigation'; +import { Layout, SettingsContainer, SettingsGroup, SettingsStack } from '../../Layout'; +import { + NavigationBar, + NavigationContainer, + NavigationItems, + NavigationScrollbars, + TitleBarItem, +} from '../../NavigationBar'; +import SettingsHeader, { HeaderTitle } from '../../SettingsHeader'; +import { AppVersionListItem, ChangelogListItem } from './components'; + +export const AppInfoView = () => { + const { pop } = useHistory(); + return ( + <BackAction action={pop}> + <Layout> + <SettingsContainer> + <NavigationContainer> + <NavigationBar> + <NavigationItems> + <TitleBarItem>{messages.pgettext('app-info-view', 'App info')}</TitleBarItem> + </NavigationItems> + </NavigationBar> + + <NavigationScrollbars> + <SettingsHeader> + <HeaderTitle>{messages.pgettext('app-info-view', 'App info')}</HeaderTitle> + </SettingsHeader> + <SettingsContainer> + <SettingsStack> + <SettingsGroup> + <AppVersionListItem /> + </SettingsGroup> + <SettingsGroup> + <ChangelogListItem /> + </SettingsGroup> + </SettingsStack> + </SettingsContainer> + </NavigationScrollbars> + </NavigationContainer> + </SettingsContainer> + </Layout> + </BackAction> + ); +}; diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/AppVersionListItem.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/AppVersionListItem.tsx new file mode 100644 index 0000000000..6460515791 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/AppVersionListItem.tsx @@ -0,0 +1,65 @@ +import { useCallback } from 'react'; + +import { messages } from '../../../../../shared/gettext'; +import { getDownloadUrl } from '../../../../../shared/version'; +import { useAppContext } from '../../../../context'; +import { useSelector } from '../../../../redux/store'; +import { Colors } from '../../../../tokens'; +import * as Cell from '../../../cell'; +import { LabelStack } from '../../../Layout'; + +export function AppVersionListItem() { + const appVersion = useSelector((state) => state.version.current); + const consistentVersion = useSelector((state) => state.version.consistent); + const upToDateVersion = useSelector((state) => (state.version.suggestedUpgrade ? false : true)); + const suggestedIsBeta = useSelector((state) => state.version.suggestedIsBeta ?? false); + const isOffline = useSelector((state) => state.connection.isBlocked); + + const { openUrl } = useAppContext(); + const openDownloadLink = useCallback( + () => openUrl(getDownloadUrl(suggestedIsBeta)), + [openUrl, suggestedIsBeta], + ); + + let alertIcon; + let footer; + if (!consistentVersion || !upToDateVersion) { + const inconsistentVersionMessage = messages.pgettext( + 'app-info-view', + 'App is out of sync. Please quit and restart.', + ); + + const updateAvailableMessage = messages.pgettext( + 'app-info-view', + 'Update available. Install the latest app version to stay up to date.', + ); + + const message = !consistentVersion ? inconsistentVersionMessage : updateAvailableMessage; + + alertIcon = <Cell.UntintedIcon source="icon-alert" width={18} tintColor={Colors.red} />; + footer = ( + <Cell.CellFooter> + <Cell.CellFooterText>{message}</Cell.CellFooterText> + </Cell.CellFooter> + ); + } + + return ( + <> + <Cell.CellNavigationButton + disabled={isOffline} + onClick={openDownloadLink} + icon={{ + source: 'icon-extLink', + 'aria-label': messages.pgettext('accessibility', 'Opens externally'), + }}> + <LabelStack> + {alertIcon} + <Cell.Label>{messages.pgettext('app-info-view', 'App version')}</Cell.Label> + </LabelStack> + <Cell.SubText>{appVersion}</Cell.SubText> + </Cell.CellNavigationButton> + {footer} + </> + ); +} diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/ChangelogListItem.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/ChangelogListItem.tsx new file mode 100644 index 0000000000..c05b0286b6 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/ChangelogListItem.tsx @@ -0,0 +1,17 @@ +import { useCallback } from 'react'; + +import { messages } from '../../../../../shared/gettext'; +import { useHistory } from '../../../../lib/history'; +import { RoutePath } from '../../../../lib/routes'; +import * as Cell from '../../../cell'; + +export function ChangelogListItem() { + const history = useHistory(); + const navigate = useCallback(() => history.push(RoutePath.changelog), [history]); + + return ( + <Cell.CellNavigationButton onClick={navigate}> + <Cell.Label>{messages.pgettext('settings-view', "What's new")}</Cell.Label> + </Cell.CellNavigationButton> + ); +} diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/index.ts new file mode 100644 index 0000000000..905bc45397 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/index.ts @@ -0,0 +1,2 @@ +export * from './AppVersionListItem'; +export * from './ChangelogListItem'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/index.ts new file mode 100644 index 0000000000..afbe9686f6 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/index.ts @@ -0,0 +1 @@ +export * from './AppInfoView'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/changelog/ChangelogView.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/changelog/ChangelogView.tsx new file mode 100644 index 0000000000..99c278c51d --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/changelog/ChangelogView.tsx @@ -0,0 +1,106 @@ +import { useCallback } from 'react'; +import styled from 'styled-components'; + +import { links } from '../../../../config.json'; +import { messages } from '../../../../shared/gettext'; +import { useAppContext } from '../../../context'; +import { useHistory } from '../../../lib/history'; +import { useSelector } from '../../../redux/store'; +import { Colors, Spacings } from '../../../tokens'; +import { Flex } from '../../common/layout'; +import { Container } from '../../common/layout/Container'; +import { Button } from '../../common/molecules/Button'; +import { BodySmall, TitleBig, TitleLarge } from '../../common/text'; +import ImageView from '../../ImageView'; +import { BackAction } from '../../KeyboardNavigation'; +import { Layout, SettingsContainer } from '../../Layout'; +import { + NavigationBar, + NavigationContainer, + NavigationItems, + NavigationScrollbars, + TitleBarItem, +} from '../../NavigationBar'; +import SettingsHeader from '../../SettingsHeader'; + +const StyledList = styled(Flex)({ + listStyleType: 'disc', + paddingLeft: 0, + li: { + marginLeft: '1.5em', + }, +}); + +const StyledFooter = styled(Flex)({ + position: 'sticky', + minHeight: '64px', + bottom: 0, + background: Colors.darkBlue, +}); + +export const ChangelogView = () => { + const { pop } = useHistory(); + const { openUrl } = useAppContext(); + const changelog = useSelector((state) => state.userInterface.changelog); + const version = useSelector((state) => state.version.current); + + const url = links.download; + const openDownloadLink = useCallback(() => openUrl(url), [openUrl, url]); + return ( + <BackAction action={pop}> + <Layout> + <SettingsContainer> + <NavigationContainer> + <NavigationBar> + <NavigationItems> + <TitleBarItem>{messages.pgettext('changelog-view', "What's new")}</TitleBarItem> + </NavigationItems> + </NavigationBar> + + <NavigationScrollbars> + <SettingsHeader> + <TitleBig as={'h1'}>{messages.pgettext('changelog-view', "What's new")}</TitleBig> + </SettingsHeader> + <Flex $flexDirection="column" $gap={Spacings.spacing3}> + <Container size="4"> + <TitleLarge as="h2">{version}</TitleLarge> + </Container> + <Container size="3" $flexDirection="column"> + {changelog.length ? ( + <StyledList as="ul" $flexDirection="column" $gap={Spacings.spacing5}> + {changelog.map((item, i) => ( + <BodySmall as="li" key={i} color={Colors.white60}> + {item} + </BodySmall> + ))} + </StyledList> + ) : ( + <BodySmall> + {messages.pgettext( + 'changelog-view', + 'No updates or changes were made in this release for this platform.', + )} + </BodySmall> + )} + </Container> + </Flex> + </NavigationScrollbars> + </NavigationContainer> + </SettingsContainer> + <StyledFooter $alignItems="center" $justifyContent="center"> + <Button + onClick={openDownloadLink} + trailing={ + <ImageView + source="icon-extLink" + aria-label={messages.pgettext('accessibility', 'Opens externally')} + tintColor={Colors.white} + /> + }> + {messages.pgettext('changelog', 'See full changelog')} + </Button> + </StyledFooter> + </Layout> + </BackAction> + ); +}; diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/changelog/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/changelog/index.ts new file mode 100644 index 0000000000..2c823d4f13 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/changelog/index.ts @@ -0,0 +1 @@ +export * from './ChangelogView'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/index.ts new file mode 100644 index 0000000000..dff5aa7a90 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/index.ts @@ -0,0 +1,2 @@ +export * from './app-info'; +export * from './changelog'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/routes.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/routes.ts index 89b50c1fb0..73f510ea3a 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/lib/routes.ts +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/routes.ts @@ -31,4 +31,6 @@ export enum RoutePath { selectLocation = '/select-location', editCustomBridge = '/select-location/edit-custom-bridge', filter = '/select-location/filter', + appInfo = '/settings/app-info', + changelog = '/settings/changelog', } diff --git a/desktop/packages/mullvad-vpn/src/shared/localization-contexts.ts b/desktop/packages/mullvad-vpn/src/shared/localization-contexts.ts index f30212025c..c4d47b1afa 100644 --- a/desktop/packages/mullvad-vpn/src/shared/localization-contexts.ts +++ b/desktop/packages/mullvad-vpn/src/shared/localization-contexts.ts @@ -37,4 +37,6 @@ export type LocalizationContexts = | 'select-language-nav' | 'tray-icon-context-menu' | 'tray-icon-tooltip' - | 'troubleshoot'; + | 'troubleshoot' + | 'app-info-view' + | 'changelog-view'; |
