summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOliver <oliver@mohlin.dev>2025-02-20 10:19:17 +0100
committerTobias Järvelöv <tobias.jarvelov@mullvad.net>2025-05-28 10:28:14 +0200
commitedead5367965b5b969a0de6e49386ba245fc07e2 (patch)
tree6d16b628b19e01e20ea75f66e49538479eb72dfa
parentb64237f97c6ac57ac045475497070bc9bc1d321c (diff)
downloadmullvadvpn-edead5367965b5b969a0de6e49386ba245fc07e2.tar.xz
mullvadvpn-edead5367965b5b969a0de6e49386ba245fc07e2.zip
Update list items in app info view
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/AppInfoView.tsx29
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/AppVersionListItem.tsx64
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/BetaListItem.tsx53
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/ChangelogListItem.tsx16
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/UpdateAvailableListItem.tsx45
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/VersionListItem.tsx41
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/index.ts3
7 files changed, 172 insertions, 79 deletions
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
index dedf6b72bb..2b0abe3b63 100644
--- 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
@@ -1,21 +1,30 @@
import { messages } from '../../../../shared/gettext';
+import { Flex } from '../../../lib/components';
import { useHistory } from '../../../lib/history';
+import { useSelector } from '../../../redux/store';
import { AppNavigationHeader } from '../../';
import { BackAction } from '../../KeyboardNavigation';
-import { Layout, SettingsContainer, SettingsGroup, SettingsStack } from '../../Layout';
+import { Layout, SettingsContainer, SettingsStack } from '../../Layout';
import { NavigationContainer } from '../../NavigationContainer';
import { NavigationScrollbars } from '../../NavigationScrollbars';
import SettingsHeader, { HeaderTitle } from '../../SettingsHeader';
-import { AppVersionListItem, ChangelogListItem } from './components';
+import { ChangelogListItem, UpdateAvailableListItem, VersionListItem } from './components';
+import { BetaListItem } from './components/BetaListItem';
-export const AppInfoView = () => {
+export function AppInfoView() {
const { pop } = useHistory();
+ const suggestedUpgrade = useSelector((state) => state.version.suggestedUpgrade);
return (
<BackAction action={pop}>
<Layout>
<SettingsContainer>
<NavigationContainer>
- <AppNavigationHeader title={messages.pgettext('app-info-view', 'App info')} />
+ <AppNavigationHeader
+ title={
+ // TRANSLATORS: Title of the app info view.
+ messages.pgettext('app-info-view', 'App info')
+ }
+ />
<NavigationScrollbars>
<SettingsHeader>
@@ -23,12 +32,12 @@ export const AppInfoView = () => {
</SettingsHeader>
<SettingsContainer>
<SettingsStack>
- <SettingsGroup>
- <AppVersionListItem />
- </SettingsGroup>
- <SettingsGroup>
+ {suggestedUpgrade && <UpdateAvailableListItem />}
+ <Flex $flexDirection="column">
+ <VersionListItem />
<ChangelogListItem />
- </SettingsGroup>
+ </Flex>
+ <BetaListItem />
</SettingsStack>
</SettingsContainer>
</NavigationScrollbars>
@@ -37,4 +46,4 @@ export const AppInfoView = () => {
</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
deleted file mode 100644
index e77d98c9ea..0000000000
--- a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/AppVersionListItem.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import { useCallback } from 'react';
-
-import { messages } from '../../../../../shared/gettext';
-import { getDownloadUrl } from '../../../../../shared/version';
-import { useAppContext } from '../../../../context';
-import { useSelector } from '../../../../redux/store';
-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.CellIcon icon="alert-circle" color="red" />;
- footer = (
- <Cell.CellFooter>
- <Cell.CellFooterText>{message}</Cell.CellFooterText>
- </Cell.CellFooter>
- );
- }
-
- return (
- <>
- <Cell.CellNavigationButton
- disabled={isOffline}
- onClick={openDownloadLink}
- icon={{
- icon: 'external',
- '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/BetaListItem.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/BetaListItem.tsx
new file mode 100644
index 0000000000..ea0348f955
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/BetaListItem.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+
+import { messages } from '../../../../../shared/gettext';
+import { useAppContext } from '../../../../context';
+import { ListItem } from '../../../../lib/components/list-item';
+import { useSelector } from '../../../../redux/store';
+import Switch from '../../../Switch';
+
+export const BetaListItem = () => {
+ const isBeta = useSelector((state) => state.version.isBeta);
+ const showBetaReleases = useSelector((state) => state.settings.showBetaReleases);
+ const { setShowBetaReleases } = useAppContext();
+ const switchId = React.useId();
+ const labelId = React.useId();
+ const descriptionId = React.useId();
+
+ return (
+ <ListItem disabled={isBeta}>
+ <ListItem.Item>
+ <ListItem.Content>
+ <ListItem.Label id={labelId} as="label" htmlFor={switchId}>
+ {
+ // TRANSLATORS: Label for switch to toggle beta program.
+ messages.pgettext('app-info-view', 'Beta program')
+ }
+ </ListItem.Label>
+ <Switch
+ id={switchId}
+ aria-labelledby={labelId}
+ aria-describedby={descriptionId}
+ isOn={showBetaReleases}
+ onChange={setShowBetaReleases}
+ />
+ </ListItem.Content>
+ </ListItem.Item>
+ <ListItem.Footer>
+ <ListItem.Text id={descriptionId}>
+ {isBeta
+ ? // TRANSLATORS: Description for beta program switch when using a beta version.
+ messages.pgettext(
+ 'app-info-view',
+ 'This option is unavailable while using a beta version.',
+ )
+ : // TRANSLATORS: Description for beta program switch.
+ messages.pgettext(
+ 'app-info-view',
+ 'Enable to get notified when new beta versions of the app are released.',
+ )}
+ </ListItem.Text>
+ </ListItem.Footer>
+ </ListItem>
+ );
+};
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
index 9c861008d1..e1c63261fe 100644
--- 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
@@ -1,17 +1,25 @@
import { useCallback } from 'react';
import { messages } from '../../../../../shared/gettext';
+import { Icon } from '../../../../lib/components';
+import { ListItem } from '../../../../lib/components/list-item';
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>
+ <ListItem>
+ <ListItem.Item>
+ <ListItem.Trigger onClick={navigate}>
+ <ListItem.Content>
+ <ListItem.Label>{messages.pgettext('settings-view', 'What’s new')}</ListItem.Label>
+ <Icon icon="chevron-right" />
+ </ListItem.Content>
+ </ListItem.Trigger>
+ </ListItem.Item>
+ </ListItem>
);
}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/UpdateAvailableListItem.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/UpdateAvailableListItem.tsx
new file mode 100644
index 0000000000..f8b6439f0a
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/UpdateAvailableListItem.tsx
@@ -0,0 +1,45 @@
+import { useCallback } from 'react';
+import styled from 'styled-components';
+
+import { messages } from '../../../../../shared/gettext';
+import { Flex, Icon } from '../../../../lib/components';
+import { Dot } from '../../../../lib/components/dot';
+import { ListItem } from '../../../../lib/components/list-item';
+import { useHistory } from '../../../../lib/history';
+import { RoutePath } from '../../../../lib/routes';
+import { useSelector } from '../../../../redux/store';
+
+const StyledText = styled(ListItem.Text)`
+ margin-top: -4px;
+`;
+
+export const UpdateAvailableListItem = () => {
+ const suggestedUpgrade = useSelector((state) => state.version.suggestedUpgrade);
+ const isOffline = useSelector((state) => state.connection.isBlocked);
+ const history = useHistory();
+ // TODO: Change to in app upgrade view
+ const navigate = useCallback(() => history.push(RoutePath.account), [history]);
+
+ return (
+ <>
+ <ListItem disabled={isOffline}>
+ <ListItem.Item>
+ <ListItem.Trigger onClick={navigate}>
+ <ListItem.Content>
+ <Flex $flexDirection="column">
+ <ListItem.Label>
+ {messages.pgettext('app-info-view', 'Update available')}
+ </ListItem.Label>
+ <StyledText variant="footnoteMini">{suggestedUpgrade}</StyledText>
+ </Flex>
+ <ListItem.Group>
+ <Dot variant="warning" size="small" />
+ <Icon icon="chevron-right" />
+ </ListItem.Group>
+ </ListItem.Content>
+ </ListItem.Trigger>
+ </ListItem.Item>
+ </ListItem>
+ </>
+ );
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/VersionListItem.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/VersionListItem.tsx
new file mode 100644
index 0000000000..bacfa7899a
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/VersionListItem.tsx
@@ -0,0 +1,41 @@
+import { messages } from '../../../../../shared/gettext';
+import { Box, Icon } from '../../../../lib/components';
+import { ListItem } from '../../../../lib/components/list-item';
+import { Colors } from '../../../../lib/foundations';
+import { useSelector } from '../../../../redux/store';
+
+export const VersionListItem = () => {
+ const appVersion = useSelector((state) => state.version.current);
+ const consistentVersion = useSelector((state) => state.version.consistent);
+
+ return (
+ <ListItem>
+ <ListItem.Item>
+ <ListItem.Content>
+ <ListItem.Group>
+ {!consistentVersion && <Icon icon="alert-circle" color={Colors.red} />}
+ <ListItem.Label>
+ {
+ // TRANSLATORS: Label for version list item.
+ messages.pgettext('app-info-view', 'Version')
+ }
+ </ListItem.Label>
+ </ListItem.Group>
+ <Box $width="24px" $height="24px" center>
+ <ListItem.Text>{appVersion}</ListItem.Text>
+ </Box>
+ </ListItem.Content>
+ </ListItem.Item>
+ {!consistentVersion && (
+ <ListItem.Footer>
+ <ListItem.Text>
+ {
+ // TRANSLATORS: Description for version list item when app is out of sync.
+ messages.pgettext('app-info-view', 'App is out of sync. Please quit and restart.')
+ }
+ </ListItem.Text>
+ </ListItem.Footer>
+ )}
+ </ListItem>
+ );
+};
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
index 905bc45397..1c7dcc318c 100644
--- 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
@@ -1,2 +1,3 @@
-export * from './AppVersionListItem';
+export * from './VersionListItem';
export * from './ChangelogListItem';
+export * from './UpdateAvailableListItem';