mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-08 03:00:41 +00:00
updates UI now support release notes
This commit is contained in:
parent
837e3735a2
commit
754dec3946
6 changed files with 133 additions and 15 deletions
|
|
@ -1,9 +1,13 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Check if the correct number of arguments are provided
|
# Usage: build-and-publish-app-release.sh <xavia-ota-url> [--yes] [--release-notes "text here"]
|
||||||
if [ "$#" -ne 1 ]; then
|
# --yes Skip interactive confirmation
|
||||||
echo "Usage: $0 <xavia-ota-url>"
|
# --release-notes Provide release notes to attach to this upload
|
||||||
echo "Example: $0 https://grim-reyna-tapframe-69970143.koyeb.app"
|
|
||||||
|
# Parse arguments
|
||||||
|
if [ "$#" -lt 1 ]; then
|
||||||
|
echo "Usage: $0 <xavia-ota-url> [--yes] [--release-notes \"text here\"]"
|
||||||
|
echo "Example: $0 https://grim-reyna-tapframe-69970143.koyeb.app --yes --release-notes \"Bug fixes and improvements\""
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -27,6 +31,29 @@ fi
|
||||||
|
|
||||||
# Assign arguments to variables
|
# Assign arguments to variables
|
||||||
serverHost=$1
|
serverHost=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
SKIP_CONFIRM=false
|
||||||
|
RELEASE_NOTES=""
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
key="$1"
|
||||||
|
case $key in
|
||||||
|
--yes)
|
||||||
|
SKIP_CONFIRM=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--release-notes)
|
||||||
|
RELEASE_NOTES="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
# Validate server URL format
|
# Validate server URL format
|
||||||
if [[ ! "$serverHost" =~ ^https?:// ]]; then
|
if [[ ! "$serverHost" =~ ^https?:// ]]; then
|
||||||
|
|
@ -47,13 +74,15 @@ echo "📱 Runtime Version: $runtimeVersion"
|
||||||
echo "🔗 Commit Hash: $commitHash"
|
echo "🔗 Commit Hash: $commitHash"
|
||||||
echo "📝 Commit Message: $commitMessage"
|
echo "📝 Commit Message: $commitMessage"
|
||||||
echo "🌐 Server URL: $serverHost"
|
echo "🌐 Server URL: $serverHost"
|
||||||
|
echo "📝 Release Notes: ${RELEASE_NOTES:-<none provided>}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
read -p "Do you want to proceed with these values? (y/n): " confirm
|
if [ "$SKIP_CONFIRM" = false ]; then
|
||||||
|
read -p "Do you want to proceed with these values? (y/n): " confirm
|
||||||
if [ "$confirm" != "y" ]; then
|
if [ "$confirm" != "y" ]; then
|
||||||
echo "❌ Operation cancelled by the user."
|
echo "❌ Operation cancelled by the user."
|
||||||
exit 1
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "🔨 Starting build process..."
|
echo "🔨 Starting build process..."
|
||||||
|
|
@ -107,6 +136,7 @@ while [ $retry_count -lt $max_retries ]; do
|
||||||
-F "runtimeVersion=$runtimeVersion" \
|
-F "runtimeVersion=$runtimeVersion" \
|
||||||
-F "commitHash=$commitHash" \
|
-F "commitHash=$commitHash" \
|
||||||
-F "commitMessage=$commitMessage" \
|
-F "commitMessage=$commitMessage" \
|
||||||
|
${RELEASE_NOTES:+-F "releaseNotes=$RELEASE_NOTES"} \
|
||||||
--write-out "HTTP_CODE:%{http_code}" \
|
--write-out "HTTP_CODE:%{http_code}" \
|
||||||
--silent \
|
--silent \
|
||||||
--show-error)
|
--show-error)
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,17 @@ const UpdatePopup: React.FC<UpdatePopupProps> = ({
|
||||||
const { currentTheme } = useTheme();
|
const { currentTheme } = useTheme();
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
|
|
||||||
|
const getReleaseNotes = () => {
|
||||||
|
const manifest: any = updateInfo?.manifest || {};
|
||||||
|
return (
|
||||||
|
manifest.description ||
|
||||||
|
manifest.releaseNotes ||
|
||||||
|
manifest.extra?.releaseNotes ||
|
||||||
|
manifest.metadata?.releaseNotes ||
|
||||||
|
''
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const handleUpdateNow = () => {
|
const handleUpdateNow = () => {
|
||||||
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
|
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
|
||||||
onUpdateNow();
|
onUpdateNow();
|
||||||
|
|
@ -129,13 +140,13 @@ const UpdatePopup: React.FC<UpdatePopupProps> = ({
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{updateInfo.manifest?.description && (
|
{!!getReleaseNotes() && (
|
||||||
<View style={styles.descriptionContainer}>
|
<View style={styles.descriptionContainer}>
|
||||||
<Text style={[
|
<Text style={[
|
||||||
styles.description,
|
styles.description,
|
||||||
{ color: currentTheme.colors.mediumEmphasis }
|
{ color: currentTheme.colors.mediumEmphasis }
|
||||||
]}>
|
]}>
|
||||||
{updateInfo.manifest.description}
|
{getReleaseNotes()}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ import Animated, {
|
||||||
useAnimatedStyle,
|
useAnimatedStyle,
|
||||||
interpolate,
|
interpolate,
|
||||||
Extrapolate,
|
Extrapolate,
|
||||||
|
useAnimatedReaction,
|
||||||
|
runOnJS,
|
||||||
} from 'react-native-reanimated';
|
} from 'react-native-reanimated';
|
||||||
import { useTheme } from '../../contexts/ThemeContext';
|
import { useTheme } from '../../contexts/ThemeContext';
|
||||||
import { logger } from '../../utils/logger';
|
import { logger } from '../../utils/logger';
|
||||||
|
|
@ -46,6 +48,7 @@ const FloatingHeader: React.FC<FloatingHeaderProps> = ({
|
||||||
setLogoLoadError,
|
setLogoLoadError,
|
||||||
}) => {
|
}) => {
|
||||||
const { currentTheme } = useTheme();
|
const { currentTheme } = useTheme();
|
||||||
|
const [isHeaderInteractive, setIsHeaderInteractive] = React.useState(false);
|
||||||
|
|
||||||
// Animated styles for the header
|
// Animated styles for the header
|
||||||
const headerAnimatedStyle = useAnimatedStyle(() => ({
|
const headerAnimatedStyle = useAnimatedStyle(() => ({
|
||||||
|
|
@ -55,6 +58,15 @@ const FloatingHeader: React.FC<FloatingHeaderProps> = ({
|
||||||
]
|
]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Disable touches when header is transparent (Android can still register touches at opacity 0)
|
||||||
|
useAnimatedReaction(
|
||||||
|
() => headerOpacity.value,
|
||||||
|
(opacity) => {
|
||||||
|
const interactive = opacity > 0.05;
|
||||||
|
runOnJS(setIsHeaderInteractive)(interactive);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Animated style for header elements
|
// Animated style for header elements
|
||||||
const headerElementsStyle = useAnimatedStyle(() => ({
|
const headerElementsStyle = useAnimatedStyle(() => ({
|
||||||
opacity: headerElementsOpacity.value,
|
opacity: headerElementsOpacity.value,
|
||||||
|
|
@ -62,7 +74,7 @@ const FloatingHeader: React.FC<FloatingHeaderProps> = ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Animated.View style={[styles.floatingHeader, headerAnimatedStyle]}>
|
<Animated.View style={[styles.floatingHeader, headerAnimatedStyle]} pointerEvents={isHeaderInteractive ? 'auto' : 'none'}>
|
||||||
{Platform.OS === 'ios' ? (
|
{Platform.OS === 'ios' ? (
|
||||||
<ExpoBlurView
|
<ExpoBlurView
|
||||||
intensity={50}
|
intensity={50}
|
||||||
|
|
|
||||||
|
|
@ -353,7 +353,7 @@ const TrailerPlayer = React.forwardRef<any, TrailerPlayerProps>(({
|
||||||
onLoad={handleLoad}
|
onLoad={handleLoad}
|
||||||
onError={(error: any) => handleError(error)}
|
onError={(error: any) => handleError(error)}
|
||||||
onProgress={handleProgress}
|
onProgress={handleProgress}
|
||||||
controls={false}
|
controls={Platform.OS === 'android' ? isFullscreen : false}
|
||||||
onEnd={() => {
|
onEnd={() => {
|
||||||
// Only loop if still considered playing and component is mounted
|
// Only loop if still considered playing and component is mounted
|
||||||
if (isPlaying && isComponentMounted) {
|
if (isPlaying && isComponentMounted) {
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ const UpdateScreen: React.FC = () => {
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
|
|
||||||
const [updateInfo, setUpdateInfo] = useState<any>(null);
|
const [updateInfo, setUpdateInfo] = useState<any>(null);
|
||||||
|
const [currentInfo, setCurrentInfo] = useState<any>(null);
|
||||||
const [isChecking, setIsChecking] = useState(false);
|
const [isChecking, setIsChecking] = useState(false);
|
||||||
const [isInstalling, setIsInstalling] = useState(false);
|
const [isInstalling, setIsInstalling] = useState(false);
|
||||||
const [lastChecked, setLastChecked] = useState<Date | null>(null);
|
const [lastChecked, setLastChecked] = useState<Date | null>(null);
|
||||||
|
|
@ -154,11 +155,35 @@ const UpdateScreen: React.FC = () => {
|
||||||
|
|
||||||
const getCurrentUpdateInfo = async () => {
|
const getCurrentUpdateInfo = async () => {
|
||||||
const info = await UpdateService.getCurrentUpdateInfo();
|
const info = await UpdateService.getCurrentUpdateInfo();
|
||||||
setUpdateInfo(info);
|
setCurrentInfo(info);
|
||||||
const logs = UpdateService.getLogs();
|
const logs = UpdateService.getLogs();
|
||||||
setLogs(logs);
|
setLogs(logs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Extract release notes from various possible manifest fields
|
||||||
|
const getReleaseNotes = () => {
|
||||||
|
const manifest: any = updateInfo?.manifest || {};
|
||||||
|
return (
|
||||||
|
manifest.description ||
|
||||||
|
manifest.releaseNotes ||
|
||||||
|
manifest.extra?.releaseNotes ||
|
||||||
|
manifest.metadata?.releaseNotes ||
|
||||||
|
''
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extract release notes for the currently running version
|
||||||
|
const getCurrentReleaseNotes = () => {
|
||||||
|
const manifest: any = currentInfo?.manifest || {};
|
||||||
|
return (
|
||||||
|
manifest.description ||
|
||||||
|
manifest.releaseNotes ||
|
||||||
|
manifest.extra?.releaseNotes ||
|
||||||
|
manifest.metadata?.releaseNotes ||
|
||||||
|
''
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const refreshLogs = () => {
|
const refreshLogs = () => {
|
||||||
const logs = UpdateService.getLogs();
|
const logs = UpdateService.getLogs();
|
||||||
setLogs(logs);
|
setLogs(logs);
|
||||||
|
|
@ -414,6 +439,19 @@ const UpdateScreen: React.FC = () => {
|
||||||
</View>
|
</View>
|
||||||
</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>
|
||||||
|
<Text style={[styles.infoValue, { color: currentTheme.colors.highEmphasis }]}>{getReleaseNotes()}</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Info Section */}
|
{/* Info Section */}
|
||||||
<View style={styles.infoSection}>
|
<View style={styles.infoSection}>
|
||||||
<View style={styles.infoItem}>
|
<View style={styles.infoItem}>
|
||||||
|
|
@ -439,6 +477,33 @@ const UpdateScreen: React.FC = () => {
|
||||||
)}
|
)}
|
||||||
</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 }]}>
|
||||||
|
{currentInfo?.manifest?.id ? `${currentInfo.manifest.id.substring(0, 8)}...` : (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>
|
||||||
|
|
||||||
{/* Advanced Toggle */}
|
{/* Advanced Toggle */}
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.modernAdvancedToggle, { backgroundColor: `${currentTheme.colors.primary}08` }]}
|
style={[styles.modernAdvancedToggle, { backgroundColor: `${currentTheme.colors.primary}08` }]}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit ef5455acaa04404d816a6bffc25a259e28189918
|
Subproject commit 90fd3dd10d6ccbef30e9ce68d81c483a5552c378
|
||||||
Loading…
Reference in a new issue