New Giftopia App Icons and Splashes #236
@@ -1360,7 +1360,7 @@ npm run assets:validate
|
||||
**Source Assets (Required):**
|
||||
- `resources/icon.png` - App icon source
|
||||
- `resources/splash.png` - Splash screen source
|
||||
- `resources/splash_dark.png` - Dark mode splash source
|
||||
- `resources/splash-dark.png` - Dark mode splash source
|
||||
|
||||
**Android Resources (Generated):**
|
||||
- `android/app/src/main/res/drawable/splash.png` - Splash screen drawable
|
||||
@@ -1604,6 +1604,11 @@ Use the commands above to check and fix code quality issues.
|
||||
4. **Native Build**: Platform-specific compilation
|
||||
5. **Package Creation**: APK/IPA generation
|
||||
|
||||
`resources/` is the canonical source for app icons and splash screens.
|
||||
Do not keep a legacy top-level `assets/` directory unless it is intentionally
|
||||
used: `@capacitor/assets` prioritizes `assets/` over `resources/`, which can
|
||||
prevent the canonical assets from being discovered.
|
||||
|
||||
## Architecture Environment Configuration
|
||||
|
||||
### Environment Files
|
||||
|
||||
@@ -199,7 +199,7 @@ icon and splash screen generation across all platforms.
|
||||
### Asset Sources
|
||||
|
||||
- **Single source of truth**: `resources/` directory (Capacitor default)
|
||||
- **Source files**: `icon.png`, `splash.png`, `splash_dark.png`
|
||||
- **Source files**: `icon.png`, `splash.png`, `splash-dark.png`
|
||||
- **Format**: PNG or SVG files for optimal quality
|
||||
|
||||
### Asset Generation
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
"icon": {
|
||||
"android": {
|
||||
"adaptive": {
|
||||
"background": "#121212",
|
||||
"foreground": "resources/icon.png",
|
||||
"monochrome": "resources/icon.png"
|
||||
"background": "resources/android/icon/icon-background.png",
|
||||
"foreground": "resources/android/icon/icon-foreground.png",
|
||||
"monochrome": "resources/android/icon/icon-monochrome.png"
|
||||
},
|
||||
"target": "android/app/src/main/res"
|
||||
},
|
||||
@@ -22,7 +22,7 @@
|
||||
"scale": "cover",
|
||||
"target": "android/app/src/main/res"
|
||||
},
|
||||
"darkSource": "resources/splash_dark.png",
|
||||
"darkSource": "resources/splash-dark.png",
|
||||
"ios": {
|
||||
"target": "ios/App/App/Assets.xcassets",
|
||||
"useStoryBoard": true
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"scale": "cover",
|
||||
"target": "android/app/src/main/res"
|
||||
},
|
||||
"darkSource": "resources/splash_dark.png",
|
||||
"darkSource": "resources/splash-dark.png",
|
||||
"ios": {
|
||||
"target": "ios/App/App/Assets.xcassets",
|
||||
"useStoryBoard": true
|
||||
|
||||
@@ -47,7 +47,7 @@ npm run build:android:studio
|
||||
#### Source Assets (Required)
|
||||
- `resources/icon.png` - App icon source
|
||||
- `resources/splash.png` - Splash screen source
|
||||
- `resources/splash_dark.png` - Dark mode splash source
|
||||
- `resources/splash-dark.png` - Dark mode splash source
|
||||
|
||||
#### Android Resources (Generated)
|
||||
- `android/app/src/main/res/drawable/splash.png` - Splash screen drawable
|
||||
@@ -201,13 +201,13 @@ mkdir -p android/app/src/main/res/mipmap-{mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi}
|
||||
# Copy source assets to assets directory
|
||||
cp resources/icon.png assets/
|
||||
cp resources/splash.png assets/
|
||||
cp resources/splash_dark.png assets/
|
||||
cp resources/splash-dark.png assets/
|
||||
|
||||
# Generate assets manually
|
||||
npx @capacitor/assets generate
|
||||
|
||||
# Clean up
|
||||
rm assets/icon.png assets/splash.png assets/splash_dark.png
|
||||
rm assets/icon.png assets/splash.png assets/splash-dark.png
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
@@ -89,7 +89,7 @@ system to a standardized, single-source asset configuration approach using
|
||||
resources/ # Image sources ONLY
|
||||
icon.png
|
||||
splash.png
|
||||
splash_dark.png
|
||||
splash-dark.png
|
||||
|
||||
config/assets/ # Versioned config & schema
|
||||
capacitor-assets.config.json
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "splash@1x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "splash@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "splash@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 156 KiB |
@@ -56,7 +56,10 @@ npx capacitor-assets generate --web
|
||||
|
||||
## Configuration
|
||||
|
||||
Asset generation is configured in `capacitor-assets.config.json` at the project root.
|
||||
`resources/` is this project's canonical asset source. `@capacitor/assets`
|
||||
prioritizes a top-level `assets/` directory over `resources/`, so a legacy
|
||||
`assets/` directory can prevent these assets from being discovered. Remove that
|
||||
directory when it is empty or obsolete.
|
||||
|
||||
## Version Control
|
||||
|
||||
|
||||
BIN
resources/android/icon/icon-background.png
Normal file
|
After Width: | Height: | Size: 602 KiB |
BIN
resources/android/icon/icon-foreground.png
Normal file
|
After Width: | Height: | Size: 223 KiB |
BIN
resources/android/icon/icon-monochrome.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 624 KiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 624 KiB |
BIN
resources/ios/icon/icon-dark.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 624 KiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.8 MiB |
BIN
resources/splash-dark.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 624 KiB |
@@ -92,7 +92,7 @@ function generateAssetConfig(): AssetConfig {
|
||||
},
|
||||
splash: {
|
||||
source: "resources/splash.png",
|
||||
darkSource: "resources/splash_dark.png",
|
||||
darkSource: "resources/splash-dark.png",
|
||||
android: {
|
||||
scale: "cover",
|
||||
target: "android/app/src/main/res"
|
||||
@@ -138,7 +138,7 @@ function validateSourceFiles(): void {
|
||||
const requiredFiles = [
|
||||
'resources/icon.png',
|
||||
'resources/splash.png',
|
||||
'resources/splash_dark.png'
|
||||
'resources/splash-dark.png'
|
||||
];
|
||||
|
||||
const missingFiles = requiredFiles.filter(file => {
|
||||
|
||||
@@ -230,8 +230,8 @@ validate_android_assets() {
|
||||
missing_assets+=("resources/splash.png")
|
||||
fi
|
||||
|
||||
if [ ! -f "resources/splash_dark.png" ]; then
|
||||
missing_assets+=("resources/splash_dark.png")
|
||||
if [ ! -f "resources/splash-dark.png" ]; then
|
||||
missing_assets+=("resources/splash-dark.png")
|
||||
fi
|
||||
|
||||
if [ ${#missing_assets[@]} -gt 0 ]; then
|
||||
@@ -278,14 +278,14 @@ validate_android_assets() {
|
||||
# Copy source assets to assets directory for capacitor-assets
|
||||
cp resources/icon.png assets/ 2>/dev/null || log_warn "Could not copy icon.png"
|
||||
cp resources/splash.png assets/ 2>/dev/null || log_warn "Could not copy splash.png"
|
||||
cp resources/splash_dark.png assets/ 2>/dev/null || log_warn "Could not copy splash_dark.png"
|
||||
cp resources/splash-dark.png assets/ 2>/dev/null || log_warn "Could not copy splash-dark.png"
|
||||
|
||||
# Generate assets
|
||||
if npx @capacitor/assets generate >/dev/null 2>&1; then
|
||||
log_success "Android assets regenerated successfully"
|
||||
|
||||
# Clean up temporary assets
|
||||
rm -f assets/icon.png assets/splash.png assets/splash_dark.png
|
||||
rm -f assets/icon.png assets/splash.png assets/splash-dark.png
|
||||
|
||||
# Verify the resources were created
|
||||
local verification_failed=false
|
||||
|
||||
@@ -172,12 +172,12 @@ check_ios_resources() {
|
||||
log_info "Checking iOS resources..."
|
||||
|
||||
# Check for required assets
|
||||
if [ ! -f "assets/icon.png" ]; then
|
||||
log_warn "App icon not found at assets/icon.png"
|
||||
if [ ! -f "resources/icon.png" ]; then
|
||||
log_warn "App icon not found at resources/icon.png"
|
||||
fi
|
||||
|
||||
if [ ! -f "assets/splash.png" ]; then
|
||||
log_warn "Splash screen not found at assets/splash.png"
|
||||
if [ ! -f "resources/splash.png" ]; then
|
||||
log_warn "Splash screen not found at resources/splash.png"
|
||||
fi
|
||||
|
||||
# Check for iOS-specific files
|
||||
@@ -192,6 +192,118 @@ check_ios_resources() {
|
||||
log_success "iOS resource check completed"
|
||||
}
|
||||
|
||||
# iOS app icon appearance variants (Dark, Tinted, …).
|
||||
# Luminosity appearance values match Apple's asset catalog format (iOS 18+).
|
||||
readonly _IOS_APP_ICON_APPEARANCE_LUMINOSITY="luminosity"
|
||||
readonly _IOS_APP_ICON_APPEARANCE_DARK="dark"
|
||||
readonly _IOS_APP_ICON_APPEARANCE_TINTED="tinted"
|
||||
|
||||
# Each row: source_file|luminosity_value|dest_filename
|
||||
# To add a variant: append one row and place the source PNG under resources/ios/.
|
||||
readonly _IOS_APP_ICON_APPEARANCE_VARIANTS=(
|
||||
"resources/ios/icon/icon-dark.png|${_IOS_APP_ICON_APPEARANCE_DARK}|AppIcon-Dark.png"
|
||||
"resources/ios/icon/icon-tinted.png|${_IOS_APP_ICON_APPEARANCE_TINTED}|AppIcon-Tinted.png"
|
||||
)
|
||||
|
||||
# Update AppIcon.appiconset/Contents.json with one 1024×1024 appearance entry.
|
||||
# Preserves all other images (including capacitor-assets output); replaces any
|
||||
# existing entry for the same luminosity appearance.
|
||||
_update_appicon_contents_for_appearance() {
|
||||
local contents_json="$1"
|
||||
local dest_filename="$2"
|
||||
local luminosity_value="$3"
|
||||
|
||||
local tmp_file
|
||||
tmp_file="$(mktemp)"
|
||||
|
||||
if ! jq --arg filename "$dest_filename" \
|
||||
--arg appearance "$_IOS_APP_ICON_APPEARANCE_LUMINOSITY" \
|
||||
--arg value "$luminosity_value" \
|
||||
'
|
||||
.images |= map(select((.appearances[0].value // "") != $value))
|
||||
| .images += [{
|
||||
"appearances": [{
|
||||
"appearance": $appearance,
|
||||
"value": $value
|
||||
}],
|
||||
"filename": $filename,
|
||||
"idiom": "universal",
|
||||
"platform": "ios",
|
||||
"size": "1024x1024"
|
||||
}]
|
||||
' "$contents_json" > "$tmp_file"; then
|
||||
rm -f "$tmp_file"
|
||||
log_error "Failed to update AppIcon Contents.json for appearance: $luminosity_value"
|
||||
return 1
|
||||
fi
|
||||
|
||||
mv "$tmp_file" "$contents_json"
|
||||
}
|
||||
|
||||
# Install one appearance variant when its source PNG exists.
|
||||
_apply_ios_app_icon_appearance_variant() {
|
||||
local appiconset_dir="$1"
|
||||
local contents_json="$2"
|
||||
local source_file="$3"
|
||||
local luminosity_value="$4"
|
||||
local dest_filename="$5"
|
||||
|
||||
if [ ! -f "$source_file" ]; then
|
||||
log_info "iOS app icon appearance variant not found ($source_file) — skipping"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -d "$appiconset_dir" ]; then
|
||||
log_warn "AppIcon.appiconset not found — skipping appearance variant ($luminosity_value)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! cp "$source_file" "$appiconset_dir/$dest_filename"; then
|
||||
log_error "Failed to copy $source_file to $appiconset_dir/$dest_filename"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Installed iOS app icon appearance variant: $luminosity_value ($dest_filename)"
|
||||
_update_appicon_contents_for_appearance "$contents_json" "$dest_filename" "$luminosity_value"
|
||||
}
|
||||
|
||||
# Post-process capacitor-assets iOS icons: copy optional Dark/Tinted sources and
|
||||
# register them in AppIcon.appiconset/Contents.json.
|
||||
apply_ios_app_icon_appearances() {
|
||||
local appiconset_dir="ios/App/App/Assets.xcassets/AppIcon.appiconset"
|
||||
local contents_json="$appiconset_dir/Contents.json"
|
||||
|
||||
if [ ! -f "$contents_json" ]; then
|
||||
log_info "AppIcon Contents.json not found — skipping appearance variants"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! command -v jq &> /dev/null; then
|
||||
log_error "jq is required to install iOS app icon appearance variants (install with: brew install jq)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local variant source_file luminosity_value dest_filename
|
||||
for variant in "${_IOS_APP_ICON_APPEARANCE_VARIANTS[@]}"; do
|
||||
IFS='|' read -r source_file luminosity_value dest_filename <<< "$variant"
|
||||
_apply_ios_app_icon_appearance_variant \
|
||||
"$appiconset_dir" "$contents_json" \
|
||||
"$source_file" "$luminosity_value" "$dest_filename"
|
||||
done
|
||||
}
|
||||
|
||||
# Generate iOS assets (capacitor-assets), then apply optional appearance variants.
|
||||
generate_ios_assets() {
|
||||
ensure_ios_capacitor_asset_directories
|
||||
if [ -d "assets" ]; then
|
||||
log_warn "@capacitor/assets prioritizes the top-level assets/ directory over resources/."
|
||||
log_warn "This project intentionally uses resources/ as the canonical asset source."
|
||||
log_warn "Remove the legacy assets/ directory if it is empty or obsolete."
|
||||
fi
|
||||
npx capacitor-assets generate --ios
|
||||
apply_ios_app_icon_appearances
|
||||
}
|
||||
|
||||
# Function to clean iOS build
|
||||
clean_ios_build() {
|
||||
log_info "Cleaning iOS build artifacts..."
|
||||
@@ -424,8 +536,7 @@ fi
|
||||
# Handle assets-only mode
|
||||
if [ "$ASSETS_ONLY" = true ]; then
|
||||
log_info "Assets-only mode: generating assets"
|
||||
ensure_ios_capacitor_asset_directories
|
||||
safe_execute "Generating assets" "npx capacitor-assets generate --ios" || exit 7
|
||||
safe_execute "Generating assets" "generate_ios_assets" || exit 7
|
||||
log_success "Assets generation completed successfully!"
|
||||
exit 0
|
||||
fi
|
||||
@@ -574,8 +685,7 @@ safe_execute "Installing CocoaPods dependencies" "run_pod_install_with_workaroun
|
||||
safe_execute "Syncing with Capacitor" "run_cap_sync_with_workaround" || exit 6
|
||||
|
||||
# Step 7: Generate assets
|
||||
ensure_ios_capacitor_asset_directories
|
||||
safe_execute "Generating assets" "npx capacitor-assets generate --ios" || exit 7
|
||||
safe_execute "Generating assets" "generate_ios_assets" || exit 7
|
||||
|
||||
# Step 8: Build iOS app
|
||||
safe_execute "Building iOS app" "build_ios_app" || exit 5
|
||||
|
||||