From 1394eae01ec47d77bc3e3ad604ab0eaa1bf9c621 Mon Sep 17 00:00:00 2001 From: herrrta <73949927+herrrta@users.noreply.github.com> Date: Fri, 28 Mar 2025 19:03:36 -0400 Subject: [PATCH] feat: better logs - added ability to write debug logs for development builds - added filtering to log page - modified filter button to allow for multiple selection if required --- .../(tabs)/(home)/settings/logs/page.tsx | 127 ++++++++++++++---- .../collections/[collectionId].tsx | 10 +- app/(auth)/(tabs)/(libraries)/[libraryId].tsx | 10 +- app/(auth)/(tabs)/(search)/index.tsx | 4 +- app/_layout.tsx | 14 +- bun.lock | 70 ++-------- components/filters/FilterButton.tsx | 11 +- components/filters/FilterSheet.tsx | 17 ++- eas.json | 9 +- hooks/useJellyseerr.ts | 17 +-- hooks/useRemuxHlsToMp4.ts | 2 +- package.json | 9 +- providers/JellyfinProvider.tsx | 4 +- translations/de.json | 2 + translations/en.json | 2 + translations/es.json | 2 + translations/fr.json | 2 + translations/it.json | 2 + translations/ja.json | 2 + translations/nl.json | 2 + translations/pl.json | 2 + translations/tr.json | 2 + translations/ua.json | 2 + translations/zh-CN.json | 2 + translations/zh-TW.json | 2 + utils/atoms/settings.ts | 2 +- utils/log.tsx | 7 +- 27 files changed, 204 insertions(+), 133 deletions(-) diff --git a/app/(auth)/(tabs)/(home)/settings/logs/page.tsx b/app/(auth)/(tabs)/(home)/settings/logs/page.tsx index 32fd3617..54bf1b78 100644 --- a/app/(auth)/(tabs)/(home)/settings/logs/page.tsx +++ b/app/(auth)/(tabs)/(home)/settings/logs/page.tsx @@ -1,37 +1,112 @@ import { Text } from "@/components/common/Text"; -import { useLog } from "@/utils/log"; +import {LogLevel, useLog} from "@/utils/log"; import { useTranslation } from "react-i18next"; -import { ScrollView, View } from "react-native"; +import {ScrollView, TouchableOpacity, View} from "react-native"; +import Collapsible from "react-native-collapsible"; +import React, {useMemo, useState} from "react"; +import {FilterButton} from "@/components/filters/FilterButton"; export default function page() { const { logs } = useLog(); const { t } = useTranslation(); + const defaultLevels: LogLevel[] = ["INFO", "ERROR", "DEBUG", "WARN"] + const codeBlockStyle = { + backgroundColor: '#000', + padding: 10, + fontFamily: 'monospace', + maxHeight: 300 + } + + const [state, setState] = useState>({}) + + const [order, setOrder] = useState<"asc" | "desc">("desc"); + const [levels, setLevels] = useState(defaultLevels); + + const filteredLogs = useMemo( + () => logs + ?.filter(log => levels.includes(log.level)) + // Already in asc order as they are recorded. just reverse for desc + ?.[order === "desc" ? "reverse" : "concat"]?.(), + [logs, order, levels] + ) + return ( - - - {logs?.map((log, index) => ( - - - {log.level} - - - {log.message} - - - ))} - {logs?.length === 0 && ( - - {t("home.settings.logs.no_logs_available")} - - )} + <> + + ["asc", "desc"]} + set={(values) => setOrder(values[0])} + values={[order]} + title={t("library.filters.sort_order")} + renderItemLabel={(order) => t(`library.filters.${order}`)} + showSearch={false} + /> + defaultLevels} + set={setLevels} + values={levels} + title={t("home.settings.logs.level")} + renderItemLabel={(level) => level} + showSearch={false} + multiple={true} + /> - + + + {filteredLogs?.map((log, index) => ( + + setState((v) => ({...v, [log.timestamp]: !v[log.timestamp]}))} + > + + + {log.level} + + + {new Date(log.timestamp).toLocaleString()} + + + {log.message} + + + + {log.data && ( + <> + {t("home.settings.logs.click_for_more_info")} + + + + + {JSON.stringify(log.data, null, 2)} + + + + + + )} + + ))} + {filteredLogs?.length === 0 && ( + + {t("home.settings.logs.no_logs_available")} + + )} + + + ); } diff --git a/app/(auth)/(tabs)/(home,libraries,search,favorites)/collections/[collectionId].tsx b/app/(auth)/(tabs)/(home,libraries,search,favorites)/collections/[collectionId].tsx index b23ae9d7..f1b48cbf 100644 --- a/app/(auth)/(tabs)/(home,libraries,search,favorites)/collections/[collectionId].tsx +++ b/app/(auth)/(tabs)/(home,libraries,search,favorites)/collections/[collectionId].tsx @@ -234,7 +234,7 @@ const page: React.FC = () => { component: ( { if (!api) return null; @@ -261,7 +261,7 @@ const page: React.FC = () => { component: ( { if (!api) return null; @@ -286,7 +286,7 @@ const page: React.FC = () => { component: ( { if (!api) return null; @@ -313,7 +313,7 @@ const page: React.FC = () => { component: ( sortOptions.map((s) => s.key)} set={setSortBy} @@ -333,7 +333,7 @@ const page: React.FC = () => { component: ( sortOrderOptions.map((s) => s.key)} set={setSortOrder} diff --git a/app/(auth)/(tabs)/(libraries)/[libraryId].tsx b/app/(auth)/(tabs)/(libraries)/[libraryId].tsx index ec0e7250..096c0948 100644 --- a/app/(auth)/(tabs)/(libraries)/[libraryId].tsx +++ b/app/(auth)/(tabs)/(libraries)/[libraryId].tsx @@ -287,7 +287,7 @@ const Page = () => { component: ( { if (!api) return null; @@ -314,7 +314,7 @@ const Page = () => { component: ( { if (!api) return null; @@ -339,7 +339,7 @@ const Page = () => { component: ( { if (!api) return null; @@ -366,7 +366,7 @@ const Page = () => { component: ( sortOptions.map((s) => s.key)} set={setSortBy} @@ -386,7 +386,7 @@ const Page = () => { component: ( sortOrderOptions.map((s) => s.key)} set={setSortOrder} diff --git a/app/(auth)/(tabs)/(search)/index.tsx b/app/(auth)/(tabs)/(search)/index.tsx index aaef84d6..8a5184a6 100644 --- a/app/(auth)/(tabs)/(search)/index.tsx +++ b/app/(auth)/(tabs)/(search)/index.tsx @@ -283,7 +283,7 @@ export default function search() { debouncedSearch.length > 0 && ( Object.keys(JellyseerrSearchSort).filter((v) => @@ -299,7 +299,7 @@ export default function search() { showSearch={false} /> ["asc", "desc"]} set={(value) => setJellyseerrSortOrder(value[0])} diff --git a/app/_layout.tsx b/app/_layout.tsx index 301433ae..55185c45 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -16,7 +16,7 @@ import { BACKGROUND_FETCH_TASK_SESSIONS, registerBackgroundFetchAsyncSessions, } from "@/utils/background-tasks"; -import { LogProvider, writeErrorLog, writeToLog } from "@/utils/log"; +import {LogProvider, writeDebugLog, writeErrorLog, writeToLog} from "@/utils/log"; import { storage } from "@/utils/mmkv"; import { cancelJobById, getAllJobsByDeviceId } from "@/utils/optimize-server"; import { ActionSheetProvider } from "@expo/react-native-action-sheet"; @@ -357,21 +357,21 @@ function Layout() { Notifications?.addNotificationResponseReceivedListener( (response: NotificationResponse) => { // Currently the notifications supported by the plugin will send data for deep links. - const data = response.notification.request.content.data; + const {title, data} = response.notification.request.content; + + writeDebugLog(`Notification ${title} opened`, response.notification.request.content) if (data && Object.keys(data).length > 0) { - const type = data["type"].toLower(); - const itemId = data["id"]; + const type = data?.type?.toLower?.(); + const itemId = data?.id; switch (type) { case "movie": router.push(`/(auth)/(tabs)/home/items/page?id=${itemId}`) break; case "episode": - const episodeId = data.id; - // We just clicked a notification for an individual episode. - if (episodeId) { + if (itemId) { router.push(`/(auth)/(tabs)/home/items/page?id=${itemId}`) } // summarized season notification for multiple episodes. Bring them to series season diff --git a/bun.lock b/bun.lock index c2fdfe7d..c72cc71f 100644 --- a/bun.lock +++ b/bun.lock @@ -62,6 +62,7 @@ "react-native-awesome-slider": "^2.9.0", "react-native-bottom-tabs": "0.8.6", "react-native-circular-progress": "^1.4.1", + "react-native-collapsible": "^1.6.2", "react-native-compressor": "^1.10.3", "react-native-country-flag": "^2.0.2", "react-native-device-info": "^14.0.4", @@ -109,7 +110,6 @@ "@types/uuid": "^10.0.0", "husky": "^9.1.7", "lint-staged": "^15.5.0", - "patch-package": "^8.0.0", "postinstall-postinstall": "^2.1.0", "react-test-renderer": "19.0.0", "typescript": "~5.7.3", @@ -761,8 +761,6 @@ "@xmldom/xmldom": ["@xmldom/xmldom@0.7.13", "", {}, "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g=="], - "@yarnpkg/lockfile": ["@yarnpkg/lockfile@1.1.0", "", {}, "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ=="], - "@zxing/text-encoding": ["@zxing/text-encoding@0.9.0", "", {}, "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA=="], "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], @@ -1263,8 +1261,6 @@ "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], - "find-yarn-workspace-root": ["find-yarn-workspace-root@2.0.0", "", { "dependencies": { "micromatch": "^4.0.2" } }, "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ=="], - "flow-enums-runtime": ["flow-enums-runtime@0.0.6", "", {}, "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw=="], "flow-parser": ["flow-parser@0.261.2", "", {}, "sha512-RtunoakA3YjtpAxPSOBVW6lmP5NYmETwkpAfNkdr8Ovf86ENkbD3mtPWnswFTIUtRvjwv0i8ZSkHK+AzsUg1JA=="], @@ -1437,8 +1433,6 @@ "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], - "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], "isobject": ["isobject@3.0.1", "", {}, "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="], @@ -1501,18 +1495,12 @@ "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - "json-stable-stringify": ["json-stable-stringify@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "isarray": "^2.0.5", "jsonify": "^0.0.1", "object-keys": "^1.1.1" } }, "sha512-Lp6HbbBgosLmJbjx0pBLbgvx68FaFU1sdkmBuckmhhJ88kL13OA51CDtR2yJB50eCNMH9wRqtQNNiAqQH4YXnA=="], - "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], - "jsonify": ["jsonify@0.0.1", "", {}, "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg=="], - "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], - "klaw-sync": ["klaw-sync@6.0.0", "", { "dependencies": { "graceful-fs": "^4.1.11" } }, "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ=="], - "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], "leven": ["leven@3.1.0", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="], @@ -1715,7 +1703,7 @@ "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], - "open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], + "open": ["open@6.4.0", "", { "dependencies": { "is-wsl": "^1.1.0" } }, "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg=="], "ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], @@ -1753,8 +1741,6 @@ "password-prompt": ["password-prompt@1.1.3", "", { "dependencies": { "ansi-escapes": "^4.3.2", "cross-spawn": "^7.0.3" } }, "sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw=="], - "patch-package": ["patch-package@8.0.0", "", { "dependencies": { "@yarnpkg/lockfile": "^1.1.0", "chalk": "^4.1.2", "ci-info": "^3.7.0", "cross-spawn": "^7.0.3", "find-yarn-workspace-root": "^2.0.0", "fs-extra": "^9.0.0", "json-stable-stringify": "^1.0.2", "klaw-sync": "^6.0.0", "minimist": "^1.2.6", "open": "^7.4.2", "rimraf": "^2.6.3", "semver": "^7.5.3", "slash": "^2.0.0", "tmp": "^0.0.33", "yaml": "^2.2.2" }, "bin": { "patch-package": "index.js" } }, "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA=="], - "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], @@ -1873,6 +1859,8 @@ "react-native-circular-progress": ["react-native-circular-progress@1.4.1", "", { "dependencies": { "prop-types": "^15.8.1" }, "peerDependencies": { "react": ">=16.0.0", "react-native": ">=0.50.0", "react-native-svg": ">=7.0.0" } }, "sha512-HEzvI0WPuWvsCgWE3Ff2HBTMgAEQB2GvTFw0KHyD/t1STAlDDRiolu0mEGhVvihKR3jJu3v3V4qzvSklY/7XzQ=="], + "react-native-collapsible": ["react-native-collapsible@1.6.2", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-MCOBVJWqHNjnDaGkvxX997VONmJeebh6wyJxnHEgg0L1PrlcXU1e/bo6eK+CDVFuMrCafw8Qh4DOv/C4V/+Iew=="], + "react-native-compressor": ["react-native-compressor@1.10.4", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-58gbmJ+8IvsKP8JKK1E8XW5trfQY3dNuH7S0hYw0tSRQc6l0GZ3k8TYtoUbySOc1xcQSrUo51o0Chwe8x7mUTg=="], "react-native-country-flag": ["react-native-country-flag@2.0.2", "", {}, "sha512-5LMWxS79ZQ0Q9ntYgDYzWp794+HcQGXQmzzZNBR1AT7z5HcJHtX7rlk8RHi7RVzfp5gW6plWSZ4dKjRpu/OafQ=="], @@ -1995,7 +1983,7 @@ "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], - "rimraf": ["rimraf@2.7.1", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="], + "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], "rtl-detect": ["rtl-detect@1.1.2", "", {}, "sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ=="], @@ -2061,7 +2049,7 @@ "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], - "slash": ["slash@2.0.0", "", {}, "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A=="], + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], "slice-ansi": ["slice-ansi@5.0.0", "", { "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" } }, "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ=="], @@ -2353,8 +2341,6 @@ "@expo/config-plugins/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], - "@expo/config-plugins/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], - "@expo/devcert/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], "@expo/devcert/sudo-prompt": ["sudo-prompt@8.2.5", "", {}, "sha512-rlBo3HU/1zAJUrkY6jNxDOC9eVYliG6nS4JA8u8KAshITd07tafMc/Br7xQwCSseXwJ2iCcHCE8SNWX3q8Z+kw=="], @@ -2403,8 +2389,6 @@ "@istanbuljs/load-nyc-config/js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], - "@jest/transform/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], - "@jest/transform/write-file-atomic": ["write-file-atomic@4.0.2", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" } }, "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg=="], "@npmcli/fs/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], @@ -2437,8 +2421,6 @@ "@react-native-community/cli-server-api/pretty-format": ["pretty-format@26.6.2", "", { "dependencies": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^17.0.1" } }, "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg=="], - "@react-native-community/cli-tools/open": ["open@6.4.0", "", { "dependencies": { "is-wsl": "^1.1.0" } }, "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg=="], - "@react-native-community/cli-tools/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], "@react-native/babel-plugin-codegen/@react-native/codegen": ["@react-native/codegen@0.76.7", "", { "dependencies": { "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.23.1", "invariant": "^2.2.4", "jscodeshift": "^0.14.0", "mkdirp": "^0.5.1", "nullthrows": "^1.1.1", "yargs": "^17.6.2" }, "peerDependencies": { "@babel/preset-env": "^7.1.6" } }, "sha512-FAn585Ll65YvkSrKDyAcsdjHhhAGiMlSTUpHh0x7J5ntudUns+voYms0xMP+pEPt0XuLdjhD7zLIIlAWP407+g=="], @@ -2453,6 +2435,8 @@ "@react-native/dev-middleware/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "@react-native/dev-middleware/open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], + "@react-native/metro-babel-transformer/@react-native/babel-preset": ["@react-native/babel-preset@0.77.0", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.77.0", "babel-plugin-syntax-hermes-parser": "0.25.1", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" } }, "sha512-Z4yxE66OvPyQ/iAlaETI1ptRLcDm7Tk6ZLqtCPuUX3AMg+JNgIA86979T4RSk486/JrBUBH5WZe2xjj7eEHXsA=="], "@react-navigation/core/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], @@ -2465,8 +2449,6 @@ "ansi-fragments/slice-ansi": ["slice-ansi@2.1.0", "", { "dependencies": { "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" } }, "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ=="], - "babel-jest/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], - "better-opn/open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="], "cacache/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -2477,8 +2459,6 @@ "chromium-edge-launcher/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], - "chromium-edge-launcher/rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], - "cli-truncate/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -2495,10 +2475,6 @@ "default-gateway/execa": ["execa@1.0.0", "", { "dependencies": { "cross-spawn": "^6.0.0", "get-stream": "^4.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" } }, "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA=="], - "del/rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], - - "del/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], - "error-ex/is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], "expo-build-properties/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], @@ -2527,8 +2503,6 @@ "foreground-child/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - "globby/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], - "hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -2537,8 +2511,6 @@ "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], - "jest-message-util/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], - "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], "jscodeshift/tmp": ["tmp@0.2.3", "", {}, "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w=="], @@ -2595,16 +2567,14 @@ "npm-package-arg/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], + "open/is-wsl": ["is-wsl@1.1.0", "", {}, "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw=="], + "ora/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "parse-bmfont-xml/xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], "password-prompt/ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], - "patch-package/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], - - "patch-package/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], - "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "pkg-dir/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], @@ -2783,8 +2753,6 @@ "@react-native-community/cli-server-api/pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], - "@react-native-community/cli-tools/open/is-wsl": ["is-wsl@1.1.0", "", {}, "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw=="], - "@react-native/babel-plugin-codegen/@react-native/codegen/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], "@react-native/babel-plugin-codegen/@react-native/codegen/hermes-parser": ["hermes-parser@0.23.1", "", { "dependencies": { "hermes-estree": "0.23.1" } }, "sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA=="], @@ -2795,6 +2763,8 @@ "@react-native/community-cli-plugin/@react-native/dev-middleware/@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.77.0", "", {}, "sha512-glOvSEjCbVXw+KtfiOAmrq21FuLE1VsmBsyT7qud4KWbXP43aUEhzn70mWyFuiIdxnzVPKe2u8iWTQTdJksR1w=="], + "@react-native/community-cli-plugin/@react-native/dev-middleware/open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], + "@react-native/community-cli-plugin/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "@react-native/dev-middleware/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], @@ -2805,8 +2775,6 @@ "ansi-fragments/slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@2.0.0", "", {}, "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w=="], - "chromium-edge-launcher/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - "cli-truncate/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="], "cli-truncate/string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], @@ -2823,8 +2791,6 @@ "default-gateway/execa/npm-run-path": ["npm-run-path@2.0.2", "", { "dependencies": { "path-key": "^2.0.0" } }, "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw=="], - "del/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - "expo-modules-autolinking/fs-extra/jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="], "expo-modules-autolinking/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], @@ -2885,10 +2851,6 @@ "password-prompt/ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], - "patch-package/fs-extra/jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="], - - "patch-package/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - "pkg-dir/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], "react-native-tvos/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], @@ -2949,8 +2911,6 @@ "ansi-fragments/slice-ansi/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], - "chromium-edge-launcher/rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - "cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], "default-gateway/execa/cross-spawn/path-key": ["path-key@2.0.1", "", {}, "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw=="], @@ -2963,8 +2923,6 @@ "default-gateway/execa/npm-run-path/path-key": ["path-key@2.0.1", "", {}, "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw=="], - "del/rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - "lint-staged/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], "lint-staged/execa/onetime/mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], @@ -3021,12 +2979,8 @@ "ansi-fragments/slice-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], - "chromium-edge-launcher/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], - "default-gateway/execa/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@1.0.0", "", {}, "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ=="], - "del/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], - "logkitty/yargs/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], "pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], diff --git a/components/filters/FilterButton.tsx b/components/filters/FilterButton.tsx index 84bf8bfb..1a1d7466 100644 --- a/components/filters/FilterButton.tsx +++ b/components/filters/FilterButton.tsx @@ -6,7 +6,7 @@ import { TouchableOpacity, View, type ViewProps } from "react-native"; import { FilterSheet } from "./FilterSheet"; interface FilterButtonProps extends ViewProps { - collectionId: string; + id: string; showSearch?: boolean; queryKey: string; values: T[]; @@ -15,11 +15,12 @@ interface FilterButtonProps extends ViewProps { queryFn: (params: any) => Promise; searchFilter?: (item: T, query: string) => boolean; renderItemLabel: (item: T) => React.ReactNode; + multiple?: boolean, icon?: "filter" | "sort"; } export const FilterButton = ({ - collectionId, + id, queryFn, queryKey, set, @@ -28,16 +29,17 @@ export const FilterButton = ({ renderItemLabel, searchFilter, showSearch = true, + multiple = false, icon = "filter", ...props }: FilterButtonProps) => { const [open, setOpen] = useState(false); const { data: filters } = useQuery({ - queryKey: ["filters", title, queryKey, collectionId], + queryKey: ["filters", title, queryKey, id], queryFn, staleTime: 0, - enabled: !!collectionId && !!queryFn && !!queryKey, + enabled: !!id && !!queryFn && !!queryKey, }); return ( @@ -93,6 +95,7 @@ export const FilterButton = ({ renderItemLabel={renderItemLabel} searchFilter={searchFilter} showSearch={showSearch} + multiple={multiple} /> ); diff --git a/components/filters/FilterSheet.tsx b/components/filters/FilterSheet.tsx index f3508ffd..ec69721b 100644 --- a/components/filters/FilterSheet.tsx +++ b/components/filters/FilterSheet.tsx @@ -31,6 +31,7 @@ interface Props extends ViewProps { searchFilter?: (item: T, query: string) => boolean; renderItemLabel: (item: T) => React.ReactNode; showSearch?: boolean; + multiple?: boolean; } const LIMIT = 100; @@ -73,6 +74,7 @@ export const FilterSheet = ({ searchFilter, renderItemLabel, showSearch = true, + multiple = false, ...props }: Props) => { const bottomSheetModalRef = useRef(null); @@ -180,12 +182,23 @@ export const FilterSheet = ({ { - if (!values.includes(item)) { - set([item]); + if (multiple) { + if (!values.includes(item)) + set(values.concat(item)) + else set(values.filter(v => v !== item)) + setTimeout(() => { setOpen(false); }, 250); } + else { + if (!values.includes(item)) { + set([item]); + setTimeout(() => { + setOpen(false); + }, 250); + } + } }} className=' bg-neutral-800 px-4 py-3 flex flex-row items-center justify-between' > diff --git a/eas.json b/eas.json index 39e6e913..82945a7b 100644 --- a/eas.json +++ b/eas.json @@ -8,7 +8,8 @@ "developmentClient": true, "distribution": "internal", "android": { - "buildType": "apk" + "buildType": "apk", + "DEBUG": "1" } }, "development_tv": { @@ -18,7 +19,8 @@ "buildType": "apk" }, "env": { - "EXPO_TV": "1" + "EXPO_TV": "1", + "DEBUG": "1" } }, "preview": { @@ -28,7 +30,8 @@ "developmentClient": true, "distribution": "internal", "ios": { - "simulator": true + "simulator": true, + "DEBUG": "1" } }, "production": { diff --git a/hooks/useJellyseerr.ts b/hooks/useJellyseerr.ts index 920d3404..930a92cd 100644 --- a/hooks/useJellyseerr.ts +++ b/hooks/useJellyseerr.ts @@ -160,9 +160,8 @@ export class JellyseerrApi { toast.error(t("jellyseerr.toasts.jellyseerr_test_failed")); writeErrorLog( `Jellyseerr returned a ${status} for url:\n` + - response.config.url + - "\n" + - JSON.stringify(response.data), + response.config.url , + response.data ); return { isValid: false, @@ -388,15 +387,11 @@ export class JellyseerrApi { return response; }, (error: AxiosError) => { - const errorMsg = "Jellyseerr response error"; - console.error(errorMsg, error, error.response?.data); writeErrorLog( - errorMsg + - `\n` + - `error: ${error.toString()}\n` + - `url: ${error?.config?.url}\n` + - `data:\n` + - JSON.stringify(error.response?.data), + "Jellyseerr response error\n" + + `error: ${error.toString()}\n` + + `url: ${error?.config?.url}`, + error.response?.data, ); if (error.status === 403) { clearJellyseerrStorageData(); diff --git a/hooks/useRemuxHlsToMp4.ts b/hooks/useRemuxHlsToMp4.ts index 67c8777d..d2594b0a 100644 --- a/hooks/useRemuxHlsToMp4.ts +++ b/hooks/useRemuxHlsToMp4.ts @@ -1,7 +1,7 @@ import { useDownload } from "@/providers/DownloadProvider"; import { apiAtom } from "@/providers/JellyfinProvider"; import { getItemImage } from "@/utils/getItemImage"; -import { writeErrorLog, writeInfoLog, writeToLog } from "@/utils/log"; +import { writeErrorLog, writeInfoLog } from "@/utils/log"; import type { BaseItemDto, MediaSourceInfo, diff --git a/package.json b/package.json index c8592aff..bc3b75d6 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,10 @@ "submodule-reload": "git submodule update --init --remote --recursive", "clean": "echo y | expo prebuild --clean", "start": "bun run submodule-reload && expo start", - "ios": "EXPO_TV=0 expo run:ios", - "ios:tv": "EXPO_TV=1 expo run:ios", - "android": "EXPO_TV=0 expo run:android", - "android:tv": "EXPO_TV=1 expo run:android", + "ios": "EXPO_TV=0 DEBUG=1 expo run:ios", + "ios:tv": "EXPO_TV=1 DEBUG=1 expo run:ios", + "android": "EXPO_TV=0 DEBUG=1 expo run:android", + "android:tv": "EXPO_TV=1 DEBUG=1 expo run:android", "prebuild": "EXPO_TV=0 bun run clean", "prebuild:tv": "EXPO_TV=1 bun run clean", "prepare": "husky", @@ -74,6 +74,7 @@ "react-native-awesome-slider": "^2.9.0", "react-native-bottom-tabs": "0.8.6", "react-native-circular-progress": "^1.4.1", + "react-native-collapsible": "^1.6.2", "react-native-compressor": "^1.10.3", "react-native-country-flag": "^2.0.2", "react-native-device-info": "^14.0.4", diff --git a/providers/JellyfinProvider.tsx b/providers/JellyfinProvider.tsx index 5c3401b6..f9377829 100644 --- a/providers/JellyfinProvider.tsx +++ b/providers/JellyfinProvider.tsx @@ -290,9 +290,7 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({ api ?.delete(`/Streamyfin/device/${deviceId}`) .then((r) => writeInfoLog("Deleted expo push token for device")) - .catch((e) => - writeErrorLog(`Failed to delete expo push token for device`), - ); + .catch((e) => writeErrorLog("Failed to delete expo push token for device")); storage.delete("token"); setUser(null); diff --git a/translations/de.json b/translations/de.json index 993c2176..67d93c93 100644 --- a/translations/de.json +++ b/translations/de.json @@ -206,6 +206,8 @@ }, "logs": { "logs_title": "Logs", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "Keine Logs verfügbar", "delete_all_logs": "Alle Logs löschen" }, diff --git a/translations/en.json b/translations/en.json index 30d7d466..0d60faad 100644 --- a/translations/en.json +++ b/translations/en.json @@ -206,6 +206,8 @@ }, "logs": { "logs_title": "Logs", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "No logs available", "delete_all_logs": "Delete all logs" }, diff --git a/translations/es.json b/translations/es.json index 0745aad3..5c7e495e 100644 --- a/translations/es.json +++ b/translations/es.json @@ -206,6 +206,8 @@ }, "logs": { "logs_title": "Registros", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "No hay registros disponibles", "delete_all_logs": "Eliminar todos los registros" }, diff --git a/translations/fr.json b/translations/fr.json index 1b707c94..663d5830 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -206,6 +206,8 @@ }, "logs": { "logs_title": "Journaux", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "Aucun journal disponible", "delete_all_logs": "Supprimer tous les journaux" }, diff --git a/translations/it.json b/translations/it.json index 44f437b3..639cfe73 100644 --- a/translations/it.json +++ b/translations/it.json @@ -206,6 +206,8 @@ }, "logs": { "logs_title": "Log", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "Nessun log disponibile", "delete_all_logs": "Cancella tutti i log" }, diff --git a/translations/ja.json b/translations/ja.json index 261b6724..b6781465 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -205,6 +205,8 @@ }, "logs": { "logs_title": "ログ", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "ログがありません", "delete_all_logs": "すべてのログを削除" }, diff --git a/translations/nl.json b/translations/nl.json index eb213102..23852166 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -206,6 +206,8 @@ }, "logs": { "logs_title": "Logs", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "Geen logs beschikbaar", "delete_all_logs": "Verwijder alle logs" }, diff --git a/translations/pl.json b/translations/pl.json index 0f6c31bd..6d5cf051 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -206,6 +206,8 @@ }, "logs": { "logs_title": "Logi", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "Brak dostępnych logów", "delete_all_logs": "Usuń wszystkie logi" }, diff --git a/translations/tr.json b/translations/tr.json index 6d1a6714..fa7c73b0 100644 --- a/translations/tr.json +++ b/translations/tr.json @@ -205,6 +205,8 @@ }, "logs": { "logs_title": "Günlükler", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "Günlükler mevcut değil", "delete_all_logs": "Tüm günlükleri sil" }, diff --git a/translations/ua.json b/translations/ua.json index d2a40d71..ae34b302 100644 --- a/translations/ua.json +++ b/translations/ua.json @@ -206,6 +206,8 @@ }, "logs": { "logs_title": "Журнал", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "Нема доступних журналів", "delete_all_logs": "Видалити усі журнали" }, diff --git a/translations/zh-CN.json b/translations/zh-CN.json index e9e0391a..bbbdf5ed 100644 --- a/translations/zh-CN.json +++ b/translations/zh-CN.json @@ -205,6 +205,8 @@ }, "logs": { "logs_title": "日志", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "无可用日志", "delete_all_logs": "删除所有日志" }, diff --git a/translations/zh-TW.json b/translations/zh-TW.json index e533b56a..83585f65 100644 --- a/translations/zh-TW.json +++ b/translations/zh-TW.json @@ -205,6 +205,8 @@ }, "logs": { "logs_title": "日誌", + "click_for_more_info": "Click for more info", + "level": "Level", "no_logs_available": "無可用日誌", "delete_all_logs": "刪除所有日誌" }, diff --git a/utils/atoms/settings.ts b/utils/atoms/settings.ts index bd7b9ab2..f4350bed 100644 --- a/utils/atoms/settings.ts +++ b/utils/atoms/settings.ts @@ -265,7 +265,7 @@ export const useSettings = () => { if (!api) return; const settings = await api.getStreamyfinPluginConfig().then( ({ data }) => { - writeInfoLog(`Got remote settings: ${data?.settings}`); + writeInfoLog("Got plugin settings", data?.settings); return data?.settings; }, (err) => undefined, diff --git a/utils/log.tsx b/utils/log.tsx index 3344b9ff..debb626a 100644 --- a/utils/log.tsx +++ b/utils/log.tsx @@ -4,7 +4,7 @@ import type React from "react"; import { createContext, useContext } from "react"; import { storage } from "./mmkv"; -type LogLevel = "INFO" | "WARN" | "ERROR"; +export type LogLevel = "INFO" | "WARN" | "ERROR" | "DEBUG"; interface LogEntry { timestamp: string; @@ -62,6 +62,11 @@ export const writeInfoLog = (message: string, data?: any) => writeToLog("INFO", message, data); export const writeErrorLog = (message: string, data?: any) => writeToLog("ERROR", message, data); +export const writeDebugLog = (message: string, data?: any) => { + if (process.env.DEBUG === "1") { + writeToLog("DEBUG", message, data); + } +} export const readFromLog = (): LogEntry[] => { const logs = storage.getString("logs");