mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-09 11:30:51 +00:00
toggle for tuning off update alerts
This commit is contained in:
parent
8c0b47975c
commit
78553d8323
3 changed files with 467 additions and 315 deletions
|
|
@ -26,6 +26,12 @@ export function useGithubMajorUpdate(): MajorUpdateData {
|
||||||
const check = useCallback(async () => {
|
const check = useCallback(async () => {
|
||||||
if (Platform.OS === 'ios') return;
|
if (Platform.OS === 'ios') return;
|
||||||
try {
|
try {
|
||||||
|
// Check if major update alerts are disabled
|
||||||
|
const majorAlertsEnabled = await mmkvStorage.getItem('@major_updates_alerts_enabled');
|
||||||
|
if (majorAlertsEnabled === 'false') {
|
||||||
|
return; // Major update alerts are disabled by user
|
||||||
|
}
|
||||||
|
|
||||||
// Always compare with Settings screen version
|
// Always compare with Settings screen version
|
||||||
const current = getDisplayedAppVersion() || Updates.runtimeVersion || '0.0.0';
|
const current = getDisplayedAppVersion() || Updates.runtimeVersion || '0.0.0';
|
||||||
const info = await fetchLatestGithubRelease();
|
const info = await fetchLatestGithubRelease();
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,11 @@ export const useUpdatePopup = (): UseUpdatePopupReturn => {
|
||||||
|
|
||||||
const checkForUpdates = useCallback(async (forceCheck = false) => {
|
const checkForUpdates = useCallback(async (forceCheck = false) => {
|
||||||
try {
|
try {
|
||||||
|
// Check if OTA update alerts are disabled
|
||||||
|
const otaAlertsEnabled = await mmkvStorage.getItem('@ota_updates_alerts_enabled');
|
||||||
|
if (otaAlertsEnabled === 'false' && !forceCheck) {
|
||||||
|
return; // OTA alerts are disabled by user
|
||||||
|
}
|
||||||
|
|
||||||
// Check if user has dismissed the popup for this version
|
// Check if user has dismissed the popup for this version
|
||||||
const dismissedVersion = await mmkvStorage.getItem(UPDATE_POPUP_STORAGE_KEY);
|
const dismissedVersion = await mmkvStorage.getItem(UPDATE_POPUP_STORAGE_KEY);
|
||||||
|
|
@ -66,9 +71,9 @@ export const useUpdatePopup = (): UseUpdatePopupReturn => {
|
||||||
try {
|
try {
|
||||||
setIsInstalling(true);
|
setIsInstalling(true);
|
||||||
setShowUpdatePopup(false);
|
setShowUpdatePopup(false);
|
||||||
|
|
||||||
const success = await UpdateService.downloadAndInstallUpdate();
|
const success = await UpdateService.downloadAndInstallUpdate();
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
// Update installed successfully - no restart alert needed
|
// Update installed successfully - no restart alert needed
|
||||||
// The app will automatically reload with the new version
|
// The app will automatically reload with the new version
|
||||||
|
|
@ -152,7 +157,7 @@ export const useUpdatePopup = (): UseUpdatePopupReturn => {
|
||||||
try {
|
try {
|
||||||
const dismissedVersion = await mmkvStorage.getItem(UPDATE_POPUP_STORAGE_KEY);
|
const dismissedVersion = await mmkvStorage.getItem(UPDATE_POPUP_STORAGE_KEY);
|
||||||
const currentVersion = updateInfo.manifest?.id;
|
const currentVersion = updateInfo.manifest?.id;
|
||||||
|
|
||||||
if (dismissedVersion !== currentVersion) {
|
if (dismissedVersion !== currentVersion) {
|
||||||
setShowUpdatePopup(true);
|
setShowUpdatePopup(true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ import {
|
||||||
StatusBar,
|
StatusBar,
|
||||||
Platform,
|
Platform,
|
||||||
Dimensions,
|
Dimensions,
|
||||||
Linking
|
Linking,
|
||||||
|
Switch
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { useToast } from '../contexts/ToastContext';
|
import { useToast } from '../contexts/ToastContext';
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
|
|
@ -37,9 +38,9 @@ interface SettingsCardProps {
|
||||||
|
|
||||||
const SettingsCard: React.FC<SettingsCardProps> = ({ children, title, isTablet = false }) => {
|
const SettingsCard: React.FC<SettingsCardProps> = ({ children, title, isTablet = false }) => {
|
||||||
const { currentTheme } = useTheme();
|
const { currentTheme } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
styles.cardContainer,
|
styles.cardContainer,
|
||||||
isTablet && styles.tabletCardContainer
|
isTablet && styles.tabletCardContainer
|
||||||
|
|
@ -111,19 +112,84 @@ const UpdateScreen: React.FC = () => {
|
||||||
const [updateProgress, setUpdateProgress] = useState<number>(0);
|
const [updateProgress, setUpdateProgress] = useState<number>(0);
|
||||||
const [updateStatus, setUpdateStatus] = useState<'idle' | 'checking' | 'available' | 'downloading' | 'installing' | 'success' | 'error'>('idle');
|
const [updateStatus, setUpdateStatus] = useState<'idle' | 'checking' | 'available' | 'downloading' | 'installing' | 'success' | 'error'>('idle');
|
||||||
|
|
||||||
|
// Update notification settings
|
||||||
|
const [otaAlertsEnabled, setOtaAlertsEnabled] = useState(true);
|
||||||
|
const [majorAlertsEnabled, setMajorAlertsEnabled] = useState(true);
|
||||||
|
|
||||||
|
// Load notification settings on mount
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const otaSetting = await mmkvStorage.getItem('@ota_updates_alerts_enabled');
|
||||||
|
const majorSetting = await mmkvStorage.getItem('@major_updates_alerts_enabled');
|
||||||
|
// Default to true if not set
|
||||||
|
setOtaAlertsEnabled(otaSetting !== 'false');
|
||||||
|
setMajorAlertsEnabled(majorSetting !== 'false');
|
||||||
|
} catch { }
|
||||||
|
})();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Handle toggling OTA alerts with warning
|
||||||
|
const handleOtaAlertsToggle = async (value: boolean) => {
|
||||||
|
if (!value) {
|
||||||
|
openAlert(
|
||||||
|
'Disable OTA Update Alerts?',
|
||||||
|
'You will no longer receive automatic notifications for OTA updates.\n\n⚠️ Warning: Staying on the latest version is important for:\n• Bug fixes and stability improvements\n• New features and enhancements\n• Providing accurate feedback and crash reports\n\nYou can still manually check for updates in this screen.',
|
||||||
|
[
|
||||||
|
{ label: 'Cancel', onPress: () => setAlertVisible(false) },
|
||||||
|
{
|
||||||
|
label: 'Disable',
|
||||||
|
onPress: async () => {
|
||||||
|
await mmkvStorage.setItem('@ota_updates_alerts_enabled', 'false');
|
||||||
|
setOtaAlertsEnabled(false);
|
||||||
|
setAlertVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await mmkvStorage.setItem('@ota_updates_alerts_enabled', 'true');
|
||||||
|
setOtaAlertsEnabled(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle toggling Major update alerts with warning
|
||||||
|
const handleMajorAlertsToggle = async (value: boolean) => {
|
||||||
|
if (!value) {
|
||||||
|
openAlert(
|
||||||
|
'Disable Major Update Alerts?',
|
||||||
|
'You will no longer receive notifications for major app updates that require reinstallation.\n\n⚠️ Warning: Major updates often include:\n• Critical security patches\n• Breaking changes that require app reinstall\n• Important compatibility fixes\n\nYou can still check for updates manually.',
|
||||||
|
[
|
||||||
|
{ label: 'Cancel', onPress: () => setAlertVisible(false) },
|
||||||
|
{
|
||||||
|
label: 'Disable',
|
||||||
|
onPress: async () => {
|
||||||
|
await mmkvStorage.setItem('@major_updates_alerts_enabled', 'false');
|
||||||
|
setMajorAlertsEnabled(false);
|
||||||
|
setAlertVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await mmkvStorage.setItem('@major_updates_alerts_enabled', 'true');
|
||||||
|
setMajorAlertsEnabled(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const checkForUpdates = async () => {
|
const checkForUpdates = async () => {
|
||||||
try {
|
try {
|
||||||
setIsChecking(true);
|
setIsChecking(true);
|
||||||
setUpdateStatus('checking');
|
setUpdateStatus('checking');
|
||||||
setUpdateProgress(0);
|
setUpdateProgress(0);
|
||||||
setLastOperation('Checking for updates...');
|
setLastOperation('Checking for updates...');
|
||||||
|
|
||||||
const info = await UpdateService.checkForUpdates();
|
const info = await UpdateService.checkForUpdates();
|
||||||
setUpdateInfo(info);
|
setUpdateInfo(info);
|
||||||
setLastChecked(new Date());
|
setLastChecked(new Date());
|
||||||
|
|
||||||
// Logs disabled
|
// Logs disabled
|
||||||
|
|
||||||
if (info.isAvailable) {
|
if (info.isAvailable) {
|
||||||
setUpdateStatus('available');
|
setUpdateStatus('available');
|
||||||
setLastOperation(`Update available: ${info.manifest?.id || 'unknown'}`);
|
setLastOperation(`Update available: ${info.manifest?.id || 'unknown'}`);
|
||||||
|
|
@ -135,7 +201,7 @@ const UpdateScreen: React.FC = () => {
|
||||||
if (__DEV__) console.error('Error checking for updates:', error);
|
if (__DEV__) console.error('Error checking for updates:', error);
|
||||||
setUpdateStatus('error');
|
setUpdateStatus('error');
|
||||||
setLastOperation(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
setLastOperation(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||||
openAlert('Error', 'Failed to check for updates');
|
openAlert('Error', 'Failed to check for updates');
|
||||||
} finally {
|
} finally {
|
||||||
setIsChecking(false);
|
setIsChecking(false);
|
||||||
}
|
}
|
||||||
|
|
@ -146,12 +212,12 @@ const UpdateScreen: React.FC = () => {
|
||||||
if (Platform.OS === 'android') {
|
if (Platform.OS === 'android') {
|
||||||
// ensure badge clears when entering this screen
|
// ensure badge clears when entering this screen
|
||||||
(async () => {
|
(async () => {
|
||||||
try { await mmkvStorage.removeItem('@update_badge_pending'); } catch {}
|
try { await mmkvStorage.removeItem('@update_badge_pending'); } catch { }
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
checkForUpdates();
|
checkForUpdates();
|
||||||
// Also refresh GitHub section on mount (works in dev and prod)
|
// Also refresh GitHub section on mount (works in dev and prod)
|
||||||
try { github.refresh(); } catch {}
|
try { github.refresh(); } catch { }
|
||||||
if (Platform.OS === 'android') {
|
if (Platform.OS === 'android') {
|
||||||
showInfo('Checking for Updates', 'Checking for updates…');
|
showInfo('Checking for Updates', 'Checking for updates…');
|
||||||
}
|
}
|
||||||
|
|
@ -163,7 +229,7 @@ const UpdateScreen: React.FC = () => {
|
||||||
setUpdateStatus('downloading');
|
setUpdateStatus('downloading');
|
||||||
setUpdateProgress(0);
|
setUpdateProgress(0);
|
||||||
setLastOperation('Downloading update...');
|
setLastOperation('Downloading update...');
|
||||||
|
|
||||||
// Simulate progress updates
|
// Simulate progress updates
|
||||||
const progressInterval = setInterval(() => {
|
const progressInterval = setInterval(() => {
|
||||||
setUpdateProgress(prev => {
|
setUpdateProgress(prev => {
|
||||||
|
|
@ -171,30 +237,30 @@ const UpdateScreen: React.FC = () => {
|
||||||
return prev + Math.random() * 10;
|
return prev + Math.random() * 10;
|
||||||
});
|
});
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
const success = await UpdateService.downloadAndInstallUpdate();
|
const success = await UpdateService.downloadAndInstallUpdate();
|
||||||
|
|
||||||
clearInterval(progressInterval);
|
clearInterval(progressInterval);
|
||||||
setUpdateProgress(100);
|
setUpdateProgress(100);
|
||||||
setUpdateStatus('installing');
|
setUpdateStatus('installing');
|
||||||
setLastOperation('Installing update...');
|
setLastOperation('Installing update...');
|
||||||
|
|
||||||
// Logs disabled
|
// Logs disabled
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
setUpdateStatus('success');
|
setUpdateStatus('success');
|
||||||
setLastOperation('Update installed successfully');
|
setLastOperation('Update installed successfully');
|
||||||
openAlert('Success', 'Update will be applied on next app restart');
|
openAlert('Success', 'Update will be applied on next app restart');
|
||||||
} else {
|
} else {
|
||||||
setUpdateStatus('error');
|
setUpdateStatus('error');
|
||||||
setLastOperation('No update available to install');
|
setLastOperation('No update available to install');
|
||||||
openAlert('No Update', 'No update available to install');
|
openAlert('No Update', 'No update available to install');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (__DEV__) console.error('Error installing update:', error);
|
if (__DEV__) console.error('Error installing update:', error);
|
||||||
setUpdateStatus('error');
|
setUpdateStatus('error');
|
||||||
setLastOperation(`Installation error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
setLastOperation(`Installation error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||||
openAlert('Error', 'Failed to install update');
|
openAlert('Error', 'Failed to install update');
|
||||||
} finally {
|
} finally {
|
||||||
setIsInstalling(false);
|
setIsInstalling(false);
|
||||||
}
|
}
|
||||||
|
|
@ -236,7 +302,7 @@ const UpdateScreen: React.FC = () => {
|
||||||
try {
|
try {
|
||||||
setLastOperation('Testing connectivity...');
|
setLastOperation('Testing connectivity...');
|
||||||
const isReachable = await UpdateService.testUpdateConnectivity();
|
const isReachable = await UpdateService.testUpdateConnectivity();
|
||||||
|
|
||||||
if (isReachable) {
|
if (isReachable) {
|
||||||
setLastOperation('Update server is reachable');
|
setLastOperation('Update server is reachable');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -334,7 +400,7 @@ const UpdateScreen: React.FC = () => {
|
||||||
{ backgroundColor: currentTheme.colors.darkBackground }
|
{ backgroundColor: currentTheme.colors.darkBackground }
|
||||||
]}>
|
]}>
|
||||||
<StatusBar barStyle="light-content" />
|
<StatusBar barStyle="light-content" />
|
||||||
|
|
||||||
<View style={styles.header}>
|
<View style={styles.header}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.backButton}
|
style={styles.backButton}
|
||||||
|
|
@ -346,316 +412,367 @@ const UpdateScreen: React.FC = () => {
|
||||||
Settings
|
Settings
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
<View style={styles.headerActions}>
|
<View style={styles.headerActions}>
|
||||||
{/* Empty for now, but ready for future actions */}
|
{/* Empty for now, but ready for future actions */}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Text style={[styles.headerTitle, { color: currentTheme.colors.text }]}>
|
<Text style={[styles.headerTitle, { color: currentTheme.colors.text }]}>
|
||||||
App Updates
|
App Updates
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<View style={styles.contentContainer}>
|
<View style={styles.contentContainer}>
|
||||||
<ScrollView
|
<ScrollView
|
||||||
style={styles.scrollView}
|
style={styles.scrollView}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
contentContainerStyle={styles.scrollContent}
|
contentContainerStyle={styles.scrollContent}
|
||||||
>
|
>
|
||||||
<SettingsCard title="APP UPDATES" isTablet={isTablet}>
|
<SettingsCard title="APP UPDATES" isTablet={isTablet}>
|
||||||
{/* Main Update Card */}
|
{/* Main Update Card */}
|
||||||
<View style={styles.updateMainCard}>
|
<View style={styles.updateMainCard}>
|
||||||
{/* Status Section */}
|
{/* Status Section */}
|
||||||
<View style={styles.updateStatusSection}>
|
<View style={styles.updateStatusSection}>
|
||||||
<View style={[styles.statusIndicator, { backgroundColor: `${getStatusColor()}20` }]}>
|
<View style={[styles.statusIndicator, { backgroundColor: `${getStatusColor()}20` }]}>
|
||||||
{getStatusIcon()}
|
{getStatusIcon()}
|
||||||
</View>
|
|
||||||
<View style={styles.statusContent}>
|
|
||||||
<Text style={[styles.statusMainText, { color: currentTheme.colors.highEmphasis }]}>
|
|
||||||
{getStatusText()}
|
|
||||||
</Text>
|
|
||||||
<Text style={[styles.statusDetailText, { color: currentTheme.colors.mediumEmphasis }]}>
|
|
||||||
{lastOperation || 'Ready to check for updates'}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
|
<View style={styles.statusContent}>
|
||||||
{/* Progress Section */}
|
<Text style={[styles.statusMainText, { color: currentTheme.colors.highEmphasis }]}>
|
||||||
{(updateStatus === 'downloading' || updateStatus === 'installing') && (
|
{getStatusText()}
|
||||||
<View style={styles.progressSection}>
|
</Text>
|
||||||
<View style={styles.progressHeader}>
|
<Text style={[styles.statusDetailText, { color: currentTheme.colors.mediumEmphasis }]}>
|
||||||
<Text style={[styles.progressLabel, { color: currentTheme.colors.mediumEmphasis }]}>
|
{lastOperation || 'Ready to check for updates'}
|
||||||
{updateStatus === 'downloading' ? 'Downloading' : 'Installing'}
|
</Text>
|
||||||
</Text>
|
|
||||||
<Text style={[styles.progressPercentage, { color: currentTheme.colors.primary }]}>
|
|
||||||
{Math.round(updateProgress)}%
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<View style={[styles.modernProgressBar, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
styles.modernProgressFill,
|
|
||||||
{
|
|
||||||
backgroundColor: currentTheme.colors.primary,
|
|
||||||
width: `${updateProgress}%`
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Action Section */}
|
|
||||||
<View style={styles.actionSection}>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[
|
|
||||||
styles.modernButton,
|
|
||||||
styles.primaryAction,
|
|
||||||
{ backgroundColor: currentTheme.colors.primary },
|
|
||||||
(isChecking || isInstalling) && styles.disabledAction
|
|
||||||
]}
|
|
||||||
onPress={checkForUpdates}
|
|
||||||
disabled={isChecking || isInstalling}
|
|
||||||
activeOpacity={0.8}
|
|
||||||
>
|
|
||||||
{isChecking ? (
|
|
||||||
<MaterialIcons name="refresh" size={18} color="white" />
|
|
||||||
) : (
|
|
||||||
<MaterialIcons name="system-update" size={18} color="white" />
|
|
||||||
)}
|
|
||||||
<Text style={styles.modernButtonText}>
|
|
||||||
{isChecking ? 'Checking...' : 'Check for Updates'}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
|
|
||||||
{updateInfo?.isAvailable && updateStatus !== 'success' && (
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[
|
|
||||||
styles.modernButton,
|
|
||||||
styles.installAction,
|
|
||||||
{ backgroundColor: currentTheme.colors.success || '#34C759' },
|
|
||||||
(isInstalling) && styles.disabledAction
|
|
||||||
]}
|
|
||||||
onPress={installUpdate}
|
|
||||||
disabled={isInstalling}
|
|
||||||
activeOpacity={0.8}
|
|
||||||
>
|
|
||||||
{isInstalling ? (
|
|
||||||
<MaterialIcons name="install-mobile" size={18} color="white" />
|
|
||||||
) : (
|
|
||||||
<MaterialIcons name="download" size={18} color="white" />
|
|
||||||
)}
|
|
||||||
<Text style={styles.modernButtonText}>
|
|
||||||
{isInstalling ? 'Installing...' : 'Install Update'}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Release Notes */}
|
{/* Progress Section */}
|
||||||
{updateInfo?.isAvailable && !!getReleaseNotes() && (
|
{(updateStatus === 'downloading' || updateStatus === 'installing') && (
|
||||||
<View style={styles.infoSection}>
|
<View style={styles.progressSection}>
|
||||||
<View style={styles.infoItem}>
|
<View style={styles.progressHeader}>
|
||||||
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
<Text style={[styles.progressLabel, { color: currentTheme.colors.mediumEmphasis }]}>
|
||||||
<MaterialIcons name="notes" size={14} color={currentTheme.colors.primary} />
|
{updateStatus === 'downloading' ? 'Downloading' : 'Installing'}
|
||||||
</View>
|
</Text>
|
||||||
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Release notes:</Text>
|
<Text style={[styles.progressPercentage, { color: currentTheme.colors.primary }]}>
|
||||||
|
{Math.round(updateProgress)}%
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[styles.modernProgressBar, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.modernProgressFill,
|
||||||
|
{
|
||||||
|
backgroundColor: currentTheme.colors.primary,
|
||||||
|
width: `${updateProgress}%`
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>{getReleaseNotes()}</Text>
|
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Info Section */}
|
{/* Action Section */}
|
||||||
<View style={styles.infoSection}>
|
<View style={styles.actionSection}>
|
||||||
<View style={styles.infoItem}>
|
<TouchableOpacity
|
||||||
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
style={[
|
||||||
<MaterialIcons name="info-outline" size={14} color={currentTheme.colors.primary} />
|
styles.modernButton,
|
||||||
</View>
|
styles.primaryAction,
|
||||||
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Version:</Text>
|
{ backgroundColor: currentTheme.colors.primary },
|
||||||
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>
|
(isChecking || isInstalling) && styles.disabledAction
|
||||||
{updateInfo?.manifest?.id ? `${updateInfo.manifest.id.substring(0, 8)}...` : 'Unknown'}
|
]}
|
||||||
|
onPress={checkForUpdates}
|
||||||
|
disabled={isChecking || isInstalling}
|
||||||
|
activeOpacity={0.8}
|
||||||
|
>
|
||||||
|
{isChecking ? (
|
||||||
|
<MaterialIcons name="refresh" size={18} color="white" />
|
||||||
|
) : (
|
||||||
|
<MaterialIcons name="system-update" size={18} color="white" />
|
||||||
|
)}
|
||||||
|
<Text style={styles.modernButtonText}>
|
||||||
|
{isChecking ? 'Checking...' : 'Check for Updates'}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</TouchableOpacity>
|
||||||
|
|
||||||
{lastChecked && (
|
|
||||||
<View style={styles.infoItem}>
|
|
||||||
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
|
||||||
<MaterialIcons name="schedule" size={14} color={currentTheme.colors.primary} />
|
|
||||||
</View>
|
|
||||||
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Last checked:</Text>
|
|
||||||
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>
|
|
||||||
{formatDate(lastChecked)}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Current Version Section */}
|
{updateInfo?.isAvailable && updateStatus !== 'success' && (
|
||||||
<View style={styles.infoSection}>
|
<TouchableOpacity
|
||||||
<View style={styles.infoItem}>
|
style={[
|
||||||
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
styles.modernButton,
|
||||||
<MaterialIcons name="verified" size={14} color={currentTheme.colors.primary} />
|
styles.installAction,
|
||||||
</View>
|
{ backgroundColor: currentTheme.colors.success || '#34C759' },
|
||||||
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Current version:</Text>
|
(isInstalling) && styles.disabledAction
|
||||||
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}
|
]}
|
||||||
selectable>
|
onPress={installUpdate}
|
||||||
{currentInfo?.manifest?.id || (currentInfo?.isEmbeddedLaunch === false ? 'Unknown' : 'Embedded')}
|
disabled={isInstalling}
|
||||||
</Text>
|
activeOpacity={0.8}
|
||||||
</View>
|
|
||||||
|
|
||||||
{!!getCurrentReleaseNotes() && (
|
|
||||||
<View style={{ marginTop: 8 }}>
|
|
||||||
<View style={[styles.infoItem, { alignItems: 'flex-start' }]}>
|
|
||||||
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
|
||||||
<MaterialIcons name="notes" size={14} color={currentTheme.colors.primary} />
|
|
||||||
</View>
|
|
||||||
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Current release notes:</Text>
|
|
||||||
</View>
|
|
||||||
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>
|
|
||||||
{getCurrentReleaseNotes()}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Developer Logs removed */}
|
|
||||||
</SettingsCard>
|
|
||||||
|
|
||||||
{/* GitHub Release (compact) – only show when update is available */}
|
|
||||||
{github.latestTag && isAnyUpgrade(getDisplayedAppVersion(), github.latestTag) ? (
|
|
||||||
<SettingsCard title="GITHUB RELEASE" isTablet={isTablet}>
|
|
||||||
<View style={styles.infoSection}>
|
|
||||||
<View style={styles.infoItem}>
|
|
||||||
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
|
||||||
<MaterialIcons name="new-releases" size={14} color={currentTheme.colors.primary} />
|
|
||||||
</View>
|
|
||||||
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Current:</Text>
|
|
||||||
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>
|
|
||||||
{getDisplayedAppVersion()}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.infoItem}>
|
|
||||||
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
|
||||||
<MaterialIcons name="tag" size={14} color={currentTheme.colors.primary} />
|
|
||||||
</View>
|
|
||||||
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Latest:</Text>
|
|
||||||
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>
|
|
||||||
{github.latestTag}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{github.releaseNotes ? (
|
|
||||||
<View style={{ marginTop: 4 }}>
|
|
||||||
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Notes:</Text>
|
|
||||||
<Text
|
|
||||||
numberOfLines={3}
|
|
||||||
style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}
|
|
||||||
>
|
|
||||||
{github.releaseNotes}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<View style={[styles.actionSection, { marginTop: 8 }]}>
|
|
||||||
<View style={{ flexDirection: 'row', gap: 10 }}>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[styles.modernButton, { backgroundColor: currentTheme.colors.primary, flex: 1 }]}
|
|
||||||
onPress={() => github.releaseUrl ? Linking.openURL(github.releaseUrl as string) : null}
|
|
||||||
activeOpacity={0.8}
|
|
||||||
>
|
|
||||||
<MaterialIcons name="open-in-new" size={18} color="white" />
|
|
||||||
<Text style={styles.modernButtonText}>View Release</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</SettingsCard>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{false && (
|
|
||||||
<SettingsCard title="UPDATE LOGS" isTablet={isTablet}>
|
|
||||||
<View style={styles.logsContainer}>
|
|
||||||
<View style={styles.logsHeader}>
|
|
||||||
<Text style={[styles.logsHeaderText, { color: currentTheme.colors.highEmphasis }]}>
|
|
||||||
Update Service Logs
|
|
||||||
</Text>
|
|
||||||
<View style={styles.logsActions}>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[styles.logActionButton, { backgroundColor: currentTheme.colors.elevation2 }]}
|
|
||||||
onPress={testConnectivity}
|
|
||||||
activeOpacity={0.7}
|
|
||||||
>
|
|
||||||
<MaterialIcons name="wifi" size={16} color={currentTheme.colors.primary} />
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[styles.logActionButton, { backgroundColor: currentTheme.colors.elevation2 }]}
|
|
||||||
onPress={testAssetUrls}
|
|
||||||
activeOpacity={0.7}
|
|
||||||
>
|
|
||||||
<MaterialIcons name="link" size={16} color={currentTheme.colors.primary} />
|
|
||||||
</TouchableOpacity>
|
|
||||||
{/* Test log removed */}
|
|
||||||
{/* Copy all logs removed */}
|
|
||||||
{/* Refresh logs removed */}
|
|
||||||
{/* Clear logs removed */}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
style={[styles.logsScrollView, { backgroundColor: currentTheme.colors.elevation2 }]}
|
|
||||||
showsVerticalScrollIndicator={true}
|
|
||||||
nestedScrollEnabled={true}
|
|
||||||
>
|
>
|
||||||
{false ? (
|
{isInstalling ? (
|
||||||
<Text style={[styles.noLogsText, { color: currentTheme.colors.mediumEmphasis }]}>No logs available</Text>
|
<MaterialIcons name="install-mobile" size={18} color="white" />
|
||||||
) : (
|
) : (
|
||||||
([] as string[]).map((log, index) => {
|
<MaterialIcons name="download" size={18} color="white" />
|
||||||
const isError = log.indexOf('[ERROR]') !== -1;
|
|
||||||
const isWarning = log.indexOf('[WARN]') !== -1;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
key={index}
|
|
||||||
style={[
|
|
||||||
styles.logEntry,
|
|
||||||
{ backgroundColor: 'rgba(255,255,255,0.05)' }
|
|
||||||
]}
|
|
||||||
onPress={() => {}}
|
|
||||||
activeOpacity={0.7}
|
|
||||||
>
|
|
||||||
<View style={styles.logEntryContent}>
|
|
||||||
<Text style={[
|
|
||||||
styles.logText,
|
|
||||||
{
|
|
||||||
color: isError
|
|
||||||
? (currentTheme.colors.error || '#ff4444')
|
|
||||||
: isWarning
|
|
||||||
? (currentTheme.colors.warning || '#ffaa00')
|
|
||||||
: currentTheme.colors.mediumEmphasis
|
|
||||||
}
|
|
||||||
]}>
|
|
||||||
{log}
|
|
||||||
</Text>
|
|
||||||
<MaterialIcons
|
|
||||||
name="content-copy"
|
|
||||||
size={14}
|
|
||||||
color={currentTheme.colors.mediumEmphasis}
|
|
||||||
style={styles.logCopyIcon}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
)}
|
)}
|
||||||
</ScrollView>
|
<Text style={styles.modernButtonText}>
|
||||||
|
{isInstalling ? 'Installing...' : 'Install Update'}
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Release Notes */}
|
||||||
|
{updateInfo?.isAvailable && !!getReleaseNotes() && (
|
||||||
|
<View style={styles.infoSection}>
|
||||||
|
<View style={styles.infoItem}>
|
||||||
|
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
||||||
|
<MaterialIcons name="notes" size={14} color={currentTheme.colors.primary} />
|
||||||
|
</View>
|
||||||
|
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Release notes:</Text>
|
||||||
</View>
|
</View>
|
||||||
</SettingsCard>
|
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>{getReleaseNotes()}</Text>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
</ScrollView>
|
|
||||||
</View>
|
{/* Info Section */}
|
||||||
|
<View style={styles.infoSection}>
|
||||||
|
<View style={styles.infoItem}>
|
||||||
|
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
||||||
|
<MaterialIcons name="info-outline" size={14} color={currentTheme.colors.primary} />
|
||||||
|
</View>
|
||||||
|
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Version:</Text>
|
||||||
|
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>
|
||||||
|
{updateInfo?.manifest?.id ? `${updateInfo.manifest.id.substring(0, 8)}...` : 'Unknown'}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{lastChecked && (
|
||||||
|
<View style={styles.infoItem}>
|
||||||
|
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
||||||
|
<MaterialIcons name="schedule" size={14} color={currentTheme.colors.primary} />
|
||||||
|
</View>
|
||||||
|
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Last checked:</Text>
|
||||||
|
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>
|
||||||
|
{formatDate(lastChecked)}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Current Version Section */}
|
||||||
|
<View style={styles.infoSection}>
|
||||||
|
<View style={styles.infoItem}>
|
||||||
|
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
||||||
|
<MaterialIcons name="verified" size={14} color={currentTheme.colors.primary} />
|
||||||
|
</View>
|
||||||
|
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Current version:</Text>
|
||||||
|
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}
|
||||||
|
selectable>
|
||||||
|
{currentInfo?.manifest?.id || (currentInfo?.isEmbeddedLaunch === false ? 'Unknown' : 'Embedded')}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{!!getCurrentReleaseNotes() && (
|
||||||
|
<View style={{ marginTop: 8 }}>
|
||||||
|
<View style={[styles.infoItem, { alignItems: 'flex-start' }]}>
|
||||||
|
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
||||||
|
<MaterialIcons name="notes" size={14} color={currentTheme.colors.primary} />
|
||||||
|
</View>
|
||||||
|
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Current release notes:</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>
|
||||||
|
{getCurrentReleaseNotes()}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Developer Logs removed */}
|
||||||
|
</SettingsCard>
|
||||||
|
|
||||||
|
{/* GitHub Release (compact) – only show when update is available */}
|
||||||
|
{github.latestTag && isAnyUpgrade(getDisplayedAppVersion(), github.latestTag) ? (
|
||||||
|
<SettingsCard title="GITHUB RELEASE" isTablet={isTablet}>
|
||||||
|
<View style={styles.infoSection}>
|
||||||
|
<View style={styles.infoItem}>
|
||||||
|
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
||||||
|
<MaterialIcons name="new-releases" size={14} color={currentTheme.colors.primary} />
|
||||||
|
</View>
|
||||||
|
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Current:</Text>
|
||||||
|
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>
|
||||||
|
{getDisplayedAppVersion()}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.infoItem}>
|
||||||
|
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.primary}15` }]}>
|
||||||
|
<MaterialIcons name="tag" size={14} color={currentTheme.colors.primary} />
|
||||||
|
</View>
|
||||||
|
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Latest:</Text>
|
||||||
|
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>
|
||||||
|
{github.latestTag}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{github.releaseNotes ? (
|
||||||
|
<View style={{ marginTop: 4 }}>
|
||||||
|
<Text style={[styles.infoLabel, { color: currentTheme.colors.mediumEmphasis }]}>Notes:</Text>
|
||||||
|
<Text
|
||||||
|
numberOfLines={3}
|
||||||
|
style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}
|
||||||
|
>
|
||||||
|
{github.releaseNotes}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<View style={[styles.actionSection, { marginTop: 8 }]}>
|
||||||
|
<View style={{ flexDirection: 'row', gap: 10 }}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.modernButton, { backgroundColor: currentTheme.colors.primary, flex: 1 }]}
|
||||||
|
onPress={() => github.releaseUrl ? Linking.openURL(github.releaseUrl as string) : null}
|
||||||
|
activeOpacity={0.8}
|
||||||
|
>
|
||||||
|
<MaterialIcons name="open-in-new" size={18} color="white" />
|
||||||
|
<Text style={styles.modernButtonText}>View Release</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</SettingsCard>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{/* Update Notification Settings */}
|
||||||
|
<SettingsCard title="NOTIFICATION SETTINGS" isTablet={isTablet}>
|
||||||
|
{/* OTA Updates Toggle */}
|
||||||
|
<View style={styles.settingRow}>
|
||||||
|
<View style={styles.settingInfo}>
|
||||||
|
<Text style={[styles.settingLabel, { color: currentTheme.colors.highEmphasis }]}>
|
||||||
|
OTA Update Alerts
|
||||||
|
</Text>
|
||||||
|
<Text style={[styles.settingDescription, { color: currentTheme.colors.mediumEmphasis }]}>
|
||||||
|
Show notifications for over-the-air updates
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Switch
|
||||||
|
value={otaAlertsEnabled}
|
||||||
|
onValueChange={handleOtaAlertsToggle}
|
||||||
|
trackColor={{ false: '#505050', true: currentTheme.colors.primary }}
|
||||||
|
thumbColor={Platform.OS === 'android' ? '#fff' : undefined}
|
||||||
|
ios_backgroundColor="#505050"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Major Updates Toggle */}
|
||||||
|
<View style={[styles.settingRow, { borderBottomWidth: 0 }]}>
|
||||||
|
<View style={styles.settingInfo}>
|
||||||
|
<Text style={[styles.settingLabel, { color: currentTheme.colors.highEmphasis }]}>
|
||||||
|
Major Update Alerts
|
||||||
|
</Text>
|
||||||
|
<Text style={[styles.settingDescription, { color: currentTheme.colors.mediumEmphasis }]}>
|
||||||
|
Show notifications for new app versions on GitHub
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Switch
|
||||||
|
value={majorAlertsEnabled}
|
||||||
|
onValueChange={handleMajorAlertsToggle}
|
||||||
|
trackColor={{ false: '#505050', true: currentTheme.colors.primary }}
|
||||||
|
thumbColor={Platform.OS === 'android' ? '#fff' : undefined}
|
||||||
|
ios_backgroundColor="#505050"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Warning note */}
|
||||||
|
<View style={[styles.infoItem, { paddingHorizontal: 16, paddingBottom: 12 }]}>
|
||||||
|
<View style={[styles.infoIcon, { backgroundColor: `${currentTheme.colors.warning || '#FFA500'}20` }]}>
|
||||||
|
<MaterialIcons name="info-outline" size={14} color={currentTheme.colors.warning || '#FFA500'} />
|
||||||
|
</View>
|
||||||
|
<Text style={[styles.settingDescription, { color: currentTheme.colors.mediumEmphasis, flex: 1 }]}>
|
||||||
|
Keeping alerts enabled ensures you receive bug fixes and can provide accurate crash reports.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</SettingsCard>
|
||||||
|
|
||||||
|
{false && (
|
||||||
|
<SettingsCard title="UPDATE LOGS" isTablet={isTablet}>
|
||||||
|
<View style={styles.logsContainer}>
|
||||||
|
<View style={styles.logsHeader}>
|
||||||
|
<Text style={[styles.logsHeaderText, { color: currentTheme.colors.highEmphasis }]}>
|
||||||
|
Update Service Logs
|
||||||
|
</Text>
|
||||||
|
<View style={styles.logsActions}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.logActionButton, { backgroundColor: currentTheme.colors.elevation2 }]}
|
||||||
|
onPress={testConnectivity}
|
||||||
|
activeOpacity={0.7}
|
||||||
|
>
|
||||||
|
<MaterialIcons name="wifi" size={16} color={currentTheme.colors.primary} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.logActionButton, { backgroundColor: currentTheme.colors.elevation2 }]}
|
||||||
|
onPress={testAssetUrls}
|
||||||
|
activeOpacity={0.7}
|
||||||
|
>
|
||||||
|
<MaterialIcons name="link" size={16} color={currentTheme.colors.primary} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
{/* Test log removed */}
|
||||||
|
{/* Copy all logs removed */}
|
||||||
|
{/* Refresh logs removed */}
|
||||||
|
{/* Clear logs removed */}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
style={[styles.logsScrollView, { backgroundColor: currentTheme.colors.elevation2 }]}
|
||||||
|
showsVerticalScrollIndicator={true}
|
||||||
|
nestedScrollEnabled={true}
|
||||||
|
>
|
||||||
|
{false ? (
|
||||||
|
<Text style={[styles.noLogsText, { color: currentTheme.colors.mediumEmphasis }]}>No logs available</Text>
|
||||||
|
) : (
|
||||||
|
([] as string[]).map((log, index) => {
|
||||||
|
const isError = log.indexOf('[ERROR]') !== -1;
|
||||||
|
const isWarning = log.indexOf('[WARN]') !== -1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
key={index}
|
||||||
|
style={[
|
||||||
|
styles.logEntry,
|
||||||
|
{ backgroundColor: 'rgba(255,255,255,0.05)' }
|
||||||
|
]}
|
||||||
|
onPress={() => { }}
|
||||||
|
activeOpacity={0.7}
|
||||||
|
>
|
||||||
|
<View style={styles.logEntryContent}>
|
||||||
|
<Text style={[
|
||||||
|
styles.logText,
|
||||||
|
{
|
||||||
|
color: isError
|
||||||
|
? (currentTheme.colors.error || '#ff4444')
|
||||||
|
: isWarning
|
||||||
|
? (currentTheme.colors.warning || '#ffaa00')
|
||||||
|
: currentTheme.colors.mediumEmphasis
|
||||||
|
}
|
||||||
|
]}>
|
||||||
|
{log}
|
||||||
|
</Text>
|
||||||
|
<MaterialIcons
|
||||||
|
name="content-copy"
|
||||||
|
size={14}
|
||||||
|
color={currentTheme.colors.mediumEmphasis}
|
||||||
|
style={styles.logCopyIcon}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
</ScrollView>
|
||||||
|
</View>
|
||||||
|
</SettingsCard>
|
||||||
|
)}
|
||||||
|
</ScrollView>
|
||||||
|
</View>
|
||||||
<CustomAlert
|
<CustomAlert
|
||||||
visible={alertVisible}
|
visible={alertVisible}
|
||||||
title={alertTitle}
|
title={alertTitle}
|
||||||
|
|
@ -715,7 +832,7 @@ const styles = StyleSheet.create({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
paddingBottom: 90,
|
paddingBottom: 90,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Common card styles
|
// Common card styles
|
||||||
cardContainer: {
|
cardContainer: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
|
@ -754,7 +871,7 @@ const styles = StyleSheet.create({
|
||||||
shadowRadius: 8,
|
shadowRadius: 8,
|
||||||
elevation: 5,
|
elevation: 5,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Update UI Styles
|
// Update UI Styles
|
||||||
updateMainCard: {
|
updateMainCard: {
|
||||||
padding: 20,
|
padding: 20,
|
||||||
|
|
@ -810,9 +927,9 @@ const styles = StyleSheet.create({
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
},
|
},
|
||||||
modernProgressFill: {
|
modernProgressFill: {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
},
|
},
|
||||||
actionSection: {
|
actionSection: {
|
||||||
gap: 12,
|
gap: 12,
|
||||||
},
|
},
|
||||||
|
|
@ -905,7 +1022,7 @@ const styles = StyleSheet.create({
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
},
|
},
|
||||||
|
|
||||||
// Logs styles
|
// Logs styles
|
||||||
logsContainer: {
|
logsContainer: {
|
||||||
padding: 20,
|
padding: 20,
|
||||||
|
|
@ -962,6 +1079,30 @@ const styles = StyleSheet.create({
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
paddingVertical: 20,
|
paddingVertical: 20,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Settings toggle styles
|
||||||
|
settingRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingVertical: 14,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
borderBottomWidth: 0.5,
|
||||||
|
borderBottomColor: 'rgba(255, 255, 255, 0.1)',
|
||||||
|
},
|
||||||
|
settingInfo: {
|
||||||
|
flex: 1,
|
||||||
|
marginRight: 12,
|
||||||
|
},
|
||||||
|
settingLabel: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '500',
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
settingDescription: {
|
||||||
|
fontSize: 13,
|
||||||
|
lineHeight: 18,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default UpdateScreen;
|
export default UpdateScreen;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue