feat: enhance iOS run script to support simulator and physical device options

This commit is contained in:
tapframe 2026-03-11 21:55:12 +05:30
parent 2f2ac96cc4
commit 0a70df9e2d
2 changed files with 127 additions and 27 deletions

View file

@ -85,16 +85,21 @@ fun StreamsScreen(
StreamsRepository.load(type, videoId)
}
val heroArtwork = if (isEpisode) {
episodeThumbnail ?: background ?: poster
} else {
background ?: poster
}
Box(
modifier = modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background),
) {
// Background artwork
val backdropUrl = background ?: poster
if (backdropUrl != null) {
if (heroArtwork != null) {
AsyncImage(
model = backdropUrl,
model = heroArtwork,
contentDescription = null,
modifier = Modifier
.fillMaxSize()
@ -105,10 +110,12 @@ fun StreamsScreen(
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black.copy(alpha = 0.82f)),
.background(Color.Black.copy(alpha = if (isEpisode) 0.9f else 0.82f)),
)
}
val streamBlendColor = MaterialTheme.colorScheme.background
// Main content column
Column(modifier = Modifier.fillMaxSize()) {
// Hero block
@ -117,7 +124,7 @@ fun StreamsScreen(
seasonNumber = seasonNumber,
episodeNumber = episodeNumber,
episodeTitle = episodeTitle ?: title,
thumbnail = episodeThumbnail ?: background ?: poster,
thumbnail = heroArtwork,
showTitle = title,
)
} else {
@ -127,18 +134,42 @@ fun StreamsScreen(
)
}
// Provider filter chips
ProviderFilterRow(
groups = uiState.groups,
selectedFilter = uiState.selectedFilter,
onFilterSelected = { addonId -> StreamsRepository.selectFilter(addonId) },
)
Box(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
) {
if (isEpisode) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(132.dp)
.background(
Brush.verticalGradient(
colors = listOf(
streamBlendColor.copy(alpha = 0.98f),
streamBlendColor.copy(alpha = 0.84f),
streamBlendColor.copy(alpha = 0.52f),
Color.Transparent,
),
),
),
)
}
// Stream list
StreamList(
uiState = uiState,
modifier = Modifier.weight(1f),
)
Column(modifier = Modifier.fillMaxSize()) {
ProviderFilterRow(
groups = uiState.groups,
selectedFilter = uiState.selectedFilter,
onFilterSelected = { addonId -> StreamsRepository.selectFilter(addonId) },
)
StreamList(
uiState = uiState,
modifier = Modifier.weight(1f),
)
}
}
}
// Back button overlay (top-left)
@ -221,6 +252,8 @@ private fun EpisodeHeroBlock(
showTitle: String,
modifier: Modifier = Modifier,
) {
val heroBlendColor = MaterialTheme.colorScheme.background
Box(
modifier = modifier
.fillMaxWidth()
@ -242,11 +275,12 @@ private fun EpisodeHeroBlock(
.fillMaxSize()
.background(
Brush.verticalGradient(
colors = listOf(
Color.Transparent,
Color.Black.copy(alpha = 0.5f),
Color.Black.copy(alpha = 0.9f),
Color.Black.copy(alpha = 0.98f),
colorStops = arrayOf(
0.0f to Color.Transparent,
0.58f to Color.Transparent,
0.8f to Color.Black.copy(alpha = 0.42f),
0.93f to heroBlendColor.copy(alpha = 0.84f),
1.0f to heroBlendColor.copy(alpha = 0.97f),
),
startY = 0f,
endY = Float.POSITIVE_INFINITY,
@ -254,6 +288,12 @@ private fun EpisodeHeroBlock(
),
)
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black.copy(alpha = 0.1f)),
)
// Safe-area push-down for status bar, then content pinned to bottom
Column(
modifier = Modifier

View file

@ -18,10 +18,12 @@ usage() {
cat <<'EOF'
Usage:
./scripts/run-mobile.sh android
./scripts/run-mobile.sh ios
./scripts/run-mobile.sh ios s
./scripts/run-mobile.sh ios p
Builds the debug app for the selected platform, installs it on the first running
Android emulator or the configured iOS device target, and launches the app.
Android emulator, a booted iOS simulator, or the configured iOS physical device,
and launches the app.
EOF
}
@ -94,7 +96,44 @@ run_android() {
adb -s "$serial" shell am start -n "$ANDROID_APP_ID/$ANDROID_ACTIVITY"
}
run_ios() {
run_ios_simulator() {
require_command xcodebuild
require_command xcrun
local simulator_id
simulator_id="$(first_booted_ios_simulator)"
if [[ -z "$simulator_id" ]]; then
echo "No booted iOS simulator found." >&2
echo "Boot a simulator first, then rerun: ./scripts/run-mobile.sh ios s" >&2
exit 1
fi
local simulator_app_path
simulator_app_path="$IOS_DERIVED_DATA/Build/Products/Debug-iphonesimulator/$IOS_APP_NAME"
echo "Building iOS debug app for simulator $simulator_id..."
xcodebuild \
-project "$IOS_PROJECT" \
-scheme "$IOS_SCHEME" \
-configuration Debug \
-destination "id=$simulator_id" \
-derivedDataPath "$IOS_DERIVED_DATA" \
build
if [[ ! -d "$simulator_app_path" ]]; then
echo "Expected iOS simulator app not found at: $simulator_app_path" >&2
exit 1
fi
echo "Installing on simulator $simulator_id..."
xcrun simctl install "$simulator_id" "$simulator_app_path"
echo "Launching app..."
xcrun simctl launch "$simulator_id" "$IOS_BUNDLE_ID"
}
run_ios_physical() {
require_command xcodebuild
require_command xcrun
@ -128,22 +167,43 @@ run_ios() {
fi
echo "Preferred iOS device not available: $IOS_PREFERRED_DEVICE_MODEL" >&2
echo "Connect and unlock that device, then rerun: ./scripts/run-mobile.sh ios" >&2
echo "Connect and unlock that device, then rerun: ./scripts/run-mobile.sh ios p" >&2
exit 1
}
main() {
if [[ $# -ne 1 ]]; then
if [[ $# -lt 1 ]]; then
usage
exit 1
fi
case "$1" in
android)
if [[ $# -ne 1 ]]; then
usage
exit 1
fi
run_android
;;
ios)
run_ios
if [[ $# -ne 2 ]]; then
usage
exit 1
fi
case "$2" in
s)
run_ios_simulator
;;
p)
run_ios_physical
;;
*)
echo "Unknown iOS target: $2" >&2
usage
exit 1
;;
esac
;;
-h|--help|help)
usage