some ui chanegs for metadascreen

This commit is contained in:
tapframe 2025-08-07 01:36:24 +05:30
parent cc494bdf17
commit e0835ddbad
6 changed files with 868 additions and 88 deletions

697
package-lock.json generated
View file

@ -46,6 +46,7 @@
"react": "18.3.1",
"react-native": "0.76.9",
"react-native-gesture-handler": "~2.20.2",
"react-native-image-colors": "^2.5.0",
"react-native-immersive-mode": "^2.0.2",
"react-native-paper": "^5.13.1",
"react-native-reanimated": "^3.18.0",
@ -2847,26 +2848,6 @@
"node": ">=12"
}
},
"node_modules/@expo/rudder-sdk-node/node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/@expo/sdk-runtime-versions": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz",
@ -3206,6 +3187,149 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/@jimp/bmp": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.12.tgz",
"integrity": "sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==",
"license": "MIT",
"dependencies": {
"@jimp/utils": "^0.22.12",
"bmp-js": "^0.1.0"
},
"peerDependencies": {
"@jimp/custom": ">=0.3.5"
}
},
"node_modules/@jimp/core": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.12.tgz",
"integrity": "sha512-l0RR0dOPyzMKfjUW1uebzueFEDtCOj9fN6pyTYWWOM/VS4BciXQ1VVrJs8pO3kycGYZxncRKhCoygbNr8eEZQA==",
"license": "MIT",
"dependencies": {
"@jimp/utils": "^0.22.12",
"any-base": "^1.1.0",
"buffer": "^5.2.0",
"exif-parser": "^0.1.12",
"file-type": "^16.5.4",
"isomorphic-fetch": "^3.0.0",
"pixelmatch": "^4.0.2",
"tinycolor2": "^1.6.0"
}
},
"node_modules/@jimp/custom": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz",
"integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==",
"license": "MIT",
"dependencies": {
"@jimp/core": "^0.22.12"
}
},
"node_modules/@jimp/gif": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.22.12.tgz",
"integrity": "sha512-y6BFTJgch9mbor2H234VSjd9iwAhaNf/t3US5qpYIs0TSbAvM02Fbc28IaDETj9+4YB4676sz4RcN/zwhfu1pg==",
"license": "MIT",
"dependencies": {
"@jimp/utils": "^0.22.12",
"gifwrap": "^0.10.1",
"omggif": "^1.0.9"
},
"peerDependencies": {
"@jimp/custom": ">=0.3.5"
}
},
"node_modules/@jimp/jpeg": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.12.tgz",
"integrity": "sha512-Rq26XC/uQWaQKyb/5lksCTCxXhtY01NJeBN+dQv5yNYedN0i7iYu+fXEoRsfaJ8xZzjoANH8sns7rVP4GE7d/Q==",
"license": "MIT",
"dependencies": {
"@jimp/utils": "^0.22.12",
"jpeg-js": "^0.4.4"
},
"peerDependencies": {
"@jimp/custom": ">=0.3.5"
}
},
"node_modules/@jimp/plugin-resize": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz",
"integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==",
"license": "MIT",
"dependencies": {
"@jimp/utils": "^0.22.12"
},
"peerDependencies": {
"@jimp/custom": ">=0.3.5"
}
},
"node_modules/@jimp/png": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.22.12.tgz",
"integrity": "sha512-Mrp6dr3UTn+aLK8ty/dSKELz+Otdz1v4aAXzV5q53UDD2rbB5joKVJ/ChY310B+eRzNxIovbUF1KVrUsYdE8Hg==",
"license": "MIT",
"dependencies": {
"@jimp/utils": "^0.22.12",
"pngjs": "^6.0.0"
},
"peerDependencies": {
"@jimp/custom": ">=0.3.5"
}
},
"node_modules/@jimp/png/node_modules/pngjs": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz",
"integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==",
"license": "MIT",
"engines": {
"node": ">=12.13.0"
}
},
"node_modules/@jimp/tiff": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.12.tgz",
"integrity": "sha512-E1LtMh4RyJsoCAfAkBRVSYyZDTtLq9p9LUiiYP0vPtXyxX4BiYBUYihTLSBlCQg5nF2e4OpQg7SPrLdJ66u7jg==",
"license": "MIT",
"dependencies": {
"utif2": "^4.0.1"
},
"peerDependencies": {
"@jimp/custom": ">=0.3.5"
}
},
"node_modules/@jimp/types": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.12.tgz",
"integrity": "sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA==",
"license": "MIT",
"dependencies": {
"@jimp/bmp": "^0.22.12",
"@jimp/gif": "^0.22.12",
"@jimp/jpeg": "^0.22.12",
"@jimp/png": "^0.22.12",
"@jimp/tiff": "^0.22.12",
"timm": "^1.6.1"
},
"peerDependencies": {
"@jimp/custom": ">=0.3.5"
}
},
"node_modules/@jimp/utils": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz",
"integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==",
"license": "MIT",
"dependencies": {
"regenerator-runtime": "^0.13.3"
}
},
"node_modules/@jimp/utils/node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
"license": "MIT"
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.12",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
@ -3581,26 +3705,6 @@
"node": ">=6"
}
},
"node_modules/@react-native/community-cli-plugin/node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/@react-native/community-cli-plugin/node_modules/npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@ -4212,26 +4316,6 @@
"node": ">= 6"
}
},
"node_modules/@sentry/cli/node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/@sentry/core": {
"version": "8.54.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.54.0.tgz",
@ -4794,6 +4878,12 @@
"node": ">=4"
}
},
"node_modules/@tokenizer/token": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
"license": "MIT"
},
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@ -5003,6 +5093,156 @@
"@urql/core": "^5.0.0"
}
},
"node_modules/@vibrant/color": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@vibrant/color/-/color-4.0.0.tgz",
"integrity": "sha512-S9ItdqS1135wTXoIIqAJu8df9dqlOo6Boc5Y4MGsBTu9UmUOvOwfj5b4Ga6S5yrLAKmKYIactkz7zYJdMddkig==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/@vibrant/core": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@vibrant/core/-/core-4.0.0.tgz",
"integrity": "sha512-fqlVRUTDjEws9VNKvI3cDXM4wUT7fMFS+cVqEjJk3im+R5EvjJzPF6OAbNhfPzW04NvHNE555eY9FfhYuX3PRw==",
"license": "MIT",
"dependencies": {
"@vibrant/color": "^4.0.0",
"@vibrant/generator": "^4.0.0",
"@vibrant/image": "^4.0.0",
"@vibrant/quantizer": "^4.0.0",
"@vibrant/worker": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/@vibrant/generator": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@vibrant/generator/-/generator-4.0.0.tgz",
"integrity": "sha512-CqKAjmgHVDXJVo3Q5+9pUJOvksR7cN3bzx/6MbURYh7lA4rhsIewkUK155M6q0vfcUN3ETi/eTneCi0tLuM2Sg==",
"license": "MIT",
"dependencies": {
"@vibrant/color": "^4.0.0",
"@vibrant/types": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/@vibrant/generator-default": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@vibrant/generator-default/-/generator-default-4.0.3.tgz",
"integrity": "sha512-HZlfp19sDokODEkZF4p70QceARHgjP3a1Dmxg+dlblYMJM98jPq+azA0fzqKNR7R17JJNHxexpJEepEsNlG0gw==",
"license": "MIT",
"dependencies": {
"@vibrant/color": "^4.0.0",
"@vibrant/generator": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/@vibrant/image": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@vibrant/image/-/image-4.0.0.tgz",
"integrity": "sha512-Asv/7R/L701norosgvbjOVkodFiwcFihkXixA/gbAd6C+5GCts1Wm1NPk14FNKnM7eKkfAN+0wwPkdOH+PY/YA==",
"license": "MIT",
"dependencies": {
"@vibrant/color": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/@vibrant/image-browser": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@vibrant/image-browser/-/image-browser-4.0.0.tgz",
"integrity": "sha512-mXckzvJWiP575Y/wNtP87W/TPgyJoGlPBjW4E9YmNS6n4Jb6RqyHQA0ZVulqDslOxjSsihDzY7gpAORRclaoLg==",
"license": "MIT",
"dependencies": {
"@vibrant/image": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/@vibrant/image-node": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@vibrant/image-node/-/image-node-4.0.0.tgz",
"integrity": "sha512-m7yfnQtmo2y8z+tOjRFBx6q/qGnhl/ax2uCaj4TBkm4TtXfR4Dsn90wT6OWXmCFFzxIKHXKKEBShkxR+4RHseA==",
"license": "MIT",
"dependencies": {
"@jimp/custom": "^0.22.12",
"@jimp/plugin-resize": "^0.22.12",
"@jimp/types": "^0.22.12",
"@vibrant/image": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/@vibrant/quantizer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@vibrant/quantizer/-/quantizer-4.0.0.tgz",
"integrity": "sha512-YDGxmCv/RvHFtZghDlVRwH5GMxdGGozWS1JpUOUt73/F5zAKGiiier8F31K1npIXARn6/Gspvg/Rbg7qqyEr2A==",
"license": "MIT",
"dependencies": {
"@vibrant/color": "^4.0.0",
"@vibrant/image": "^4.0.0",
"@vibrant/types": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/@vibrant/quantizer-mmcq": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@vibrant/quantizer-mmcq/-/quantizer-mmcq-4.0.0.tgz",
"integrity": "sha512-TZqNiRoGGyCP8fH1XE6rvhFwLNv9D8MP1Xhz3K8tsuUweC6buWax3qLfrfEnkhtQnPJHaqvTfTOlIIXVMfRpow==",
"license": "MIT",
"dependencies": {
"@vibrant/color": "^4.0.0",
"@vibrant/image": "^4.0.0",
"@vibrant/quantizer": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/@vibrant/types": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@vibrant/types/-/types-4.0.0.tgz",
"integrity": "sha512-tA5TAbuROXcPkt+PWjmGfoaiEXyySVaNnCZovf6vXhCbMdrTTCQXvNCde2geiVl6YwtuU/Qrj9iZxS5jZ6yVIw==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/@vibrant/worker": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@vibrant/worker/-/worker-4.0.0.tgz",
"integrity": "sha512-nSaZZwWQKOgN/nPYUAIRF0/uoa7KpK91A+gjLmZZDgfN1enqxaiihmn+75ayNadW0c6cxAEpEFEHTONR5u9tMw==",
"license": "MIT",
"dependencies": {
"@vibrant/types": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/@xmldom/xmldom": {
"version": "0.7.13",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz",
@ -5176,6 +5416,12 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/any-base": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz",
"integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==",
"license": "MIT"
},
"node_modules/any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
@ -5713,6 +5959,12 @@
"node": ">=0.6"
}
},
"node_modules/bmp-js": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
"integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==",
"license": "MIT"
},
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@ -6500,26 +6752,6 @@
"node-fetch": "^2.7.0"
}
},
"node_modules/cross-fetch/node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@ -7218,6 +7450,15 @@
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
"license": "MIT"
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"license": "MIT",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/exec-async": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/exec-async/-/exec-async-2.2.0.tgz",
@ -7315,6 +7556,11 @@
"which": "bin/which"
}
},
"node_modules/exif-parser": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz",
"integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="
},
"node_modules/expo": {
"version": "52.0.44",
"resolved": "https://registry.npmjs.org/expo/-/expo-52.0.44.tgz",
@ -7894,6 +8140,23 @@
"integrity": "sha512-e6eB7zN6UBSwGVwrbWVH+gdLnkW9WwHhmq2YDK1Sh30pzx1onRVGBvogTlUeWxwTa+L86NYdo4hFkh7O8ZjSnA==",
"license": "MIT"
},
"node_modules/file-type": {
"version": "16.5.4",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz",
"integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==",
"license": "MIT",
"dependencies": {
"readable-web-to-node-stream": "^3.0.0",
"strtok3": "^6.2.4",
"token-types": "^4.1.1"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sindresorhus/file-type?sponsor=1"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@ -8243,6 +8506,16 @@
"assert-plus": "^1.0.0"
}
},
"node_modules/gifwrap": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.10.1.tgz",
"integrity": "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==",
"license": "MIT",
"dependencies": {
"image-q": "^4.0.0",
"omggif": "^1.0.10"
}
},
"node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
@ -8667,6 +8940,21 @@
"node": ">= 4"
}
},
"node_modules/image-q": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz",
"integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==",
"license": "MIT",
"dependencies": {
"@types/node": "16.9.1"
}
},
"node_modules/image-q/node_modules/@types/node": {
"version": "16.9.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz",
"integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==",
"license": "MIT"
},
"node_modules/image-size": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz",
@ -9070,6 +9358,16 @@
"node": ">=0.10.0"
}
},
"node_modules/isomorphic-fetch": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz",
"integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==",
"license": "MIT",
"dependencies": {
"node-fetch": "^2.6.1",
"whatwg-fetch": "^3.4.1"
}
},
"node_modules/isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@ -9311,6 +9609,12 @@
"integrity": "sha512-bF7vcQxbODoGK1imE2P9GS9aw4zD0Sd+Hni68IMZLj7zRnquH7dXUmMw9hDI5S/Jzt7q+IyTXN0rSg2GI0IKhQ==",
"license": "MIT"
},
"node_modules/jpeg-js": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz",
"integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==",
"license": "BSD-3-Clause"
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -10783,6 +11087,26 @@
"node": ">= 0.10.5"
}
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-forge": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
@ -10804,6 +11128,39 @@
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
"license": "MIT"
},
"node_modules/node-vibrant": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/node-vibrant/-/node-vibrant-4.0.3.tgz",
"integrity": "sha512-kzoIuJK90BH/k65Avt077JCX4Nhqz1LNc8cIOm2rnYEvFdJIYd8b3SQwU1MTpzcHtr8z8jxkl1qdaCfbP3olFg==",
"license": "MIT",
"dependencies": {
"@types/node": "^18.15.3",
"@vibrant/core": "^4.0.0",
"@vibrant/generator-default": "^4.0.3",
"@vibrant/image-browser": "^4.0.0",
"@vibrant/image-node": "^4.0.0",
"@vibrant/quantizer-mmcq": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/crutchcorn"
}
},
"node_modules/node-vibrant/node_modules/@types/node": {
"version": "18.19.121",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.121.tgz",
"integrity": "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ==",
"license": "MIT",
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/node-vibrant/node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"license": "MIT"
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -10962,6 +11319,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/omggif": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz",
"integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==",
"license": "MIT"
},
"node_modules/on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
@ -11216,6 +11579,12 @@
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
"license": "BlueOak-1.0.0"
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@ -11344,6 +11713,19 @@
"node": ">=8"
}
},
"node_modules/peek-readable": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
"integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==",
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@ -11387,6 +11769,18 @@
"node": ">= 6"
}
},
"node_modules/pixelmatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz",
"integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==",
"license": "ISC",
"dependencies": {
"pngjs": "^3.0.0"
},
"bin": {
"pixelmatch": "bin/pixelmatch"
}
},
"node_modules/pkg-dir": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
@ -11602,6 +11996,15 @@
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@ -11943,6 +12346,20 @@
"react-native": "*"
}
},
"node_modules/react-native-image-colors": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/react-native-image-colors/-/react-native-image-colors-2.5.0.tgz",
"integrity": "sha512-3zSDgNj5HaZ0PDWaXkc4BpWpZRM5N4gBsoPC7DBfM/+op69Yvwbc0S1T7CnxBWbvShtOvRE+b2BUBadVn+6z/g==",
"license": "MIT",
"dependencies": {
"node-vibrant": "^4.0.3"
},
"peerDependencies": {
"expo": "*",
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-immersive-mode": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/react-native-immersive-mode/-/react-native-immersive-mode-2.0.2.tgz",
@ -12452,6 +12869,71 @@
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/readable-web-to-node-stream": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.4.tgz",
"integrity": "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==",
"license": "MIT",
"dependencies": {
"readable-stream": "^4.7.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/readable-web-to-node-stream/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/readable-web-to-node-stream/node_modules/readable-stream": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
"integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
"license": "MIT",
"dependencies": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/readable-web-to-node-stream/node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/readline": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz",
@ -13542,6 +14024,23 @@
"node": ">=0.10.0"
}
},
"node_modules/strtok3": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz",
"integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==",
"license": "MIT",
"dependencies": {
"@tokenizer/token": "^0.3.0",
"peek-readable": "^4.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/structured-headers": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/structured-headers/-/structured-headers-0.4.1.tgz",
@ -13966,6 +14465,18 @@
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
"license": "MIT"
},
"node_modules/timm": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz",
"integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==",
"license": "MIT"
},
"node_modules/tinycolor2": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
"integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
"license": "MIT"
},
"node_modules/tldts": {
"version": "6.1.86",
"resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz",
@ -14013,6 +14524,23 @@
"node": ">=0.6"
}
},
"node_modules/token-types": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz",
"integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==",
"license": "MIT",
"dependencies": {
"@tokenizer/token": "^0.3.0",
"ieee754": "^1.2.1"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/tough-cookie": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz",
@ -14301,6 +14829,15 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/utif2": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/utif2/-/utif2-4.1.0.tgz",
"integrity": "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==",
"license": "MIT",
"dependencies": {
"pako": "^1.0.11"
}
},
"node_modules/util": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",

View file

@ -47,6 +47,7 @@
"react": "18.3.1",
"react-native": "0.76.9",
"react-native-gesture-handler": "~2.20.2",
"react-native-image-colors": "^2.5.0",
"react-native-immersive-mode": "^2.0.2",
"react-native-paper": "^5.13.1",
"react-native-reanimated": "^3.18.0",

View file

@ -70,6 +70,7 @@ interface HeroSectionProps {
setBannerImage: (bannerImage: string | null) => void;
setLogoLoadError: (error: boolean) => void;
groupedEpisodes?: { [seasonNumber: number]: any[] };
dynamicBackgroundColor?: string;
}
// Ultra-optimized ActionButtons Component - minimal re-renders
@ -677,6 +678,7 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
setBannerImage,
setLogoLoadError,
groupedEpisodes,
dynamicBackgroundColor,
}) => {
const { currentTheme } = useTheme();
const { isAuthenticated: isTraktAuthenticated } = useTraktContext();
@ -929,15 +931,17 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
/>
)}
{/* Optimized Gradient */}
{/* Ultra-light Gradient with subtle dynamic background blend */}
<LinearGradient
colors={[
'rgba(0,0,0,0)',
'rgba(0,0,0,0.4)',
'rgba(0,0,0,0.8)',
themeColors.darkBackground
'rgba(0,0,0,0.05)',
'rgba(0,0,0,0.15)',
'rgba(0,0,0,0.35)',
'rgba(0,0,0,0.65)',
dynamicBackgroundColor || themeColors.darkBackground
]}
locations={[0, 0.6, 0.85, 1]}
locations={[0, 0.3, 0.55, 0.75, 0.9, 1]}
style={styles.heroGradient}
>
<View style={styles.heroContent}>
@ -994,6 +998,23 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
/>
</View>
</LinearGradient>
{/* Ultra-subtle bottom fade for feather-light seamless blend */}
<LinearGradient
colors={[
'transparent',
`${dynamicBackgroundColor || themeColors.darkBackground}05`,
`${dynamicBackgroundColor || themeColors.darkBackground}15`,
`${dynamicBackgroundColor || themeColors.darkBackground}30`,
`${dynamicBackgroundColor || themeColors.darkBackground}50`,
`${dynamicBackgroundColor || themeColors.darkBackground}70`,
`${dynamicBackgroundColor || themeColors.darkBackground}85`,
dynamicBackgroundColor || themeColors.darkBackground
]}
locations={[0, 0.15, 0.3, 0.45, 0.65, 0.8, 0.92, 1]}
style={styles.bottomFadeGradient}
pointerEvents="none"
/>
</Animated.View>
);
});
@ -1017,10 +1038,20 @@ const styles = StyleSheet.create({
justifyContent: 'flex-end',
paddingBottom: 20,
},
bottomFadeGradient: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: 200,
zIndex: -1,
},
heroContent: {
padding: 16,
paddingTop: 8,
paddingBottom: 8,
position: 'relative',
zIndex: 5,
},
logoContainer: {
alignItems: 'center',
@ -1075,6 +1106,7 @@ const styles = StyleSheet.create({
justifyContent: 'center',
width: '100%',
position: 'relative',
zIndex: 10,
},
actionButton: {
flexDirection: 'row',

View file

@ -0,0 +1,169 @@
import { useState, useEffect, useCallback } from 'react';
import { getColors } from 'react-native-image-colors';
import type { ImageColorsResult } from 'react-native-image-colors';
interface DominantColorResult {
dominantColor: string | null;
loading: boolean;
error: string | null;
}
// Simple in-memory cache for extracted colors
const colorCache = new Map<string, string>();
// Preload function to start extraction early
export const preloadDominantColor = async (imageUri: string | null) => {
if (!imageUri || colorCache.has(imageUri)) return;
console.log('[useDominantColor] Preloading color for URI:', imageUri);
try {
const result = await getColors(imageUri, {
fallback: '#1a1a1a',
cache: true,
key: imageUri,
quality: 'low',
});
let extractedColor = '#1a1a1a';
if (result.platform === 'android') {
extractedColor = result.darkMuted || result.muted || result.darkVibrant || result.dominant || '#1a1a1a';
} else if (result.platform === 'ios') {
extractedColor = result.background || result.primary || '#1a1a1a';
} else if (result.platform === 'web') {
extractedColor = result.darkMuted || result.muted || result.dominant || '#1a1a1a';
}
// Apply darkening logic
const hex = extractedColor.replace('#', '');
const r = parseInt(hex.substr(0, 2), 16);
const g = parseInt(hex.substr(2, 2), 16);
const b = parseInt(hex.substr(4, 2), 16);
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
if (brightness > 50) {
const darkenFactor = 0.15;
const newR = Math.floor(r * darkenFactor);
const newG = Math.floor(g * darkenFactor);
const newB = Math.floor(b * darkenFactor);
extractedColor = `#${newR.toString(16).padStart(2, '0')}${newG.toString(16).padStart(2, '0')}${newB.toString(16).padStart(2, '0')}`;
}
colorCache.set(imageUri, extractedColor);
} catch (err) {
console.warn('[preloadDominantColor] Failed to preload color:', err);
colorCache.set(imageUri, '#1a1a1a');
}
};
export const useDominantColor = (imageUri: string | null): DominantColorResult => {
// Start with cached color if available, otherwise use fallback immediately
const [dominantColor, setDominantColor] = useState<string | null>(() => {
if (imageUri && colorCache.has(imageUri)) {
return colorCache.get(imageUri) || '#1a1a1a';
}
// Never return null - always provide immediate fallback
return '#1a1a1a';
});
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const extractColor = useCallback(async (uri: string) => {
if (!uri) {
setDominantColor('#1a1a1a');
setLoading(false);
return;
}
// Check cache first
if (colorCache.has(uri)) {
const cachedColor = colorCache.get(uri)!;
setDominantColor(cachedColor);
setLoading(false);
return;
}
try {
setLoading(true);
setError(null);
const result: ImageColorsResult = await getColors(uri, {
fallback: '#1a1a1a',
cache: true,
key: uri,
quality: 'low', // Use low quality for better performance
});
let extractedColor = '#1a1a1a'; // Default fallback
// Handle different platform results
if (result.platform === 'android') {
// Prefer darker, more muted colors for background
extractedColor = result.darkMuted || result.muted || result.darkVibrant || result.dominant || '#1a1a1a';
} else if (result.platform === 'ios') {
// Use background color from iOS, or fallback to primary
extractedColor = result.background || result.primary || '#1a1a1a';
} else if (result.platform === 'web') {
// Use muted colors for web
extractedColor = result.darkMuted || result.muted || result.dominant || '#1a1a1a';
}
// Ensure the color is dark enough for a background
// Convert hex to RGB to check brightness
const hex = extractedColor.replace('#', '');
const r = parseInt(hex.substr(0, 2), 16);
const g = parseInt(hex.substr(2, 2), 16);
const b = parseInt(hex.substr(4, 2), 16);
// Calculate brightness (0-255)
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
// If too bright, darken it significantly
if (brightness > 50) {
const darkenFactor = 0.15;
const newR = Math.floor(r * darkenFactor);
const newG = Math.floor(g * darkenFactor);
const newB = Math.floor(b * darkenFactor);
extractedColor = `#${newR.toString(16).padStart(2, '0')}${newG.toString(16).padStart(2, '0')}${newB.toString(16).padStart(2, '0')}`;
}
// Cache the extracted color for future use
colorCache.set(uri, extractedColor);
setDominantColor(extractedColor);
} catch (err) {
console.warn('[useDominantColor] Failed to extract color:', err);
setError(err instanceof Error ? err.message : 'Failed to extract color');
const fallbackColor = '#1a1a1a';
colorCache.set(uri, fallbackColor); // Cache fallback to avoid repeated failures
setDominantColor(fallbackColor);
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
if (imageUri) {
// If we have a cached color, use it immediately, but still extract in background for accuracy
if (colorCache.has(imageUri)) {
setDominantColor(colorCache.get(imageUri)!);
setLoading(false);
} else {
// No cache, extract color
extractColor(imageUri);
}
} else {
setDominantColor('#1a1a1a');
setLoading(false);
setError(null);
}
}, [imageUri, extractColor]);
return {
dominantColor,
loading,
error,
};
};
export default useDominantColor;

View file

@ -15,6 +15,7 @@ import { MaterialIcons } from '@expo/vector-icons';
import * as Haptics from 'expo-haptics';
import { useTheme } from '../contexts/ThemeContext';
import { useMetadata } from '../hooks/useMetadata';
import { useDominantColor, preloadDominantColor } from '../hooks/useDominantColor';
import { CastSection } from '../components/metadata/CastSection';
import { CastDetailsModal } from '../components/metadata/CastDetailsModal';
import { SeriesContent } from '../components/metadata/SeriesContent';
@ -98,6 +99,43 @@ const MetadataScreen: React.FC = () => {
const watchProgressData = useWatchProgress(id, type as 'movie' | 'series', episodeId, episodes);
const assetData = useMetadataAssets(metadata, id, type, imdbId, settings, setMetadata);
const animations = useMetadataAnimations(safeAreaTop, watchProgressData.watchProgress);
// Extract dominant color from hero image for dynamic background
const heroImageUri = useMemo(() => {
if (!metadata) return null;
return assetData.bannerImage || metadata.banner || metadata.poster || null;
}, [metadata, assetData.bannerImage]);
// Preload color extraction as soon as we have the URI
useEffect(() => {
if (heroImageUri) {
preloadDominantColor(heroImageUri);
}
}, [heroImageUri]);
const { dominantColor, loading: colorLoading } = useDominantColor(heroImageUri);
// Memoized background color with immediate fallback and smooth transition
const dynamicBackgroundColor = useMemo(() => {
// Start with theme background, then use extracted color when available and different from fallback
if (dominantColor && dominantColor !== '#1a1a1a' && dominantColor !== null && dominantColor !== currentTheme.colors.darkBackground) {
return dominantColor;
}
// Always return theme background as immediate fallback
return currentTheme.colors.darkBackground;
}, [dominantColor, currentTheme.colors.darkBackground]);
// Debug logging for color extraction timing
useEffect(() => {
if (heroImageUri && dominantColor) {
console.log('[MetadataScreen] Dynamic background color:', {
dominantColor,
fallback: currentTheme.colors.darkBackground,
finalColor: dynamicBackgroundColor,
heroImageUri
});
}
}, [dominantColor, dynamicBackgroundColor, heroImageUri, currentTheme.colors.darkBackground]);
// Focus effect for performance optimization
useFocusEffect(
@ -389,7 +427,7 @@ const MetadataScreen: React.FC = () => {
return (
<SafeAreaView
style={[styles.container, { backgroundColor: currentTheme.colors.darkBackground }]}
style={[styles.container, { backgroundColor: dynamicBackgroundColor }]}
edges={['bottom']}
>
<StatusBar translucent backgroundColor="transparent" barStyle="light-content" />
@ -428,7 +466,7 @@ const MetadataScreen: React.FC = () => {
return (
<SafeAreaView
style={[containerStyle, styles.container, { backgroundColor: currentTheme.colors.darkBackground }]}
style={[containerStyle, styles.container, { backgroundColor: dynamicBackgroundColor }]}
edges={['bottom']}
>
<StatusBar translucent backgroundColor="transparent" barStyle="light-content" animated />
@ -484,6 +522,7 @@ const MetadataScreen: React.FC = () => {
setBannerImage={assetData.setBannerImage}
setLogoLoadError={assetData.setLogoLoadError}
groupedEpisodes={groupedEpisodes}
dynamicBackgroundColor={dynamicBackgroundColor}
/>
{/* Main Content - Optimized */}

View file

@ -3,6 +3,8 @@
"compilerOptions": {
"strict": true,
"jsx": "react-jsx",
"esModuleInterop": true
"esModuleInterop": true,
"target": "es2017",
"downlevelIteration": true
}
}