138 lines
4.2 KiB
TypeScript
138 lines
4.2 KiB
TypeScript
// components/UpdatePrompt.tsx
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// Modal that appears when a newer build is available.
|
|
// "Update now" opens the Gitea release page in the browser.
|
|
// "Later" dismisses it for the current session (it reappears next launch).
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
import React from 'react';
|
|
import {
|
|
Linking,
|
|
Modal,
|
|
Pressable,
|
|
StyleSheet,
|
|
Text,
|
|
View,
|
|
} from 'react-native';
|
|
import type { UpdateInfo } from '../hooks/useUpdatecheck';
|
|
import { version as currentVersion } from '../version.json';
|
|
|
|
interface Props {
|
|
updateInfo: UpdateInfo;
|
|
onDismiss: () => void;
|
|
}
|
|
|
|
export function UpdatePrompt({ updateInfo, onDismiss }: Props) {
|
|
function openRelease() {
|
|
Linking.openURL(updateInfo.releaseUrl).catch(() => {
|
|
// If the device can't open the URL, just dismiss so the app isn't stuck.
|
|
onDismiss();
|
|
});
|
|
}
|
|
|
|
return (
|
|
<Modal
|
|
visible
|
|
transparent
|
|
animationType="fade"
|
|
onRequestClose={onDismiss}
|
|
>
|
|
<View style={styles.overlay}>
|
|
<View style={styles.card}>
|
|
<Text style={styles.title}>Update available</Text>
|
|
|
|
<Text style={styles.body}>
|
|
A new version of the app is available.{'\n'}
|
|
You are on build <Text style={styles.bold}>{currentVersion}</Text>,
|
|
the latest is build{' '}
|
|
<Text style={styles.bold}>{updateInfo.latestVersion}</Text>.
|
|
</Text>
|
|
|
|
<View style={styles.actions}>
|
|
<Pressable
|
|
style={[styles.btn, styles.btnSecondary]}
|
|
onPress={onDismiss}
|
|
accessibilityRole="button"
|
|
accessibilityLabel="Remind me later"
|
|
>
|
|
<Text style={styles.btnSecondaryText}>Later</Text>
|
|
</Pressable>
|
|
|
|
<Pressable
|
|
style={[styles.btn, styles.btnPrimary]}
|
|
onPress={openRelease}
|
|
accessibilityRole="button"
|
|
accessibilityLabel="Open the release page to update"
|
|
>
|
|
<Text style={styles.btnPrimaryText}>Update now</Text>
|
|
</Pressable>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</Modal>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
overlay: {
|
|
flex: 1,
|
|
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
padding: 24,
|
|
},
|
|
card: {
|
|
width: '100%',
|
|
maxWidth: 380,
|
|
backgroundColor: '#fff',
|
|
borderRadius: 12,
|
|
padding: 24,
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: 4 },
|
|
shadowOpacity: 0.15,
|
|
shadowRadius: 12,
|
|
elevation: 8,
|
|
},
|
|
title: {
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
color: '#111',
|
|
marginBottom: 12,
|
|
},
|
|
body: {
|
|
fontSize: 15,
|
|
color: '#444',
|
|
lineHeight: 22,
|
|
marginBottom: 24,
|
|
},
|
|
bold: {
|
|
fontWeight: '700',
|
|
color: '#111',
|
|
},
|
|
actions: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'flex-end',
|
|
gap: 12,
|
|
},
|
|
btn: {
|
|
paddingVertical: 10,
|
|
paddingHorizontal: 20,
|
|
borderRadius: 8,
|
|
},
|
|
btnPrimary: {
|
|
backgroundColor: '#2563EB',
|
|
},
|
|
btnPrimaryText: {
|
|
color: '#fff',
|
|
fontWeight: '600',
|
|
fontSize: 15,
|
|
},
|
|
btnSecondary: {
|
|
backgroundColor: '#F3F4F6',
|
|
},
|
|
btnSecondaryText: {
|
|
color: '#374151',
|
|
fontWeight: '600',
|
|
fontSize: 15,
|
|
},
|
|
}); |