diff --git a/package-lock.json b/package-lock.json index b0b6d96..a252957 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "rssuper", "version": "1.0.0", "dependencies": { + "@react-native-async-storage/async-storage": "^3.0.2", "@react-navigation/bottom-tabs": "^7.15.5", "@react-navigation/elements": "^2.9.10", "@react-navigation/native": "^7.1.33", @@ -20,21 +21,22 @@ "expo-glass-effect": "55.0.9-canary-20260328-2049187", "expo-image": "55.0.7-canary-20260328-2049187", "expo-linking": "55.0.10-canary-20260328-2049187", - "expo-localization": "^55.0.10-canary-20260328-bdc6273", - "expo-notifications": "^55.0.15-canary-20260328-bdc6273", + "expo-localization": "55.0.10-canary-20260328-2049187", + "expo-notifications": "55.0.15-canary-20260328-2049187", "expo-router": "55.0.9-canary-20260328-2049187", "expo-splash-screen": "55.0.14-canary-20260328-2049187", - "expo-sqlite": "^55.0.12-canary-20260328-bdc6273", + "expo-sqlite": "55.0.12-canary-20260328-2049187", "expo-status-bar": "55.0.5-canary-20260328-2049187", "expo-symbols": "55.0.6-canary-20260328-2049187", "expo-system-ui": "55.0.12-canary-20260328-2049187", - "expo-task-manager": "^55.0.11-canary-20260328-bdc6273", + "expo-task-manager": "55.0.11-canary-20260328-2049187", "expo-web-browser": "55.0.11-canary-20260328-2049187", "react": "19.2.0", "react-dom": "19.2.0", "react-native": "0.83.4", "react-native-gesture-handler": "~2.30.0", "react-native-reanimated": "4.2.1", + "react-native-render-html": "^6.3.4", "react-native-safe-area-context": "~5.6.2", "react-native-screens": "~4.23.0", "react-native-web": "~0.21.0", @@ -2149,6 +2151,57 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsamr/counter-style": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@jsamr/counter-style/-/counter-style-2.0.2.tgz", + "integrity": "sha512-2mXudGVtSzVxWEA7B9jZLKjoXUeUFYDDtFrQoC0IFX9/Dszz4t1vZOmafi3JSw/FxD+udMQ+4TAFR8Qs0J3URQ==", + "license": "MIT" + }, + "node_modules/@jsamr/react-native-li": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@jsamr/react-native-li/-/react-native-li-2.3.1.tgz", + "integrity": "sha512-Qbo4NEj48SQ4k8FZJHFE2fgZDKTWaUGmVxcIQh3msg5JezLdTMMHuRRDYctfdHI6L0FZGObmEv3haWbIvmol8w==", + "license": "MIT", + "peerDependencies": { + "@jsamr/counter-style": "^1.0.0 || ^2.0.0", + "react": "*", + "react-native": "*" + } + }, + "node_modules/@native-html/css-processor": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@native-html/css-processor/-/css-processor-1.11.0.tgz", + "integrity": "sha512-NnhBEbJX5M2gBGltPKOetiLlKhNf3OHdRafc8//e2ZQxXN8JaSW/Hy8cm94pnIckQxwaMKxrtaNT3x4ZcffoNQ==", + "license": "MIT", + "dependencies": { + "css-to-react-native": "^3.0.0", + "csstype": "^3.0.8" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-native": "*" + } + }, + "node_modules/@native-html/transient-render-engine": { + "version": "11.2.3", + "resolved": "https://registry.npmjs.org/@native-html/transient-render-engine/-/transient-render-engine-11.2.3.tgz", + "integrity": "sha512-zXwgA3gPUEmFs3I3syfnvDvS6WiUHXEE6jY09OBzK+trq7wkweOSFWIoyXiGkbXrozGYG0KY90YgPyr8Tg8Uyg==", + "license": "MIT", + "dependencies": { + "@native-html/css-processor": "1.11.0", + "@types/ramda": "^0.27.44", + "csstype": "^3.0.9", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "htmlparser2": "^7.1.2", + "ramda": "^0.27.2" + }, + "peerDependencies": { + "@types/react-native": "*", + "react-native": "^*" + } + }, "node_modules/@radix-ui/primitive": { "version": "1.1.3", "license": "MIT" @@ -2588,6 +2641,19 @@ } } }, + "node_modules/@react-native-async-storage/async-storage": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-3.0.2.tgz", + "integrity": "sha512-XP0zDIl+1XoeuQ7f878qXKdl77zLwzLALPpxvNRc7ZtDh9ew36WSvOdQOhFkexMySapFAWxEbZxS8K8J2DU4eg==", + "license": "MIT", + "dependencies": { + "idb": "8.0.3" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/@react-native/assets-registry": { "version": "0.83.4", "license": "MIT", @@ -3015,18 +3081,57 @@ "undici-types": "~7.18.0" } }, + "node_modules/@types/ramda": { + "version": "0.27.66", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.27.66.tgz", + "integrity": "sha512-i2YW+E2U6NfMt3dp0RxNcejox+bxJUNDjB7BpYuRuoHIzv5juPHkJkNgcUOu+YSQEmaWu8cnAo/8r63C0NnuVA==", + "license": "MIT", + "dependencies": { + "ts-toolbelt": "^6.15.1" + } + }, "node_modules/@types/react": { "version": "19.2.14", - "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" } }, + "node_modules/@types/react-native": { + "version": "0.72.8", + "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.72.8.tgz", + "integrity": "sha512-St6xA7+EoHN5mEYfdWnfYt0e8u6k2FR0P9s2arYgakQGFgU1f9FlPrIEcj0X24pLCF5c5i3WVuLCUdiCYHmOoA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@react-native/virtualized-lists": "^0.72.4", + "@types/react": "*" + } + }, + "node_modules/@types/react-native/node_modules/@react-native/virtualized-lists": { + "version": "0.72.8", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.72.8.tgz", + "integrity": "sha512-J3Q4Bkuo99k7mu+jPS9gSUSgq+lLRSI/+ahXNwV92XgJ/8UgOTxu2LPwhJnBk/sQKxq7E8WkZBnBiozukQMqrw==", + "license": "MIT", + "peer": true, + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "peerDependencies": { + "react-native": "*" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "license": "MIT" }, + "node_modules/@types/urijs": { + "version": "1.19.26", + "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.26.tgz", + "integrity": "sha512-wkXrVzX5yoqLnndOwFsieJA7oKM8cNkOKJtf/3vVGSUFkWDKZvFHpIl9Pvqb/T9UsawBBFMTTD8xu7sK5MWuvg==", + "license": "MIT" + }, "node_modules/@types/xml2js": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz", @@ -3602,6 +3707,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001781", "funding": [ @@ -3647,6 +3761,26 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/character-entities-html4": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz", + "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chrome-launcher": { "version": "0.15.2", "license": "Apache-2.0", @@ -3899,6 +4033,15 @@ "node": ">= 8" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, "node_modules/css-in-js-utils": { "version": "3.1.0", "license": "MIT", @@ -3906,9 +4049,19 @@ "hyphenate-style-name": "^1.0.3" } }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/csstype": { "version": "3.2.3", - "dev": true, "license": "MIT" }, "node_modules/debug": { @@ -3996,6 +4149,61 @@ "version": "1.1.4", "license": "MIT" }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -4029,6 +4237,15 @@ "node": ">= 0.8" } }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/error-stack-parser": { "version": "2.1.4", "license": "MIT", @@ -4180,12 +4397,12 @@ } }, "node_modules/expo-application": { - "version": "55.0.11-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-55.0.11-canary-20260328-bdc6273.tgz", - "integrity": "sha512-tXk3YZaTJ2W3vbawnEtOy5o/SVpaUqygqZwbiOearcnXFGtJOS/U3J5KRhH9FZVomeW19h+aplcy4mPPMbc65g==", + "version": "55.0.11-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-55.0.11-canary-20260328-2049187.tgz", + "integrity": "sha512-XrWghJefOb3fTdxK0B3RKuz9l31nZn2SIPqn2qhYx4kOPXa/CytaUvH5wG5gHJ2ZGtonk4JPmw+a69OiDj7MfQ==", "license": "MIT", "peerDependencies": { - "expo": "55.0.10-canary-20260328-bdc6273" + "expo": "55.0.10-canary-20260328-2049187" } }, "node_modules/expo-asset": { @@ -4291,15 +4508,15 @@ } }, "node_modules/expo-localization": { - "version": "55.0.10-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/expo-localization/-/expo-localization-55.0.10-canary-20260328-bdc6273.tgz", - "integrity": "sha512-BCawgtUzcRIoT8DA8k4O8CYV3NuunPHe3TnYTt9ETIfMIxeKXAF2f2LlRrbhIqsbwjPWnMcZwpse2q/HSXxXcQ==", + "version": "55.0.10-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/expo-localization/-/expo-localization-55.0.10-canary-20260328-2049187.tgz", + "integrity": "sha512-4ZxHWAssJzQzkzcEGNzSxB/BpoN5IWE/FvMbJExByYqh2/x7EVJqamT8lNvFmfTdwrVCwGX6AhzMB6MGmf38Yg==", "license": "MIT", "dependencies": { "rtl-detect": "^1.0.2" }, "peerDependencies": { - "expo": "55.0.10-canary-20260328-bdc6273", + "expo": "55.0.10-canary-20260328-2049187", "react": "*" } }, @@ -4335,191 +4552,23 @@ } }, "node_modules/expo-notifications": { - "version": "55.0.15-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-55.0.15-canary-20260328-bdc6273.tgz", - "integrity": "sha512-odWh8KPkk9P6aZv/NR83poePVFfcz4jW70sgyaFv0EpDZkSN3gJKFCmgfaMldCKrn52Q9q4xrXfFzZRJdDe4xg==", + "version": "55.0.15-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-55.0.15-canary-20260328-2049187.tgz", + "integrity": "sha512-Z6eQ5HPs2q71O+tt+dmINigAT+WxB2pCp/EAmvhtIPVYhopSuxJDmPGd+sMjeUe/npiwJqbr2agDLPcH8NxsHA==", "license": "MIT", "dependencies": { - "@expo/image-utils": "0.8.13-canary-20260328-bdc6273", + "@expo/image-utils": "0.8.13-canary-20260328-2049187", "abort-controller": "^3.0.0", "badgin": "^1.1.5", - "expo-application": "55.0.11-canary-20260328-bdc6273", - "expo-constants": "55.0.10-canary-20260328-bdc6273" + "expo-application": "55.0.11-canary-20260328-2049187", + "expo-constants": "55.0.10-canary-20260328-2049187" }, "peerDependencies": { - "expo": "55.0.10-canary-20260328-bdc6273", + "expo": "55.0.10-canary-20260328-2049187", "react": "*", "react-native": "*" } }, - "node_modules/expo-notifications/node_modules/@expo/config": { - "version": "55.0.12-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-55.0.12-canary-20260328-bdc6273.tgz", - "integrity": "sha512-79kzhpY5VAkLem/BPZasapvtZShK1PAWQYg/78edXRdLAL0k7x7Gy9ubgNgkT6KzbC9xvN6rwQ9wKx95Wd+Urg==", - "license": "MIT", - "dependencies": { - "@expo/config-plugins": "55.0.8-canary-20260328-bdc6273", - "@expo/config-types": "55.0.6-canary-20260328-bdc6273", - "@expo/json-file": "10.0.13-canary-20260328-bdc6273", - "@expo/require-utils": "55.0.4-canary-20260328-bdc6273", - "deepmerge": "^4.3.1", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "resolve-from": "^5.0.0", - "resolve-workspace-root": "^2.0.0", - "semver": "^7.6.0", - "slugify": "^1.3.4" - } - }, - "node_modules/expo-notifications/node_modules/@expo/config-plugins": { - "version": "55.0.8-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-55.0.8-canary-20260328-bdc6273.tgz", - "integrity": "sha512-djT9urGkLkL9kJcO1+frUkFgZk63J4akISvXtUmoNGe+k7zGSQmoQRy/tWmhMwwNMGm2BrmVyoLX+243gmnHwA==", - "license": "MIT", - "dependencies": { - "@expo/config-types": "55.0.6-canary-20260328-bdc6273", - "@expo/json-file": "10.0.13-canary-20260328-bdc6273", - "@expo/plist": "0.5.3-canary-20260328-bdc6273", - "@expo/sdk-runtime-versions": "^1.0.0", - "chalk": "^4.1.2", - "debug": "^4.3.5", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "resolve-from": "^5.0.0", - "semver": "^7.5.4", - "slugify": "^1.6.6", - "xcode": "^3.0.1", - "xml2js": "0.6.0" - } - }, - "node_modules/expo-notifications/node_modules/@expo/config-types": { - "version": "55.0.6-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-55.0.6-canary-20260328-bdc6273.tgz", - "integrity": "sha512-IUD5dTOZkTr+dxNmqJi09GzxxRMqTlIFCSWa5DIjioyxCBkRQ1fi3jkmDcS4owHjZpNA2XRKG8QNum+OKwXw/g==", - "license": "MIT" - }, - "node_modules/expo-notifications/node_modules/@expo/env": { - "version": "2.1.2-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.1.2-canary-20260328-bdc6273.tgz", - "integrity": "sha512-iopcE9NDqKTaLEuiAEEYS0zohyXJamyX7csFTTI93tcnXEr/eh3ZnvQjkEKhPNAVcB9MmcAiowCHQCfiDcV0Nw==", - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "debug": "^4.3.4", - "getenv": "^2.0.0" - }, - "engines": { - "node": ">=20.12.0" - } - }, - "node_modules/expo-notifications/node_modules/@expo/image-utils": { - "version": "0.8.13-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.8.13-canary-20260328-bdc6273.tgz", - "integrity": "sha512-1n6J1iVSM58n0mTw/czSHmHGXMUUau0PQc0aQqdQyzElrluNpdShJL5McFsr6usbhztz6Fg4dWMFWXuuON9R+Q==", - "license": "MIT", - "dependencies": { - "@expo/spawn-async": "^1.7.2", - "chalk": "^4.0.0", - "getenv": "^2.0.0", - "jimp-compact": "0.16.1", - "parse-png": "^2.1.0", - "resolve-from": "^5.0.0", - "semver": "^7.6.0" - } - }, - "node_modules/expo-notifications/node_modules/@expo/json-file": { - "version": "10.0.13-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.0.13-canary-20260328-bdc6273.tgz", - "integrity": "sha512-bB+r3u2BIIl4tpc0bc2h9vc6hhwzf0w9vG1co3WHXCDLBfWx0Dvxc5xfUq4E5+Lz61oAO0Qq9dUM8f8qgra4TA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "json5": "^2.2.3" - } - }, - "node_modules/expo-notifications/node_modules/@expo/plist": { - "version": "0.5.3-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.5.3-canary-20260328-bdc6273.tgz", - "integrity": "sha512-Mibai5bnKjtaSuQtPS1CuTvIwN9Fi3Vw6+5ZNdoPQ1bwJSYLMDxIIBKBUaAPgJSB/EHYd1rErYabozWGhj1ebg==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" - } - }, - "node_modules/expo-notifications/node_modules/@expo/require-utils": { - "version": "55.0.4-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-55.0.4-canary-20260328-bdc6273.tgz", - "integrity": "sha512-PhOAVBPFCfgMYKnLWogOLprNEr/S78TRUo1gvK9rPF/PYhLXJBpmrQB8Te7PmbaqD2AoB6rYopy858lrVHHjOw==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "@babel/core": "^7.25.2", - "@babel/plugin-transform-modules-commonjs": "^7.24.8" - }, - "peerDependencies": { - "typescript": "^5.0.0 || ^5.0.0-0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/expo-notifications/node_modules/expo-constants": { - "version": "55.0.10-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-55.0.10-canary-20260328-bdc6273.tgz", - "integrity": "sha512-K6Eu2OFjIlDmHsupLdaS/qxIDk+kzPVmFC0kmsME5NDZpPiH7eyS47q3wiMa9ZRxOtk4bLbSYMfMXQ1pcnhh/w==", - "license": "MIT", - "dependencies": { - "@expo/config": "55.0.12-canary-20260328-bdc6273", - "@expo/env": "2.1.2-canary-20260328-bdc6273" - }, - "peerDependencies": { - "expo": "55.0.10-canary-20260328-bdc6273", - "react-native": "*" - } - }, - "node_modules/expo-notifications/node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/expo-notifications/node_modules/xml2js": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz", - "integrity": "sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==", - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/expo-notifications/node_modules/xml2js/node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, "node_modules/expo-router": { "version": "55.0.9-canary-20260328-2049187", "license": "MIT", @@ -4611,15 +4660,15 @@ } }, "node_modules/expo-sqlite": { - "version": "55.0.12-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/expo-sqlite/-/expo-sqlite-55.0.12-canary-20260328-bdc6273.tgz", - "integrity": "sha512-iDPDnn4IJhi/ajlPKlb7qf4IwAVoyVDNSyYyacDz3YKfc4xajsW78AosDeJo+RxdAhFzPen3Bd0WinROmuwb+w==", + "version": "55.0.12-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/expo-sqlite/-/expo-sqlite-55.0.12-canary-20260328-2049187.tgz", + "integrity": "sha512-pzcd8T1A1a/SKDkFrUXQP/VQXdmsSRpE1XJwFps6Jt3+7DT1kQlFuQEp1xx7hqko/Qhjo7i1X0s67b1pt0lYWg==", "license": "MIT", "dependencies": { "await-lock": "^2.2.2" }, "peerDependencies": { - "expo": "55.0.10-canary-20260328-bdc6273", + "expo": "55.0.10-canary-20260328-2049187", "react": "*", "react-native": "*" } @@ -4668,15 +4717,15 @@ } }, "node_modules/expo-task-manager": { - "version": "55.0.11-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/expo-task-manager/-/expo-task-manager-55.0.11-canary-20260328-bdc6273.tgz", - "integrity": "sha512-b+iQORUVW5fHk8zbI5l1I+bD+h4iJmFNI1IZN2ii+IR3wF0h8P4UcXkXHbISHHAEYoEFVtSqaUEKE0LiEFHrrA==", + "version": "55.0.11-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/expo-task-manager/-/expo-task-manager-55.0.11-canary-20260328-2049187.tgz", + "integrity": "sha512-eneHR2t2WLWeRKfFuY2UDREh9OSryVDGWXy2V+IBlAKdOEQBQ1FlJESbLrYCEkhu6qiLUYMd61e0tgn3fbRhWQ==", "license": "MIT", "dependencies": { - "unimodules-app-loader": "55.0.3-canary-20260328-bdc6273" + "unimodules-app-loader": "55.0.3-canary-20260328-2049187" }, "peerDependencies": { - "expo": "55.0.10-canary-20260328-bdc6273", + "expo": "55.0.10-canary-20260328-2049187", "react-native": "*" } }, @@ -5122,6 +5171,37 @@ "version": "10.4.3", "license": "ISC" }, + "node_modules/htmlparser2": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", + "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "entities": "^3.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/http-errors": { "version": "2.0.1", "license": "MIT", @@ -5155,6 +5235,12 @@ "version": "1.1.0", "license": "BSD-3-Clause" }, + "node_modules/idb": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/idb/-/idb-8.0.3.tgz", + "integrity": "sha512-LtwtVyVYO5BqRvcsKuB2iUMnHwPVByPCXFXOpuU96IZPPoPN6xjOGxZQ74pgSVVLQWtUOYgyeL4GE98BY5D3wg==", + "license": "ISC" + }, "node_modules/ignore": { "version": "5.3.2", "license": "MIT", @@ -6515,6 +6601,23 @@ "node": ">= 6" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/proxy-from-env": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", @@ -6547,6 +6650,12 @@ "inherits": "~2.0.3" } }, + "node_modules/ramda": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", + "integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==", + "license": "MIT" + }, "node_modules/range-parser": { "version": "1.2.1", "license": "MIT", @@ -6705,6 +6814,27 @@ "node": ">=10" } }, + "node_modules/react-native-render-html": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/react-native-render-html/-/react-native-render-html-6.3.4.tgz", + "integrity": "sha512-H2jSMzZjidE+Wo3qCWPUMU1nm98Vs2SGCvQCz/i6xf0P3Y9uVtG/b0sDbG/cYFir2mSYBYCIlS1Dv0WC1LjYig==", + "license": "BSD-2-Clause", + "dependencies": { + "@jsamr/counter-style": "^2.0.1", + "@jsamr/react-native-li": "^2.3.0", + "@native-html/transient-render-engine": "11.2.3", + "@types/ramda": "^0.27.40", + "@types/urijs": "^1.19.15", + "prop-types": "^15.5.7", + "ramda": "^0.27.2", + "stringify-entities": "^3.1.0", + "urijs": "^1.19.6" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-safe-area-context": { "version": "5.6.2", "license": "MIT", @@ -7270,6 +7400,21 @@ "node": ">=8" } }, + "node_modules/stringify-entities": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.1.0.tgz", + "integrity": "sha512-3FP+jGMmMV/ffZs86MoghGqAoqXAdxLrJP4GUdrDN1aIScYih5tuIO3eF4To5AJZ79KDZ8Fpdy7QJnK8SsL1Vg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/strip-ansi": { "version": "5.2.0", "license": "MIT", @@ -7427,6 +7572,12 @@ "version": "0.0.3", "license": "MIT" }, + "node_modules/ts-toolbelt": { + "version": "6.15.5", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz", + "integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==", + "license": "Apache-2.0" + }, "node_modules/tslib": { "version": "2.8.1", "license": "0BSD" @@ -7447,7 +7598,7 @@ }, "node_modules/typescript": { "version": "5.9.3", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -7518,9 +7669,9 @@ } }, "node_modules/unimodules-app-loader": { - "version": "55.0.3-canary-20260328-bdc6273", - "resolved": "https://registry.npmjs.org/unimodules-app-loader/-/unimodules-app-loader-55.0.3-canary-20260328-bdc6273.tgz", - "integrity": "sha512-L95O/qGf1Z5AC+Hc4scmzTdXkZ7SSwyZxJeEuyDL79tfUxTtn88gbIvzxSV0ml4oAQMEFCZmulVDLXZBdUQrNw==", + "version": "55.0.3-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/unimodules-app-loader/-/unimodules-app-loader-55.0.3-canary-20260328-2049187.tgz", + "integrity": "sha512-kqGCLCS35FFs4ue6BCIMuCVLO/KTco9WOHq/ghEVsR4NgGnhb9D3td2/D6KAFRY3c8qQ83x8mBAsHTwN7EUnNA==", "license": "MIT" }, "node_modules/unpipe": { @@ -7558,6 +7709,12 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "license": "MIT" + }, "node_modules/use-callback-ref": { "version": "1.3.3", "license": "MIT", @@ -7815,6 +7972,15 @@ "node": ">=8.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "license": "ISC", diff --git a/package.json b/package.json index 2560a6b..98c4b54 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "lint": "expo lint" }, "dependencies": { + "@react-native-async-storage/async-storage": "^3.0.2", "@react-navigation/bottom-tabs": "^7.15.5", "@react-navigation/elements": "^2.9.10", "@react-navigation/native": "^7.1.33", @@ -38,6 +39,7 @@ "react-native": "0.83.4", "react-native-gesture-handler": "~2.30.0", "react-native-reanimated": "4.2.1", + "react-native-render-html": "^6.3.4", "react-native-safe-area-context": "~5.6.2", "react-native-screens": "~4.23.0", "react-native-web": "~0.21.0", diff --git a/src/app/article/[id].tsx b/src/app/article/[id].tsx index a682c05..57b029c 100644 --- a/src/app/article/[id].tsx +++ b/src/app/article/[id].tsx @@ -13,6 +13,7 @@ import { import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { SymbolView } from 'expo-symbols'; import { useLocalSearchParams } from 'expo-router'; +import RenderHtml from 'react-native-render-html'; import { ThemedText } from '@/components/themed-text'; import { ThemedView } from '@/components/themed-view'; @@ -81,9 +82,46 @@ export default function ArticleDetailScreen() { }); }; + const extractImagesFromHtml = (html: string): string[] => { + const imgRegex = /]+src=["']([^"']+)["'][^>]*>/gi; + const images: string[] = []; + let match; + while ((match = imgRegex.exec(html)) !== null) { + if (match[1] && !images.includes(match[1])) { + images.push(match[1]); + } + } + return images; + }; + + const getGalleryImages = (): string[] => { + const images: string[] = []; + if (article?.content) { + images.push(...extractImagesFromHtml(article.content)); + } + if (article?.description) { + images.push(...extractImagesFromHtml(article.description)); + } + return [...new Set(images)]; + }; + + const galleryImages = getGalleryImages(); + const renderContent = (content?: string) => { if (!content) return null; + const isHtml = /<[a-z][\s\S]*>/i.test(content); + + if (isHtml) { + return ( + + ); + } + return ( {content} @@ -169,6 +207,26 @@ export default function ArticleDetailScreen() { + {galleryImages.length > 0 && ( + + + {galleryImages.map((imgUrl, index) => ( + Linking.openURL(imgUrl)}> + + + ))} + + + )} + {article.description && ( @@ -244,6 +302,18 @@ const styles = StyleSheet.create({ justifyContent: 'center', alignItems: 'center', }, + gallery: { + paddingVertical: Spacing.two, + }, + galleryContent: { + paddingHorizontal: Spacing.four, + gap: Spacing.two, + }, + galleryImage: { + width: 200, + height: 150, + borderRadius: Spacing.two, + }, section: { padding: Spacing.four, paddingTop: 0, diff --git a/src/components/feed-item-card.tsx b/src/components/feed-item-card.tsx index 92e44e9..d1d3a25 100644 --- a/src/components/feed-item-card.tsx +++ b/src/components/feed-item-card.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { StyleSheet, TouchableOpacity, Linking } from 'react-native'; +import { useRouter } from 'expo-router'; import { FeedItem } from '@/types/feed'; import { ThemedText } from './themed-text'; import { ThemedView } from './themed-view'; @@ -18,10 +19,13 @@ interface FeedItemCardProps { export function FeedItemCard({ item, onPress, onLongPress }: FeedItemCardProps) { const scheme = useColorScheme(); const colors = Colors[scheme === 'unspecified' ? 'light' : scheme]; + const router = useRouter(); const handlePress = () => { if (onPress) { onPress(item); + } else if (item.id) { + router.push(`/article/${item.id}` as any); } else if (item.link) { Linking.openURL(item.link); } @@ -63,7 +67,7 @@ export function FeedItemCard({ item, onPress, onLongPress }: FeedItemCardProps) return ''; }, [item.content, item.description]); - return ( + const cardContent = ( ); + + if (item.id) { + return ( + + + {item.subscriptionTitle && ( + + {item.subscriptionTitle} + + )} + + + {item.title} + + + {excerpt && ( + + {excerpt} + + )} + + + {item.author && ( + + {item.author} + + )} + {item.published && ( + + {formatDate(item.published)} + + )} + + + {item.enclosure && item.enclosure.type.includes('audio') && ( + + + 🎧 Audio + + + )} + + + ); +} + + return cardContent; } const styles = StyleSheet.create({ diff --git a/src/components/settings.tsx b/src/components/settings.tsx index 95ed37c..0e2091d 100644 --- a/src/components/settings.tsx +++ b/src/components/settings.tsx @@ -387,7 +387,7 @@ export default function SettingsScreen() { Timezone handleAccountSettingChange('timezone', text)} diff --git a/src/stores/bookmark-store.ts b/src/stores/bookmark-store.ts index 58cbdf6..91450e6 100644 --- a/src/stores/bookmark-store.ts +++ b/src/stores/bookmark-store.ts @@ -2,6 +2,7 @@ import { create } from 'zustand'; import { persist, createJSONStorage } from 'zustand/middleware'; +import AsyncStorage from '@react-native-async-storage/async-storage'; interface BookmarkState { bookmarkedIds: Set; @@ -50,7 +51,7 @@ export const useBookmarkStore = create()( }), { name: 'rssuper-bookmarks', - storage: createJSONStorage(() => localStorage), + storage: createJSONStorage(() => AsyncStorage), partialize: (state) => ({ bookmarkedIds: Array.from(state.bookmarkedIds), }),