Skip to content

Commit 2b17fed

Browse files
Merge pull request #19 from OpenDTU-App/in-app-update-notes
2 parents 2ddda23 + e3a0b0b commit 2b17fed

File tree

21 files changed

+424
-81
lines changed

21 files changed

+424
-81
lines changed

android/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ android {
8080
setProperty("archivesBaseName", "OpenDTUApp")
8181
minSdkVersion rootProject.ext.minSdkVersion
8282
targetSdkVersion rootProject.ext.targetSdkVersion
83-
versionCode 6
84-
versionName "0.1.8"
83+
versionCode 7
84+
versionName "0.1.9"
8585
}
8686
signingConfigs {
8787
debug {

ios/opendtureactnative/Info.plist

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
<key>CFBundlePackageType</key>
1818
<string>APPL</string>
1919
<key>CFBundleShortVersionString</key>
20-
<string>0.1.8</string>
20+
<string>0.1.9</string>
2121
<key>CFBundleSignature</key>
2222
<string>????</string>
2323
<key>CFBundleVersion</key>
24-
<string>5</string>
24+
<string>7</string>
2525
<key>LSRequiresIPhoneOS</key>
2626
<true />
2727
<key>NSAppTransportSecurity</key>

ios/opendtureactnativeTests/Info.plist

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
<key>CFBundlePackageType</key>
1616
<string>BNDL</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>0.1.8</string>
18+
<string>0.1.9</string>
1919
<key>CFBundleSignature</key>
2020
<string>????</string>
2121
<key>CFBundleVersion</key>
22-
<string>6</string>
22+
<string>7</string>
2323
</dict>
2424
</plist>

licenses.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@
154154
"licenseUrl": "https://github.com/onubo/react-native-logs/raw/master/LICENSE",
155155
"parents": "opendtu-react-native"
156156
},
157-
"[email protected].0-alpha.2": {
157+
158158
"licenses": "MIT",
159159
"repository": "https://github.com/iamacup/react-native-markdown-display",
160160
"licenseUrl": "https://github.com/iamacup/react-native-markdown-display/raw/master/LICENSE",

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "opendtu-react-native",
3-
"version": "0.1.8",
3+
"version": "0.1.9",
44
"private": true,
55
"repository": {
66
"type": "git",
@@ -52,7 +52,7 @@
5252
"react-native-get-random-values": "^1.9.0",
5353
"react-native-linear-gradient": "^2.8.3",
5454
"react-native-logs": "^5.0.1",
55-
"react-native-markdown-display": "^7.0.0-alpha.2",
55+
"react-native-markdown-display": "^7.0.2",
5656
"react-native-paper": "^5.11.2",
5757
"react-native-paper-dates": "^0.20.4",
5858
"react-native-reanimated": "^3.5.4",

src/App.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { SafeAreaProvider } from 'react-native-safe-area-context';
1414
import SplashScreen from 'react-native-splash-screen';
1515
import { Provider as ReduxProvider } from 'react-redux';
1616

17+
import EnableAppUpdatesModal from '@/components/modals/EnableAppUpdatesModal';
18+
1719
import ApiProvider from '@/api/ApiHandler';
1820
import DatabaseProvider from '@/database';
1921
import GithubProvider from '@/github';
@@ -231,6 +233,10 @@ const _App: FC = () => {
231233
});
232234
}, [i18n.language, t]);
233235

236+
const showEnableAppUpdatesModal = useAppSelector(
237+
state => state.settings.enableAppUpdates === null,
238+
);
239+
234240
if (!i18nLanguageMatchesSettings) {
235241
return null;
236242
}
@@ -245,6 +251,13 @@ const _App: FC = () => {
245251
<NavigationContainer theme={navigationTheme}>
246252
<NavigationStack />
247253
</NavigationContainer>
254+
<EnableAppUpdatesModal
255+
visible={showEnableAppUpdatesModal}
256+
/* eslint-disable-next-line @typescript-eslint/no-empty-function */
257+
onDismiss={() => {}}
258+
dismissable={false}
259+
dismissableBackButton={false}
260+
/>
248261
</PaperProvider>
249262
);
250263
};
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import type { FC } from 'react';
2+
import { useCallback } from 'react';
3+
import { useTranslation } from 'react-i18next';
4+
import { Box } from 'react-native-flex-layout';
5+
import type { ModalProps } from 'react-native-paper';
6+
import { Button, Portal, Text } from 'react-native-paper';
7+
8+
import { setEnableAppUpdates } from '@/slices/settings';
9+
10+
import BaseModal from '@/components/BaseModal';
11+
12+
import { useAppDispatch } from '@/store';
13+
14+
const EnableAppUpdatesModal: FC<Omit<ModalProps, 'children'>> = props => {
15+
const { onDismiss } = props;
16+
const { t } = useTranslation();
17+
const dispatch = useAppDispatch();
18+
19+
const handleAbort = useCallback(() => {
20+
onDismiss?.();
21+
}, [onDismiss]);
22+
23+
const handleEnable = useCallback(() => {
24+
console.log('handleEnable');
25+
dispatch(setEnableAppUpdates({ enable: true }));
26+
handleAbort();
27+
}, [dispatch, handleAbort]);
28+
29+
const handleDisable = useCallback(() => {
30+
dispatch(setEnableAppUpdates({ enable: false }));
31+
handleAbort();
32+
}, [dispatch, handleAbort]);
33+
34+
return (
35+
<Portal>
36+
<BaseModal {...props}>
37+
<Box p={16}>
38+
<Box mb={8}>
39+
<Text variant="bodyLarge">
40+
{t('settings.doYouWantToEnableAppUpdates')}
41+
</Text>
42+
</Box>
43+
</Box>
44+
<Box
45+
style={{
46+
flexDirection: 'row',
47+
justifyContent: 'flex-end',
48+
alignItems: 'center',
49+
padding: 8,
50+
}}
51+
>
52+
<Button
53+
style={{ marginRight: 8 }}
54+
onPress={handleEnable}
55+
mode="contained"
56+
>
57+
{t('enable')}
58+
</Button>
59+
<Button onPress={handleDisable} mode="text">
60+
{t('disable')}
61+
</Button>
62+
</Box>
63+
</BaseModal>
64+
</Portal>
65+
);
66+
};
67+
68+
export default EnableAppUpdatesModal;

src/github/FetchHandler.tsx

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,19 @@ import type { Release } from '@octokit/webhooks-types';
33
import type { FC } from 'react';
44
import { useEffect } from 'react';
55

6-
import { setLatestRelease, setReleases } from '@/slices/github';
6+
import {
7+
setLatestAppRelease,
8+
setLatestRelease,
9+
setReleases,
10+
} from '@/slices/github';
711

812
import ago from '@/utils/ago';
913

10-
import { GithubBaseConfig, useGithub } from '@/github/index';
14+
import {
15+
AppGithubBaseConfig,
16+
OpenDTUGithubBaseConfig,
17+
useGithub,
18+
} from '@/github/index';
1119
import { useAppDispatch, useAppSelector } from '@/store';
1220

1321
const FetchHandler: FC = () => {
@@ -26,6 +34,16 @@ const FetchHandler: FC = () => {
2634
: true,
2735
);
2836

37+
const latestAppReleaseRefetchOk = useAppSelector(state =>
38+
state.github.latestAppRelease.lastUpdate
39+
? ago(state.github.latestAppRelease.lastUpdate) > 1000 * 60 * 10 // 10 minutes
40+
: true,
41+
);
42+
43+
const enableAppUpdates = useAppSelector(
44+
state => !!state.settings.enableAppUpdates,
45+
);
46+
2947
const githubApi = useGithub();
3048

3149
useEffect(() => {
@@ -38,7 +56,7 @@ const FetchHandler: FC = () => {
3856
if (latestReleaseRefetchOk) {
3957
const latestRelease = await githubApi.request(
4058
'GET /repos/{owner}/{repo}/releases/latest',
41-
GithubBaseConfig,
59+
OpenDTUGithubBaseConfig,
4260
);
4361

4462
dispatch(setLatestRelease({ latest: latestRelease.data as Release }));
@@ -49,13 +67,24 @@ const FetchHandler: FC = () => {
4967
if (allReleasesRefetchOk) {
5068
const releases = await githubApi.request(
5169
'GET /repos/{owner}/{repo}/releases',
52-
GithubBaseConfig,
70+
OpenDTUGithubBaseConfig,
5371
);
5472

5573
dispatch(setReleases({ releases: releases.data as Release[] }));
5674
} else {
5775
console.log('SKIP allReleasesRefetchOk');
5876
}
77+
78+
if (latestAppReleaseRefetchOk && enableAppUpdates) {
79+
const appRelease = await githubApi.request(
80+
'GET /repos/{owner}/{repo}/releases/latest',
81+
AppGithubBaseConfig,
82+
);
83+
84+
dispatch(setLatestAppRelease({ latest: appRelease.data as Release }));
85+
} else {
86+
console.log('SKIP latestAppReleaseRefetchOk');
87+
}
5988
} catch (e) {
6089
console.warn('GITHUB FETCH ERROR', e);
6190
}
@@ -68,6 +97,8 @@ const FetchHandler: FC = () => {
6897
githubApi,
6998
latestReleaseRefetchOk,
7099
allReleasesRefetchOk,
100+
latestAppReleaseRefetchOk,
101+
enableAppUpdates,
71102
]);
72103

73104
return null;

src/github/index.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,22 @@ import { createContext, useContext, useMemo } from 'react';
55

66
export const GithubContext = createContext<Octokit | undefined>(undefined);
77

8-
export const GithubBaseConfig = {
8+
export const OpenDTUGithubBaseConfig = {
99
owner: 'tbnobody',
1010
repo: 'OpenDTU',
1111
headers: {
1212
'X-GitHub-Api-Version': '2022-11-28',
1313
},
1414
};
1515

16+
export const AppGithubBaseConfig = {
17+
owner: 'OpenDTU-App',
18+
repo: 'opendtu-react-native',
19+
headers: {
20+
'X-GitHub-Api-Version': '2022-11-28',
21+
},
22+
};
23+
1624
export const GithubProvider: FC<PropsWithChildren<unknown>> = ({
1725
children,
1826
}) => {

src/hooks/useHasNewAppVersion.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import packageJson from '@root/package.json';
2+
import { compare } from 'compare-versions';
3+
4+
import { useMemo } from 'react';
5+
6+
import { useAppSelector } from '@/store';
7+
8+
const useHasNewAppVersion = (options?: { usedForIndicatorOnly: boolean }) => {
9+
const { usedForIndicatorOnly = false } = options ?? {};
10+
11+
const appRelease = useAppSelector(
12+
state => state.github.latestAppRelease?.data,
13+
);
14+
15+
const showIndicator = useAppSelector(
16+
state => !!state.settings.enableAppUpdates,
17+
);
18+
19+
return useMemo(() => {
20+
if (!appRelease) return [false, null] as const;
21+
22+
const newAppVersionAvailable = compare(
23+
appRelease?.tag_name,
24+
packageJson.version,
25+
'>',
26+
);
27+
28+
return [
29+
!showIndicator && usedForIndicatorOnly ? false : newAppVersionAvailable,
30+
appRelease,
31+
] as const;
32+
}, [appRelease, showIndicator, usedForIndicatorOnly]);
33+
};
34+
35+
export default useHasNewAppVersion;

0 commit comments

Comments
 (0)