ui changes

This commit is contained in:
tapframe 2025-10-15 21:54:02 +05:30
parent 7e300e8789
commit 829e569ccd
10 changed files with 221 additions and 144 deletions

View file

@ -81,7 +81,7 @@ def enableMinifyInReleaseBuilds = (findProperty('android.enableMinifyInReleaseBu
*/ */
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+' def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
apply from: new File(["node", "--print", "require('path').dirname(require.resolve('@sentry/react-native/package.json'))"].execute().text.trim(), "sentry.gradle") // apply from: new File(["node", "--print", "require('path').dirname(require.resolve('@sentry/react-native/package.json'))"].execute().text.trim(), "sentry.gradle")
android { android {
ndkVersion rootProject.ext.ndkVersion ndkVersion rootProject.ext.ndkVersion
@ -100,41 +100,32 @@ android {
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\"" buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
} }
// Split APKs by architecture and density for smaller downloads // Split APKs by architecture only for smaller downloads
splits { splits {
abi { abi {
enable true enable true
reset() reset()
include "arm64-v8a", "armeabi-v7a", "x86", "x86_64" include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
universalApk true // Generate universal APK as well universalApk true
} }
density { density {
enable true enable false
reset()
include "ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
universalApk true // Generate universal APK as well
} }
} }
// Generate unique version codes for each split APK // Generate unique version codes for each split APK
def abiVersionCodes = ['armeabi-v7a': 1, 'arm64-v8a': 2, 'x86': 3, 'x86_64': 4] def abiVersionCodes = ['armeabi-v7a': 1, 'arm64-v8a': 2, 'x86': 3, 'x86_64': 4]
def densityVersionCodes = ['ldpi': 1, 'mdpi': 2, 'hdpi': 3, 'xhdpi': 4, 'xxhdpi': 5, 'xxxhdpi': 6] applicationVariants.all { variant ->
android.applicationVariants.all { variant ->
variant.outputs.each { output -> variant.outputs.each { output ->
def baseVersionCode = 19 // Current versionCode 20from defaultConfig def baseVersionCode = 20 // Current versionCode from defaultConfig
def abiName = output.getFilter(com.android.build.OutputFile.ABI) def abiName = output.getFilter(com.android.build.OutputFile.ABI)
def densityName = output.getFilter(com.android.build.OutputFile.DENSITY)
def versionCode = baseVersionCode * 100 // Base multiplier
def versionCode 20= baseVersionCode * 100 // Base multiplier
if (abiName != null) { if (abiName != null) {
versionCode 20+= abiVersionCodes.get(abiName) * 10 versionCode += abiVersionCodes.get(abiName)
} }
if (densityName != null) {
versionCode 20+= densityVersionCodes.get(densityName)
}
output.versionCodeOverride = versionCode output.versionCodeOverride = versionCode
} }
} }

View file

@ -10,7 +10,7 @@
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit

1
app/Streams.tsx Normal file
View file

@ -0,0 +1 @@

View file

@ -461,7 +461,7 @@
); );
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
PRODUCT_BUNDLE_IDENTIFIER = com.nuvio.app; PRODUCT_BUNDLE_IDENTIFIER = com.nuvio.app;
PRODUCT_NAME = Nuvio; PRODUCT_NAME = "Nuvio";
SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@ -492,8 +492,8 @@
"-lc++", "-lc++",
); );
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = com.nuvio.app; PRODUCT_BUNDLE_IDENTIFIER = "com.nuvio.app";
PRODUCT_NAME = Nuvio; PRODUCT_NAME = "Nuvio";
SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";

View file

@ -2506,7 +2506,7 @@ PODS:
- ReactCommon/turbomodule/core - ReactCommon/turbomodule/core
- ReactNativeDependencies - ReactNativeDependencies
- Yoga - Yoga
- RNSentry (7.2.0): - RNSentry (7.3.0):
- hermes-engine - hermes-engine
- RCTRequired - RCTRequired
- RCTTypeSafety - RCTTypeSafety
@ -2528,7 +2528,7 @@ PODS:
- ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core - ReactCommon/turbomodule/core
- ReactNativeDependencies - ReactNativeDependencies
- Sentry/HybridSDK (= 8.56.1) - Sentry/HybridSDK (= 8.56.2)
- Yoga - Yoga
- RNSVG (15.12.1): - RNSVG (15.12.1):
- hermes-engine - hermes-engine
@ -2677,7 +2677,7 @@ PODS:
- SDWebImageWebPCoder (0.14.6): - SDWebImageWebPCoder (0.14.6):
- libwebp (~> 1.0) - libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17) - SDWebImage/Core (~> 5.17)
- Sentry/HybridSDK (8.56.1) - Sentry/HybridSDK (8.56.2)
- SwiftUIIntrospect (1.3.0) - SwiftUIIntrospect (1.3.0)
- Yoga (0.0.0) - Yoga (0.0.0)
@ -3225,14 +3225,14 @@ SPEC CHECKSUMS:
RNGestureHandler: 2914750df066d89bf9d8f48a10ad5f0051108ac3 RNGestureHandler: 2914750df066d89bf9d8f48a10ad5f0051108ac3
RNReanimated: 3895a29fdf77bbe2a627e1ed599a5e5d1df76c29 RNReanimated: 3895a29fdf77bbe2a627e1ed599a5e5d1df76c29
RNScreens: d8d6f1792f6e7ac12b0190d33d8d390efc0c1845 RNScreens: d8d6f1792f6e7ac12b0190d33d8d390efc0c1845
RNSentry: 41979b419908128847ef662cc130a400b7576fa9 RNSentry: 7726bf35e00ab799f50c4618df6f5417553678a0
RNSVG: 31d6639663c249b7d5abc9728dde2041eb2a3c34 RNSVG: 31d6639663c249b7d5abc9728dde2041eb2a3c34
RNVectorIcons: 4351544f100d4f12cac156a7c13399e60bab3e26 RNVectorIcons: 4351544f100d4f12cac156a7c13399e60bab3e26
RNWorklets: 54d8dffb7f645873a58484658ddfd4bd1a9a0bc1 RNWorklets: 54d8dffb7f645873a58484658ddfd4bd1a9a0bc1
SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a
SDWebImageAVIFCoder: afe194a084e851f70228e4be35ef651df0fc5c57 SDWebImageAVIFCoder: afe194a084e851f70228e4be35ef651df0fc5c57
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
Sentry: b3ec44d01708fce73f99b544beb57e890eca4406 Sentry: b53951377b78e21a734f5dc8318e333dbfc682d7
SwiftUIIntrospect: fee9aa07293ee280373a591e1824e8ddc869ba5d SwiftUIIntrospect: fee9aa07293ee280373a591e1824e8ddc869ba5d
Yoga: 051f086b5ccf465ff2ed38a2cf5a558ae01aaaa1 Yoga: 051f086b5ccf465ff2ed38a2cf5a558ae01aaaa1

164
package-lock.json generated
View file

@ -27,7 +27,7 @@
"@react-navigation/native": "^7.1.6", "@react-navigation/native": "^7.1.6",
"@react-navigation/native-stack": "^7.3.10", "@react-navigation/native-stack": "^7.3.10",
"@react-navigation/stack": "^7.2.10", "@react-navigation/stack": "^7.2.10",
"@sentry/react-native": "~7.2.0", "@sentry/react-native": "~7.3.0",
"@shopify/flash-list": "2.0.2", "@shopify/flash-list": "2.0.2",
"@supabase/supabase-js": "^2.54.0", "@supabase/supabase-js": "^2.54.0",
"@types/lodash": "^4.17.16", "@types/lodash": "^4.17.16",
@ -3284,50 +3284,50 @@
} }
}, },
"node_modules/@sentry-internal/browser-utils": { "node_modules/@sentry-internal/browser-utils": {
"version": "10.12.0", "version": "10.18.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.12.0.tgz", "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.18.0.tgz",
"integrity": "sha512-dozbx389jhKynj0d657FsgbBVOar7pX3mb6GjqCxslXF0VKpZH2Xks0U32RgDY/nK27O+o095IWz7YvjVmPkDw==", "integrity": "sha512-6Y5VkNcj5ecIFsKdL8/7hrLt7pCuWR4BRLsKOHAmhdCnXtobf7v6DeBow2Hk5yEYO0AwjP5mqvoBAewbS+h3GA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sentry/core": "10.12.0" "@sentry/core": "10.18.0"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@sentry-internal/feedback": { "node_modules/@sentry-internal/feedback": {
"version": "10.12.0", "version": "10.18.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.12.0.tgz", "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.18.0.tgz",
"integrity": "sha512-0+7ceO6yQPPqfxRc9ue/xoPHKcnB917ezPaehGQNfAFNQB9PNTG1y55+8mRu0Fw+ANbZeCt/HyoCmXuRdxmkpg==", "integrity": "sha512-uuupIivGPCpRStMU1I3sYPgD+pl8PqNV1DSVgVS5LF99h8tqjmRGS1xkCrUaUhVhVmsnxzbnvXb1hsOaCXX7DA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sentry/core": "10.12.0" "@sentry/core": "10.18.0"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@sentry-internal/replay": { "node_modules/@sentry-internal/replay": {
"version": "10.12.0", "version": "10.18.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.12.0.tgz", "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.18.0.tgz",
"integrity": "sha512-/1093gSNGN5KlOBsuyAl33JkzGiG38kCnxswQLZWpPpR6LBbR1Ddb18HjhDpoQNNEZybJBgJC3a5NKl43C2TSQ==", "integrity": "sha512-ixr3K19q4oTRgM0xANi+8ThDUbxV5iixUIgvJrT7c1L6yyidovIwO0D82ZY3phUfMkgE+mX3cxX46gXTRTglKQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sentry-internal/browser-utils": "10.12.0", "@sentry-internal/browser-utils": "10.18.0",
"@sentry/core": "10.12.0" "@sentry/core": "10.18.0"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@sentry-internal/replay-canvas": { "node_modules/@sentry-internal/replay-canvas": {
"version": "10.12.0", "version": "10.18.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.12.0.tgz", "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.18.0.tgz",
"integrity": "sha512-W/z1/+69i3INNfPjD1KuinSNaRQaApjzwb37IFmiyF440F93hxmEYgXHk3poOlYYaigl2JMYbysGPWOiXnqUXA==", "integrity": "sha512-asp1biXA+F5HAKl7RvPbf5s087bg1bpxMB9E69xWc1ECUfFMPrFRNS7mAJ5A8DTd1K74E9cFsLl6zO29HpH4+w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sentry-internal/replay": "10.12.0", "@sentry-internal/replay": "10.18.0",
"@sentry/core": "10.12.0" "@sentry/core": "10.18.0"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@ -3343,25 +3343,25 @@
} }
}, },
"node_modules/@sentry/browser": { "node_modules/@sentry/browser": {
"version": "10.12.0", "version": "10.18.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.12.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.18.0.tgz",
"integrity": "sha512-lKyaB2NFmr7SxPjmMTLLhQ7xfxaY3kdkMhpzuRI5qwOngtKt4+FtvNYHRuz+PTtEFv4OaHhNNbRn6r91gWguQg==", "integrity": "sha512-JrPfxjCsuVYUe16U4fo4W2Fn0f9BwRev3G28a4ZIkwKwJo+qSnIk1mT8Eam8nwNCU8MZjB4KNE9w2p0kaoQxvQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sentry-internal/browser-utils": "10.12.0", "@sentry-internal/browser-utils": "10.18.0",
"@sentry-internal/feedback": "10.12.0", "@sentry-internal/feedback": "10.18.0",
"@sentry-internal/replay": "10.12.0", "@sentry-internal/replay": "10.18.0",
"@sentry-internal/replay-canvas": "10.12.0", "@sentry-internal/replay-canvas": "10.18.0",
"@sentry/core": "10.12.0" "@sentry/core": "10.18.0"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@sentry/cli": { "node_modules/@sentry/cli": {
"version": "2.55.0", "version": "2.56.0",
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.55.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.56.0.tgz",
"integrity": "sha512-cynvcIM2xL8ddwELyFRSpZQw4UtFZzoM2rId2l9vg7+wDREPDocMJB9lEQpBIo3eqhp9JswqUT037yjO6iJ5Sw==", "integrity": "sha512-br6+1nTPUV5EG1oaxLzxv31kREFKr49Y1+3jutfMUz9Nl8VyVP7o9YwakB/YWl+0Vi0NXg5vq7qsd/OOuV5j8w==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
@ -3378,20 +3378,20 @@
"node": ">= 10" "node": ">= 10"
}, },
"optionalDependencies": { "optionalDependencies": {
"@sentry/cli-darwin": "2.55.0", "@sentry/cli-darwin": "2.56.0",
"@sentry/cli-linux-arm": "2.55.0", "@sentry/cli-linux-arm": "2.56.0",
"@sentry/cli-linux-arm64": "2.55.0", "@sentry/cli-linux-arm64": "2.56.0",
"@sentry/cli-linux-i686": "2.55.0", "@sentry/cli-linux-i686": "2.56.0",
"@sentry/cli-linux-x64": "2.55.0", "@sentry/cli-linux-x64": "2.56.0",
"@sentry/cli-win32-arm64": "2.55.0", "@sentry/cli-win32-arm64": "2.56.0",
"@sentry/cli-win32-i686": "2.55.0", "@sentry/cli-win32-i686": "2.56.0",
"@sentry/cli-win32-x64": "2.55.0" "@sentry/cli-win32-x64": "2.56.0"
} }
}, },
"node_modules/@sentry/cli-darwin": { "node_modules/@sentry/cli-darwin": {
"version": "2.55.0", "version": "2.56.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.55.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.56.0.tgz",
"integrity": "sha512-jGHE7SHHzqXUmnsmRLgorVH6nmMmTjQQXdPZbSL5tRtH8d3OIYrVNr5D72DSgD26XAPBDMV0ibqOQ9NKoiSpfA==", "integrity": "sha512-CzXFWbv3GrjU0gFlUM9jt0fvJmyo5ktty4HGxRFfS/eMC6xW58Gg/sEeMVEkdvk5osKooX/YEgfLBdo4zvuWDA==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"optional": true, "optional": true,
"os": [ "os": [
@ -3402,9 +3402,9 @@
} }
}, },
"node_modules/@sentry/cli-linux-arm": { "node_modules/@sentry/cli-linux-arm": {
"version": "2.55.0", "version": "2.56.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.55.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.56.0.tgz",
"integrity": "sha512-ATjU0PsiWADSPLF/kZroLZ7FPKd5W9TDWHVkKNwIUNTei702LFgTjNeRwOIzTgSvG3yTmVEqtwFQfFN/7hnVXQ==", "integrity": "sha512-vQCCMhZLugPmr25XBoP94dpQsFa110qK5SBUVJcRpJKyzMZd+6ueeHNslq2mB0OF4BwL1qd/ZDIa4nxa1+0rjQ==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -3420,9 +3420,9 @@
} }
}, },
"node_modules/@sentry/cli-linux-arm64": { "node_modules/@sentry/cli-linux-arm64": {
"version": "2.55.0", "version": "2.56.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.55.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.56.0.tgz",
"integrity": "sha512-jNB/0/gFcOuDCaY/TqeuEpsy/k52dwyk1SOV3s1ku4DUsln6govTppeAGRewY3T1Rj9B2vgIWTrnB8KVh9+Rgg==", "integrity": "sha512-91d5ZlC989j/t+TXor/glPyx6SnLFS/SlJ9fIrHIQohdGKyWWSFb4VKUan8Ok3GYu9SUzKTMByryIOoYEmeGVw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -3438,9 +3438,9 @@
} }
}, },
"node_modules/@sentry/cli-linux-i686": { "node_modules/@sentry/cli-linux-i686": {
"version": "2.55.0", "version": "2.56.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.55.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.56.0.tgz",
"integrity": "sha512-8LZjo6PncTM6bWdaggscNOi5r7F/fqRREsCwvd51dcjGj7Kp1plqo9feEzYQ+jq+KUzVCiWfHrUjddFmYyZJrg==", "integrity": "sha512-MZzXuq1Q/TktN81DUs6XSBU752pG3XWSJdZR+NCStIg3l8s3O/Pwh6OcDHTYqgwsYJaGBpA0fP2Afl5XeSAUNg==",
"cpu": [ "cpu": [
"x86", "x86",
"ia32" "ia32"
@ -3457,9 +3457,9 @@
} }
}, },
"node_modules/@sentry/cli-linux-x64": { "node_modules/@sentry/cli-linux-x64": {
"version": "2.55.0", "version": "2.56.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.55.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.56.0.tgz",
"integrity": "sha512-5LUVvq74Yj2cZZy5g5o/54dcWEaX4rf3myTHy73AKhRj1PABtOkfexOLbF9xSrZy95WXWaXyeH+k5n5z/vtHfA==", "integrity": "sha512-INOO2OQ90Y3UzYgHRdrHdKC/0es3YSHLv0iNNgQwllL0YZihSVNYSSrZqcPq8oSDllEy9Vt9oOm/7qEnUP2Kfw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -3475,9 +3475,9 @@
} }
}, },
"node_modules/@sentry/cli-win32-arm64": { "node_modules/@sentry/cli-win32-arm64": {
"version": "2.55.0", "version": "2.56.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.55.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.56.0.tgz",
"integrity": "sha512-cWIQdzm1pfLwPARsV6dUb8TVd6Y3V1A2VWxjTons3Ift6GvtVmiAe0OWL8t2Yt95i8v61kTD/6Tq21OAaogqzA==", "integrity": "sha512-eUvkVk9KK01q6/qyugQPh7dAxqFPbgOa62QAoSwo11WQFYc3NPgJLilFWLQo+nahHGYKh6PKuCJ5tcqnQq5Hkg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -3491,9 +3491,9 @@
} }
}, },
"node_modules/@sentry/cli-win32-i686": { "node_modules/@sentry/cli-win32-i686": {
"version": "2.55.0", "version": "2.56.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.55.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.56.0.tgz",
"integrity": "sha512-ldepCn2t9r4I0wvgk7NRaA7coJyy4rTQAzM66u9j5nTEsUldf66xym6esd5ZZRAaJUjffqvHqUIr/lrieTIrVg==", "integrity": "sha512-mpCA8hKXuvT17bl1H/54KOa5i+02VBBHVlOiP3ltyBuQUqfvX/30Zl/86Spy+ikodovZWAHv5e5FpyXbY1/mPw==",
"cpu": [ "cpu": [
"x86", "x86",
"ia32" "ia32"
@ -3508,9 +3508,9 @@
} }
}, },
"node_modules/@sentry/cli-win32-x64": { "node_modules/@sentry/cli-win32-x64": {
"version": "2.55.0", "version": "2.56.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.55.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.56.0.tgz",
"integrity": "sha512-4hPc/I/9tXx+HLTdTGwlagtAfDSIa2AoTUP30tl32NAYQhx9a6niUbPAemK2qfxesiufJ7D2djX83rCw6WnJVA==", "integrity": "sha512-UV0pXNls+/ViAU/3XsHLLNEHCsRYaGEwJdY3HyGIufSlglxrX6BVApkV9ziGi4WAxcJWLjQdfcEs6V5B+wBy0A==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -3524,22 +3524,22 @@
} }
}, },
"node_modules/@sentry/core": { "node_modules/@sentry/core": {
"version": "10.12.0", "version": "10.18.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.12.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.18.0.tgz",
"integrity": "sha512-Jrf0Yo7DvmI/ZQcvBnA0xKNAFkJlVC/fMlvcin+5IrFNRcqOToZ2vtF+XqTgjRZymXQNE8s1QTD7IomPHk0TAw==", "integrity": "sha512-zlhAlzc/Qpza8f/CMUb7zg/9FOhWouKAm9zyV9jZlx9lL6WceVbUEwQ3rq8ncGgM+LMwlASCOjsz5a728vAhCw==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@sentry/react": { "node_modules/@sentry/react": {
"version": "10.12.0", "version": "10.18.0",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-10.12.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/react/-/react-10.18.0.tgz",
"integrity": "sha512-TpqgdoYbkf5JynmmW2oQhHQ/h5w+XPYk0cEb/UrsGlvJvnBSR+5tgh0AqxCSi3gvtp82rAXI5w1TyRPBbhLDBw==", "integrity": "sha512-mLVJzF/+VFTNkqVqApU9QLrTAahASLKLaPreJ5LUXhEbCEiBUTQNZIn8Js+tDisHwbdy9k94XC1/OLxld3Calg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sentry/browser": "10.12.0", "@sentry/browser": "10.18.0",
"@sentry/core": "10.12.0", "@sentry/core": "10.18.0",
"hoist-non-react-statics": "^3.3.2" "hoist-non-react-statics": "^3.3.2"
}, },
"engines": { "engines": {
@ -3550,17 +3550,17 @@
} }
}, },
"node_modules/@sentry/react-native": { "node_modules/@sentry/react-native": {
"version": "7.2.0", "version": "7.3.0",
"resolved": "https://registry.npmjs.org/@sentry/react-native/-/react-native-7.2.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/react-native/-/react-native-7.3.0.tgz",
"integrity": "sha512-rjqYgEjntPz1sPysud78wi4B9ui7LBVPsG6qr8s/htLMYho9GPGFA5dF+eqsQWqMX8NDReAxNkLTC4+gCNklLQ==", "integrity": "sha512-VrvHK062zq+zuwFffloUjJ2K/+I+IO+tmtgwQMW8t1GkjdtVmrKm3QfZQVzfsXW53sehqkK9CgIHawj4p7DKjQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sentry/babel-plugin-component-annotate": "4.3.0", "@sentry/babel-plugin-component-annotate": "4.3.0",
"@sentry/browser": "10.12.0", "@sentry/browser": "10.18.0",
"@sentry/cli": "2.55.0", "@sentry/cli": "2.56.0",
"@sentry/core": "10.12.0", "@sentry/core": "10.18.0",
"@sentry/react": "10.12.0", "@sentry/react": "10.18.0",
"@sentry/types": "10.12.0" "@sentry/types": "10.18.0"
}, },
"bin": { "bin": {
"sentry-expo-upload-sourcemaps": "scripts/expo-upload-sourcemaps.js" "sentry-expo-upload-sourcemaps": "scripts/expo-upload-sourcemaps.js"
@ -3577,12 +3577,12 @@
} }
}, },
"node_modules/@sentry/types": { "node_modules/@sentry/types": {
"version": "10.12.0", "version": "10.18.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-10.12.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/types/-/types-10.18.0.tgz",
"integrity": "sha512-sKGj3l3V8ZKISh2Tu88bHfnm5ztkRtSLdmpZ6TmCeJdSM9pV+RRd6CMJ0RnSEXmYHselPNUod521t2NQFd4W1w==", "integrity": "sha512-AVUL63Lotvd7cujtch1A7Rax5syleB7jAP/I5sdCs6UvDc5VqmuTNsrg5DfjBNOOPPoGGfbSBaMBQAimvtNFaA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sentry/core": "10.12.0" "@sentry/core": "10.18.0"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"

View file

@ -27,7 +27,7 @@
"@react-navigation/native": "^7.1.6", "@react-navigation/native": "^7.1.6",
"@react-navigation/native-stack": "^7.3.10", "@react-navigation/native-stack": "^7.3.10",
"@react-navigation/stack": "^7.2.10", "@react-navigation/stack": "^7.2.10",
"@sentry/react-native": "~7.2.0", "@sentry/react-native": "~7.3.0",
"@shopify/flash-list": "2.0.2", "@shopify/flash-list": "2.0.2",
"@supabase/supabase-js": "^2.54.0", "@supabase/supabase-js": "^2.54.0",
"@types/lodash": "^4.17.16", "@types/lodash": "^4.17.16",

View file

@ -1,4 +1,4 @@
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
import { import {
View, View,
Text, Text,
@ -16,11 +16,17 @@ const { width, height } = Dimensions.get('window');
interface MetadataLoadingScreenProps { interface MetadataLoadingScreenProps {
type?: 'movie' | 'series'; type?: 'movie' | 'series';
onExitComplete?: () => void;
} }
export const MetadataLoadingScreen: React.FC<MetadataLoadingScreenProps> = ({ export interface MetadataLoadingScreenRef {
type = 'movie' exit: () => void;
}) => { }
export const MetadataLoadingScreen = forwardRef<MetadataLoadingScreenRef, MetadataLoadingScreenProps>(({
type = 'movie',
onExitComplete
}, ref) => {
const { currentTheme } = useTheme(); const { currentTheme } = useTheme();
// Animation values - removed fadeAnim since parent handles transitions // Animation values - removed fadeAnim since parent handles transitions
@ -32,6 +38,39 @@ export const MetadataLoadingScreen: React.FC<MetadataLoadingScreenProps> = ({
const sceneScale = useRef(new Animated.Value(0.95)).current; const sceneScale = useRef(new Animated.Value(0.95)).current;
const sceneTranslateY = useRef(new Animated.Value(8)).current; const sceneTranslateY = useRef(new Animated.Value(8)).current;
// Exit animation function
const exit = () => {
const exitAnimation = Animated.parallel([
Animated.timing(sceneOpacity, {
toValue: 0,
duration: 200,
easing: Easing.bezier(0.25, 0.1, 0.25, 1.0),
useNativeDriver: true,
}),
Animated.timing(sceneScale, {
toValue: 0.95,
duration: 200,
easing: Easing.bezier(0.25, 0.1, 0.25, 1.0),
useNativeDriver: true,
}),
Animated.timing(sceneTranslateY, {
toValue: 8,
duration: 200,
easing: Easing.bezier(0.25, 0.1, 0.25, 1.0),
useNativeDriver: true,
}),
]);
exitAnimation.start(() => {
onExitComplete?.();
});
};
// Expose exit method through ref
useImperativeHandle(ref, () => ({
exit,
}));
useEffect(() => { useEffect(() => {
// Scene entrance animation (matching tab navigator) // Scene entrance animation (matching tab navigator)
const sceneAnimation = Animated.parallel([ const sceneAnimation = Animated.parallel([
@ -61,13 +100,15 @@ export const MetadataLoadingScreen: React.FC<MetadataLoadingScreenProps> = ({
const pulseAnimation = Animated.loop( const pulseAnimation = Animated.loop(
Animated.sequence([ Animated.sequence([
Animated.timing(pulseAnim, { Animated.timing(pulseAnim, {
toValue: 1, toValue: 0.8,
duration: 1200, duration: 2500,
easing: Easing.bezier(0.4, 0, 0.2, 1),
useNativeDriver: true, useNativeDriver: true,
}), }),
Animated.timing(pulseAnim, { Animated.timing(pulseAnim, {
toValue: 0.3, toValue: 0.4,
duration: 1200, duration: 2500,
easing: Easing.bezier(0.4, 0, 0.2, 1),
useNativeDriver: true, useNativeDriver: true,
}), }),
]) ])
@ -77,7 +118,8 @@ export const MetadataLoadingScreen: React.FC<MetadataLoadingScreenProps> = ({
const shimmerAnimation = Animated.loop( const shimmerAnimation = Animated.loop(
Animated.timing(shimmerAnim, { Animated.timing(shimmerAnim, {
toValue: 1, toValue: 1,
duration: 1500, duration: 2500,
easing: Easing.inOut(Easing.ease),
useNativeDriver: true, useNativeDriver: true,
}) })
); );
@ -264,7 +306,7 @@ export const MetadataLoadingScreen: React.FC<MetadataLoadingScreenProps> = ({
</Animated.View> </Animated.View>
</SafeAreaView> </SafeAreaView>
); );
}; });
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {

View file

@ -67,7 +67,6 @@ interface HeroSectionProps {
metadata: any; metadata: any;
bannerImage: string | null; bannerImage: string | null;
loadingBanner: boolean; loadingBanner: boolean;
logoLoadError: boolean;
scrollY: SharedValue<number>; scrollY: SharedValue<number>;
heroHeight: SharedValue<number>; heroHeight: SharedValue<number>;
heroOpacity: SharedValue<number>; heroOpacity: SharedValue<number>;
@ -93,7 +92,6 @@ interface HeroSectionProps {
navigation: any; navigation: any;
getPlayButtonText: () => string; getPlayButtonText: () => string;
setBannerImage: (bannerImage: string | null) => void; setBannerImage: (bannerImage: string | null) => void;
setLogoLoadError: (error: boolean) => void;
groupedEpisodes?: { [seasonNumber: number]: any[] }; groupedEpisodes?: { [seasonNumber: number]: any[] };
dynamicBackgroundColor?: string; dynamicBackgroundColor?: string;
handleBack: () => void; handleBack: () => void;
@ -772,7 +770,6 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
metadata, metadata,
bannerImage, bannerImage,
loadingBanner, loadingBanner,
logoLoadError,
scrollY, scrollY,
heroHeight, heroHeight,
heroOpacity, heroOpacity,
@ -790,7 +787,6 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
navigation, navigation,
getPlayButtonText, getPlayButtonText,
setBannerImage, setBannerImage,
setLogoLoadError,
groupedEpisodes, groupedEpisodes,
dynamicBackgroundColor, dynamicBackgroundColor,
handleBack, handleBack,
@ -942,6 +938,36 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
const logoUri = useMemo(() => { const logoUri = useMemo(() => {
return metadata?.logo as string | undefined; return metadata?.logo as string | undefined;
}, [metadata?.logo]); }, [metadata?.logo]);
// Stable logo state management - prevent flickering between logo and text
const [stableLogoUri, setStableLogoUri] = useState<string | null>(null);
const [logoHasLoadedSuccessfully, setLogoHasLoadedSuccessfully] = useState(false);
// Update stable logo URI when metadata logo changes
useEffect(() => {
if (metadata?.logo && metadata.logo !== stableLogoUri) {
setStableLogoUri(metadata.logo);
setLogoHasLoadedSuccessfully(false); // Reset for new logo
} else if (!metadata?.logo && stableLogoUri) {
// Clear logo if metadata no longer has one
setStableLogoUri(null);
setLogoHasLoadedSuccessfully(false);
}
}, [metadata?.logo, stableLogoUri]);
// Handle logo load success - once loaded successfully, keep it stable
const handleLogoLoad = useCallback(() => {
setLogoHasLoadedSuccessfully(true);
}, []);
// Handle logo load error - only set error if logo hasn't loaded successfully before
const handleLogoError = useCallback(() => {
if (!logoHasLoadedSuccessfully) {
// Only remove logo if it never loaded successfully
setStableLogoUri(null);
}
// If logo loaded successfully before, keep showing it even if it fails later
}, [logoHasLoadedSuccessfully]);
// Performance optimization: Lazy loading setup // Performance optimization: Lazy loading setup
useEffect(() => { useEffect(() => {
@ -1548,14 +1574,13 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
{/* Optimized Title/Logo - Show logo immediately when available */} {/* Optimized Title/Logo - Show logo immediately when available */}
<Animated.View style={[styles.logoContainer, titleCardAnimatedStyle]}> <Animated.View style={[styles.logoContainer, titleCardAnimatedStyle]}>
<Animated.View style={[styles.titleLogoContainer, logoAnimatedStyle]}> <Animated.View style={[styles.titleLogoContainer, logoAnimatedStyle]}>
{logoUri && !logoLoadError ? ( {stableLogoUri ? (
<Image <Image
source={{ uri: logoUri }} source={{ uri: stableLogoUri }}
style={isTablet ? styles.tabletTitleLogo : styles.titleLogo} style={isTablet ? styles.tabletTitleLogo : styles.titleLogo}
resizeMode={'contain'} resizeMode={'contain'}
onError={() => { onLoad={handleLogoLoad}
runOnJS(setLogoLoadError)(true); onError={handleLogoError}
}}
/> />
) : ( ) : (
<Text style={[isTablet ? styles.tabletHeroTitle : styles.heroTitle, { color: themeColors.highEmphasis }]}> <Text style={[isTablet ? styles.tabletHeroTitle : styles.heroTitle, { color: themeColors.highEmphasis }]}>

View file

@ -43,7 +43,7 @@ import { RouteProp } from '@react-navigation/native';
import { NavigationProp } from '@react-navigation/native'; import { NavigationProp } from '@react-navigation/native';
import { RootStackParamList } from '../navigation/AppNavigator'; import { RootStackParamList } from '../navigation/AppNavigator';
import { useSettings } from '../hooks/useSettings'; import { useSettings } from '../hooks/useSettings';
import { MetadataLoadingScreen } from '../components/loading/MetadataLoadingScreen'; import { MetadataLoadingScreen, MetadataLoadingScreenRef } from '../components/loading/MetadataLoadingScreen';
import { useTrailer } from '../contexts/TrailerContext'; import { useTrailer } from '../contexts/TrailerContext';
import FastImage from '@d11/react-native-fast-image'; import FastImage from '@d11/react-native-fast-image';
@ -103,6 +103,8 @@ const MetadataScreen: React.FC = () => {
const [commentBottomSheetVisible, setCommentBottomSheetVisible] = useState(false); const [commentBottomSheetVisible, setCommentBottomSheetVisible] = useState(false);
const [selectedComment, setSelectedComment] = useState<any>(null); const [selectedComment, setSelectedComment] = useState<any>(null);
const [revealedSpoilers, setRevealedSpoilers] = useState<Set<string>>(new Set()); const [revealedSpoilers, setRevealedSpoilers] = useState<Set<string>>(new Set());
const loadingScreenRef = useRef<MetadataLoadingScreenRef>(null);
const [loadingScreenExited, setLoadingScreenExited] = useState(false);
// Debug state changes // Debug state changes
@ -157,24 +159,26 @@ const MetadataScreen: React.FC = () => {
// Animate network section when data becomes available (for series) // Animate network section when data becomes available (for series)
useEffect(() => { useEffect(() => {
const hasNetworks = metadata?.networks && metadata.networks.length > 0; const hasNetworks = metadata?.networks && metadata.networks.length > 0;
const hasDescription = !!metadata?.description;
const isSeries = Object.keys(groupedEpisodes).length > 0; const isSeries = Object.keys(groupedEpisodes).length > 0;
const shouldShow = shouldLoadSecondaryData && hasNetworks && isSeries; const shouldShow = shouldLoadSecondaryData && hasNetworks && hasDescription && isSeries;
if (shouldShow && networkSectionOpacity.value === 0) { if (shouldShow && networkSectionOpacity.value === 0) {
networkSectionOpacity.value = withTiming(1, { duration: 400 }); networkSectionOpacity.value = withTiming(1, { duration: 400 });
} }
}, [metadata?.networks, Object.keys(groupedEpisodes).length, shouldLoadSecondaryData, networkSectionOpacity]); }, [metadata?.networks, metadata?.description, Object.keys(groupedEpisodes).length, shouldLoadSecondaryData, networkSectionOpacity]);
// Animate production section when data becomes available (for movies) // Animate production section when data becomes available (for movies)
useEffect(() => { useEffect(() => {
const hasNetworks = metadata?.networks && metadata.networks.length > 0; const hasNetworks = metadata?.networks && metadata.networks.length > 0;
const hasDescription = !!metadata?.description;
const isMovie = Object.keys(groupedEpisodes).length === 0; const isMovie = Object.keys(groupedEpisodes).length === 0;
const shouldShow = shouldLoadSecondaryData && hasNetworks && isMovie; const shouldShow = shouldLoadSecondaryData && hasNetworks && hasDescription && isMovie;
if (shouldShow && productionSectionOpacity.value === 0) { if (shouldShow && productionSectionOpacity.value === 0) {
productionSectionOpacity.value = withTiming(1, { duration: 400 }); productionSectionOpacity.value = withTiming(1, { duration: 400 });
} }
}, [metadata?.networks, Object.keys(groupedEpisodes).length, shouldLoadSecondaryData, productionSectionOpacity]); }, [metadata?.networks, metadata?.description, Object.keys(groupedEpisodes).length, shouldLoadSecondaryData, productionSectionOpacity]);
// Optimized hooks with memoization and conditional loading // Optimized hooks with memoization and conditional loading
const watchProgressData = useWatchProgress(id, Object.keys(groupedEpisodes).length > 0 ? 'series' : type as 'movie' | 'series', episodeId, episodes); const watchProgressData = useWatchProgress(id, Object.keys(groupedEpisodes).length > 0 ? 'series' : type as 'movie' | 'series', episodeId, episodes);
@ -471,9 +475,17 @@ const MetadataScreen: React.FC = () => {
} else if (!isReady && isContentReady) { } else if (!isReady && isContentReady) {
setIsContentReady(false); setIsContentReady(false);
transitionOpacity.value = 0; transitionOpacity.value = 0;
setLoadingScreenExited(false); // Reset for next load
} }
}, [isReady, isContentReady, isScreenFocused]); }, [isReady, isContentReady, isScreenFocused]);
// Trigger loading screen exit animation when content is ready
useEffect(() => {
if (isReady && isContentReady && !loadingScreenExited && loadingScreenRef.current) {
loadingScreenRef.current.exit();
}
}, [isReady, isContentReady, loadingScreenExited]);
// Optimized callback functions with reduced dependencies and haptics throttling // Optimized callback functions with reduced dependencies and haptics throttling
const handleToggleLibrary = useCallback(() => { const handleToggleLibrary = useCallback(() => {
if (isScreenFocused) { if (isScreenFocused) {
@ -802,15 +814,22 @@ const MetadataScreen: React.FC = () => {
return ErrorComponent; return ErrorComponent;
} }
// Show loading screen if metadata is not yet available // Show loading screen if metadata is not yet available or exit animation hasn't completed
if (loading || !isContentReady) { if (loading || !isContentReady || !loadingScreenExited) {
console.log('🔍 [MetadataScreen] Showing loading screen:', { console.log('🔍 [MetadataScreen] Showing loading screen:', {
isLoading: loading, isLoading: loading,
isContentReady, isContentReady,
loadingScreenExited,
hasMetadata: !!metadata, hasMetadata: !!metadata,
errorMessage: metadataError errorMessage: metadataError
}); });
return <MetadataLoadingScreen type={Object.keys(groupedEpisodes).length > 0 ? 'series' : type as 'movie' | 'series'} />; return (
<MetadataLoadingScreen
ref={loadingScreenRef}
type={Object.keys(groupedEpisodes).length > 0 ? 'series' : type as 'movie' | 'series'}
onExitComplete={() => setLoadingScreenExited(true)}
/>
);
} }
return ( return (
@ -853,7 +872,6 @@ const MetadataScreen: React.FC = () => {
metadata={metadata} metadata={metadata}
bannerImage={assetData.bannerImage} bannerImage={assetData.bannerImage}
loadingBanner={assetData.loadingBanner} loadingBanner={assetData.loadingBanner}
logoLoadError={assetData.logoLoadError}
scrollY={animations.scrollY} scrollY={animations.scrollY}
heroHeight={animations.heroHeight} heroHeight={animations.heroHeight}
heroOpacity={animations.heroOpacity} heroOpacity={animations.heroOpacity}
@ -872,7 +890,6 @@ const MetadataScreen: React.FC = () => {
navigation={navigation} navigation={navigation}
getPlayButtonText={watchProgressData.getPlayButtonText} getPlayButtonText={watchProgressData.getPlayButtonText}
setBannerImage={assetData.setBannerImage} setBannerImage={assetData.setBannerImage}
setLogoLoadError={assetData.setLogoLoadError}
groupedEpisodes={groupedEpisodes} groupedEpisodes={groupedEpisodes}
dynamicBackgroundColor={dynamicBackgroundColor} dynamicBackgroundColor={dynamicBackgroundColor}
handleBack={handleBack} handleBack={handleBack}
@ -893,7 +910,7 @@ const MetadataScreen: React.FC = () => {
/> />
{/* Production info row — shown below description and above cast for series */} {/* Production info row — shown below description and above cast for series */}
{shouldLoadSecondaryData && Object.keys(groupedEpisodes).length > 0 && metadata?.networks && metadata.networks.length > 0 && ( {shouldLoadSecondaryData && Object.keys(groupedEpisodes).length > 0 && metadata?.networks && metadata.networks.length > 0 && metadata?.description && (
<Animated.View style={[styles.productionContainer, networkSectionAnimatedStyle]}> <Animated.View style={[styles.productionContainer, networkSectionAnimatedStyle]}>
<Text style={styles.productionHeader}>Network</Text> <Text style={styles.productionHeader}>Network</Text>
<View style={styles.productionRow}> <View style={styles.productionRow}>
@ -928,7 +945,8 @@ const MetadataScreen: React.FC = () => {
{shouldLoadSecondaryData && {shouldLoadSecondaryData &&
Object.keys(groupedEpisodes).length === 0 && Object.keys(groupedEpisodes).length === 0 &&
metadata?.networks && Array.isArray(metadata.networks) && metadata?.networks && Array.isArray(metadata.networks) &&
metadata.networks.some((n: any) => !!n?.logo) && ( metadata.networks.some((n: any) => !!n?.logo) &&
metadata?.description && (
<Animated.View style={[styles.productionContainer, productionSectionAnimatedStyle]}> <Animated.View style={[styles.productionContainer, productionSectionAnimatedStyle]}>
<Text style={styles.productionHeader}>Production</Text> <Text style={styles.productionHeader}>Production</Text>
<View style={styles.productionRow}> <View style={styles.productionRow}>