diff --git a/.editorconfig b/.editorconfig index ab3ba8831..0f1786729 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,7 +7,3 @@ indent_size = 2 indent_style = space insert_final_newline = true trim_trailing_whitespace = true - -# Windows files -[*.bat] -end_of_line = crlf diff --git a/.eslintrc.js b/.eslintrc.js index 6e83b407b..b017f0aa8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,10 +1,10 @@ module.exports = { + root: true, + parser: '@typescript-eslint/parser', extends: [ - 'standard', + 'standard-with-typescript', 'plugin:react-hooks/recommended', ], - plugins: ['html', 'react'], - parser: '@babel/eslint-parser', rules: { 'no-new': 'off', camelcase: 'off', @@ -16,12 +16,47 @@ module.exports = { eqeqeq: 'off', 'no-multiple-empty-lines': [1, { max: 2 }], 'comma-dangle': [2, 'always-multiline'], - 'react/jsx-uses-react': 'error', - 'react/jsx-uses-vars': 'error', + 'standard/no-callback-literal': 'off', 'prefer-const': 'off', + 'no-labels': 'off', + 'node/no-callback-literal': 'off', }, - settings: { - 'html/html-extensions': ['.jsx'], - }, - ignorePatterns: ['vendors', '*.min.js'], + overrides: [ + { + files: ['*.ts', '*.tsx'], + rules: { + 'no-new': 'off', + camelcase: 'off', + 'no-return-assign': 'off', + 'space-before-function-paren': ['error', 'never'], + 'no-var': 'error', + 'no-fallthrough': 'off', + 'prefer-promise-reject-errors': 'off', + eqeqeq: 'off', + 'no-multiple-empty-lines': [1, { max: 2 }], + 'comma-dangle': [2, 'always-multiline'], + 'standard/no-callback-literal': 'off', + 'prefer-const': 'off', + 'no-labels': 'off', + 'node/no-callback-literal': 'off', + '@typescript-eslint/strict-boolean-expressions': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/space-before-function-paren': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/restrict-template-expressions': [1, { + allowBoolean: true, + }], + '@typescript-eslint/naming-convention': 'off', + '@typescript-eslint/return-await': 'off', + 'multiline-ternary': 'off', + '@typescript-eslint/comma-dangle': 'off', + '@typescript-eslint/no-dynamic-delete': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/ban-types': 'off', + }, + parserOptions: { + project: './tsconfig.json', + }, + }, + ], } diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index 975227dab..000000000 --- a/.flowconfig +++ /dev/null @@ -1,67 +0,0 @@ -[ignore] -; We fork some components by platform -.*/*[.]android.js - -; Ignore "BUCK" generated dirs -/\.buckd/ - -; Ignore polyfills -node_modules/react-native/Libraries/polyfills/.* - -; Flow doesn't support platforms -.*/Libraries/Utilities/LoadingView.js - -.*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$ - -[untyped] -.*/node_modules/@react-native-community/cli/.*/.* - -[include] - -[libs] -node_modules/react-native/interface.js -node_modules/react-native/flow/ - -[options] -emoji=true - -exact_by_default=true - -format.bracket_spacing=false - -module.file_ext=.js -module.file_ext=.json -module.file_ext=.ios.js - -munge_underscores=true - -module.name_mapper='^react-native/\(.*\)$' -> '/node_modules/react-native/\1' -module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub' - -suppress_type=$FlowIssue -suppress_type=$FlowFixMe -suppress_type=$FlowFixMeProps -suppress_type=$FlowFixMeState - -[lints] -sketchy-null-number=warn -sketchy-null-mixed=warn -sketchy-number=warn -untyped-type-import=warn -nonstrict-import=warn -deprecated-type=warn -unsafe-getters-setters=warn -unnecessary-invariant=warn -signature-verification-failure=warn - -[strict] -deprecated-type -nonstrict-import -sketchy-null -unclear-type -unsafe-getters-setters -untyped-import -untyped-type-import - -[version] -^0.170.0 diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 59b845bf9..000000000 --- a/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -# Windows files should use crlf line endings -# https://help.github.com/articles/dealing-with-line-endings/ -*.bat text eol=crlf \ No newline at end of file diff --git a/.github/workflows/beta-pack.yml b/.github/workflows/beta-pack.yml index 684cec495..7dbe949ce 100644 --- a/.github/workflows/beta-pack.yml +++ b/.github/workflows/beta-pack.yml @@ -16,7 +16,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v3 with: - node-version: '16' + node-version: '18' - name: Cache Gradle Wrapper uses: actions/cache@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5cef50dba..a2d96200b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v3 with: - node-version: '16' + node-version: '18' - name: Cache Gradle Wrapper uses: actions/cache@v3 diff --git a/.gitignore b/.gitignore index ac9287a78..6bb4d5792 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ DerivedData *.hmap *.ipa *.xcuserstate +ios/.xcode.env.local # Android/IntelliJ # @@ -30,6 +31,7 @@ local.properties keystore.properties *.iml *.hprof +.cxx/ # node.js # @@ -50,9 +52,10 @@ buck-out/ # For more information about the recommended setup visit: # https://docs.fastlane.tools/best-practices/source-control/ -*/fastlane/report.xml -*/fastlane/Preview.html -*/fastlane/screenshots +**/fastlane/report.xml +**/fastlane/Preview.html +**/fastlane/screenshots +**/fastlane/test_output # Bundle artifact *.jsbundle diff --git a/.ncurc.js b/.ncurc.js index 6ba15efab..85152c461 100644 --- a/.ncurc.js +++ b/.ncurc.js @@ -1,17 +1,16 @@ module.exports = { upgrade: true, - // target: 'newest', reject: [ - 'metro-react-native-babel-preset', - 'readable-stream', - 'stream-browserify', - 'url', - 'util', - 'babel-jest', - 'jest', - + // 'metro-react-native-babel-preset', + '@types/react-native', 'react-native', 'react', - 'react-test-renderer', ] + + // target: 'patch', + // filter: [ + // 'react-native', + // '@types/react-native', + // 'react' + // ], } diff --git a/.node-version b/.node-version new file mode 100644 index 000000000..b6a7d89c6 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +16 diff --git a/.ruby-version b/.ruby-version index a4dd9dba4..a603bb50a 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.4 +2.7.5 diff --git a/.vscode/i18n-ally-custom-framework.yml b/.vscode/i18n-ally-custom-framework.yml new file mode 100644 index 000000000..8f52ce17e --- /dev/null +++ b/.vscode/i18n-ally-custom-framework.yml @@ -0,0 +1,30 @@ +# .vscode/i18n-ally-custom-framework.yml + +# An array of strings which contain Language Ids defined by VS Code +# You can check avaliable language ids here: https://code.visualstudio.com/docs/languages/overview#_language-id +languageIds: + - javascript + - javascriptreact + - typescript + - typescriptreact + +# An array of RegExes to find the key usage. **The key should be captured in the first match group**. +# You should unescape RegEx strings in order to fit in the YAML file +# To help with this, you can use https://www.freeformatter.com/json-escape.html +usageMatchRegex: + # The following example shows how to detect `t("your.i18n.keys")` + # the `{key}` will be placed by a proper keypath matching regex, + # you can ignore it and use your own matching rules as well + - "[^\\w\\d]t\\(['\"`]({key})['\"`]" + + +# An array of strings containing refactor templates. +# The "$1" will be replaced by the keypath specified. +# Optional: uncomment the following two lines to use + +# refactorTemplates: +# - i18n.get("$1") + + +# If set to true, only enables this custom framework (will disable all built-in frameworks) +monopoly: true diff --git a/.vscode/javascript.code-snippets b/.vscode/javascript.code-snippets index 1abd32362..f22c2506a 100644 --- a/.vscode/javascript.code-snippets +++ b/.vscode/javascript.code-snippets @@ -16,7 +16,7 @@ // "description": "Log output to console" // } "Import translation": { - "scope": "javascript,typescript", + "scope": "javascript,typescript,typescriptreact", "prefix": "imtl", "body": [ "import { useTranslation } from '@/plugins/i18n'", @@ -24,16 +24,32 @@ ], "description": "Translation Language" }, - "Import store hook": { - "scope": "javascript,typescript", - "prefix": "imsh", + "Import store setting": { + "scope": "javascript,typescript,typescriptreact", + "prefix": "imss", "body": [ - "import { useGetter, useDispatch } from '@/store'" + "import settingState from '@/store/setting/state'" ], - "description": "Import store hook" + "description": "Import store setting" + }, + "Import store player": { + "scope": "javascript,typescript,typescriptreact", + "prefix": "imsp", + "body": [ + "import playerState from '@/store/player/state'" + ], + "description": "Import store player" + }, + "Import store list": { + "scope": "javascript,typescript,typescriptreact", + "prefix": "imsl", + "body": [ + "import listState from '@/store/list/state'" + ], + "description": "Import store list" }, "Import toast": { - "scope": "javascript,typescript", + "scope": "javascript,typescript,typescriptreact", "prefix": "imts", "body": [ "import { toast } from '@/utils/tools'", @@ -42,7 +58,7 @@ "description": "Import toast" }, "Use getter theme": { - "scope": "javascript,typescript", + "scope": "javascript,typescript,typescriptreact", "prefix": "ugt", "body": [ "const theme = useGetter('common', 'theme')" diff --git a/Gemfile b/Gemfile index c72a1ae2c..5efda89f4 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,6 @@ source 'https://rubygems.org' + # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version -ruby '2.7.4' +ruby '2.7.5' + gem 'cocoapods', '~> 1.11', '>= 1.11.2' diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 562835193..000000000 --- a/Gemfile.lock +++ /dev/null @@ -1,100 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - CFPropertyList (3.0.5) - rexml - activesupport (6.1.5) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - zeitwerk (~> 2.3) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) - algoliasearch (1.27.5) - httpclient (~> 2.8, >= 2.8.3) - json (>= 1.5.1) - atomos (0.1.3) - claide (1.1.0) - cocoapods (1.11.3) - addressable (~> 2.8) - claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.11.3) - cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.4.0, < 2.0) - cocoapods-plugins (>= 1.0.0, < 2.0) - cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.4.0, < 2.0) - cocoapods-try (>= 1.1.0, < 2.0) - colored2 (~> 3.1) - escape (~> 0.0.4) - fourflusher (>= 2.3.0, < 3.0) - gh_inspector (~> 1.0) - molinillo (~> 0.8.0) - nap (~> 1.0) - ruby-macho (>= 1.0, < 3.0) - xcodeproj (>= 1.21.0, < 2.0) - cocoapods-core (1.11.3) - activesupport (>= 5.0, < 7) - addressable (~> 2.8) - algoliasearch (~> 1.0) - concurrent-ruby (~> 1.1) - fuzzy_match (~> 2.0.4) - nap (~> 1.0) - netrc (~> 0.11) - public_suffix (~> 4.0) - typhoeus (~> 1.0) - cocoapods-deintegrate (1.0.5) - cocoapods-downloader (1.6.3) - cocoapods-plugins (1.0.0) - nap - cocoapods-search (1.0.1) - cocoapods-trunk (1.6.0) - nap (>= 0.8, < 2.0) - netrc (~> 0.11) - cocoapods-try (1.2.0) - colored2 (3.1.2) - concurrent-ruby (1.1.10) - escape (0.0.4) - ethon (0.15.0) - ffi (>= 1.15.0) - ffi (1.15.5) - fourflusher (2.3.1) - fuzzy_match (2.0.4) - gh_inspector (1.1.3) - httpclient (2.8.3) - i18n (1.10.0) - concurrent-ruby (~> 1.0) - json (2.6.1) - minitest (5.15.0) - molinillo (0.8.0) - nanaimo (0.3.0) - nap (1.1.0) - netrc (0.11.0) - public_suffix (4.0.7) - rexml (3.2.5) - ruby-macho (2.5.1) - typhoeus (1.4.0) - ethon (>= 0.9.0) - tzinfo (2.0.4) - concurrent-ruby (~> 1.0) - xcodeproj (1.21.0) - CFPropertyList (>= 2.3.3, < 4.0) - atomos (~> 0.1.3) - claide (>= 1.0.2, < 2.0) - colored2 (~> 3.1) - nanaimo (~> 0.3.0) - rexml (~> 3.2.4) - zeitwerk (2.5.4) - -PLATFORMS - ruby - -DEPENDENCIES - cocoapods (~> 1.11, >= 1.11.2) - -RUBY VERSION - ruby 2.7.4p191 - -BUNDLED WITH - 2.2.27 diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9e9..000000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/android/app/build.gradle b/android/app/build.gradle index 637d70e5f..9cc4df50b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -152,30 +152,17 @@ android { targetSdkVersion rootProject.ext.targetSdkVersion versionCode verCode versionName verName - multiDexEnabled true buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + if (isNewArchitectureEnabled()) { - // We configure the NDK build only if you decide to opt-in for the New Architecture. + // We configure the CMake build only if you decide to opt-in for the New Architecture. externalNativeBuild { - ndkBuild { - arguments "APP_PLATFORM=android-21", - "APP_STL=c++_shared", - "NDK_TOOLCHAIN_VERSION=clang", - "GENERATED_SRC_DIR=$buildDir/generated/source", - "PROJECT_BUILD_DIR=$buildDir", - "REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid", - "REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build" - cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1" - cppFlags "-std=c++17" - // Make sure this target name is the same you specify inside the - // src/main/jni/Android.mk file for the `LOCAL_MODULE` variable. - targets "lxmusicmobile_appmodules" - - - // Fix for windows limit on number of character in file paths and in command lines - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - arguments "NDK_APP_SHORT_COMMANDS=true" - } + cmake { + arguments "-DPROJECT_BUILD_DIR=$buildDir", + "-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid", + "-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build", + "-DNODE_MODULES_DIR=$rootDir/../node_modules", + "-DANDROID_STL=c++_shared" } } if (!enableSeparateBuildPerCPUArchitecture) { @@ -185,11 +172,12 @@ android { } } } + if (isNewArchitectureEnabled()) { // We configure the NDK build only if you decide to opt-in for the New Architecture. externalNativeBuild { - ndkBuild { - path "$projectDir/src/main/jni/Android.mk" + cmake { + path "$projectDir/src/main/jni/CMakeLists.txt" } } def reactAndroidProjectDir = project(':ReactAndroid').projectDir @@ -209,16 +197,17 @@ android { // preBuild.dependsOn("generateCodegenArtifactsFromSchema") preDebugBuild.dependsOn(packageReactNdkDebugLibs) preReleaseBuild.dependsOn(packageReactNdkReleaseLibs) + // Due to a bug inside AGP, we have to explicitly set a dependency - // between configureNdkBuild* tasks and the preBuild tasks. + // between configureCMakeDebug* tasks and the preBuild tasks. // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732 - configureNdkBuildRelease.dependsOn(preReleaseBuild) - configureNdkBuildDebug.dependsOn(preDebugBuild) + configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild) + configureCMakeDebug.dependsOn(preDebugBuild) reactNativeArchitectures().each { architecture -> - tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure { + tasks.findByName("configureCMakeDebug[${architecture}]")?.configure { dependsOn("preDebugBuild") } - tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure { + tasks.findByName("configureCMakeRelWithDebInfo[${architecture}]")?.configure { dependsOn("preReleaseBuild") } } @@ -303,11 +292,8 @@ dependencies { implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" - implementation 'com.android.support:multidex:1.0.3' - - implementation 'commons-io:commons-io:2.8.0' - - implementation 'org.apache.commons:commons-compress:1.20' + implementation 'commons-io:commons-io:2.11.0' + implementation 'org.apache.commons:commons-compress:1.22' debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { exclude group:'com.facebook.fbjni' @@ -323,9 +309,10 @@ dependencies { } if (enableHermes) { - def hermesPath = "../../node_modules/hermes-engine/android/"; - debugImplementation files(hermesPath + "hermes-debug.aar") - releaseImplementation files(hermesPath + "hermes-release.aar") + //noinspection GradleDynamicVersion + implementation("com.facebook.react:hermes-engine:+") { // From node_modules + exclude group:'com.facebook.fbjni' + } } else { implementation jscFlavor } @@ -338,7 +325,11 @@ if (isNewArchitectureEnabled()) { configurations.all { resolutionStrategy.dependencySubstitution { substitute(module("com.facebook.react:react-native")) - .using(project(":ReactAndroid")).because("On New Architecture we're building React Native from source") + .using(project(":ReactAndroid")) + .because("On New Architecture we're building React Native from source") + substitute(module("com.facebook.react:hermes-engine")) + .using(project(":ReactAndroid:hermes-engine")) + .because("On New Architecture we're building Hermes from source") } } } @@ -361,4 +352,3 @@ def isNewArchitectureEnabled() { } apply from: "../../node_modules/react-native-vector-icons/fonts.gradle" - diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index 3cc0f30e4..889cc8b91 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -9,5 +9,5 @@ # Add any project specific keep options here: --keep class com.facebook.hermes.unicode.** { *; } --keep class com.facebook.jni.** { *; } +# -keep class com.facebook.hermes.unicode.** { *; } +# -keep class com.facebook.jni.** { *; } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8fee2af29..7cc39d51a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,7 +1,6 @@ - + xmlns:tools="http://schemas.android.com/tools" + package="cn.toside.music.mobile"> @@ -11,42 +10,40 @@ - - - - - - - - - - - - - - - - + android:networkSecurityConfig="@xml/network_security_config" + android:requestLegacyExternalStorage="true" + android:icon="@mipmap/ic_launcher" + android:roundIcon="@mipmap/ic_launcher_round" + android:allowBackup="false" + android:theme="@style/AppTheme"> + + + + + + + + + + + + + + diff --git a/android/app/src/main/assets/fonts/icomoon.ttf b/android/app/src/main/assets/fonts/icomoon.ttf index 96df7084d..ad3ecd824 100644 Binary files a/android/app/src/main/assets/fonts/icomoon.ttf and b/android/app/src/main/assets/fonts/icomoon.ttf differ diff --git a/android/app/src/main/java/cn/toside/music/mobile/MainActivity.java b/android/app/src/main/java/cn/toside/music/mobile/MainActivity.java index ba710df8d..b4fd3172f 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/MainActivity.java +++ b/android/app/src/main/java/cn/toside/music/mobile/MainActivity.java @@ -1,15 +1,33 @@ package cn.toside.music.mobile; -import android.os.Bundle; - import com.reactnativenavigation.NavigationActivity; - -import org.devio.rn.splashscreen.SplashScreen; +import com.facebook.react.ReactActivityDelegate; +import com.facebook.react.ReactRootView; public class MainActivity extends NavigationActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - SplashScreen.show(this, R.style.SplashScreenTheme, true); // here - super.onCreate(savedInstanceState); + + + + + + public static class MainActivityDelegate extends ReactActivityDelegate { + public MainActivityDelegate(NavigationActivity activity, String mainComponentName) { + super(activity, mainComponentName); + } + + @Override + protected ReactRootView createRootView() { + ReactRootView reactRootView = new ReactRootView(getContext()); + // If you opted-in for the New Architecture, we enable the Fabric Renderer. + reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED); + return reactRootView; + } + + @Override + protected boolean isConcurrentRootEnabled() { + // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18). + // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html + return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + } } } diff --git a/android/app/src/main/java/cn/toside/music/mobile/MainApplication.java b/android/app/src/main/java/cn/toside/music/mobile/MainApplication.java index 32588e110..d46b343cf 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/MainApplication.java +++ b/android/app/src/main/java/cn/toside/music/mobile/MainApplication.java @@ -1,22 +1,22 @@ package cn.toside.music.mobile; +import android.app.Application; import android.content.Context; - import com.facebook.react.PackageList; +import com.reactnativenavigation.NavigationApplication; import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactNativeHost; +import com.reactnativenavigation.react.NavigationReactNativeHost; import com.facebook.react.ReactPackage; import com.facebook.react.config.ReactFeatureFlags; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.react.NavigationReactNativeHost; - +import com.facebook.soloader.SoLoader; +import cn.toside.music.mobile.newarchitecture.MainApplicationReactNativeHost; import java.lang.reflect.InvocationTargetException; import java.util.List; import cn.toside.music.mobile.cache.CachePackage; import cn.toside.music.mobile.gzip.GzipPackage; import cn.toside.music.mobile.lyric.LyricPackage; -import cn.toside.music.mobile.newarchitecture.MainApplicationReactNativeHost; import cn.toside.music.mobile.utils.UtilsPackage; public class MainApplication extends NavigationApplication { @@ -34,10 +34,10 @@ protected List getPackages() { List packages = new PackageList(this).getPackages(); // Packages that cannot be autolinked yet can be added manually here, for example: // packages.add(new MyReactNativePackage()); - packages.add(new GzipPackage()); packages.add(new CachePackage()); - packages.add(new UtilsPackage()); + packages.add(new GzipPackage()); packages.add(new LyricPackage()); + packages.add(new UtilsPackage()); return packages; } @@ -48,7 +48,8 @@ protected String getJSMainModuleName() { }; private final ReactNativeHost mNewArchitectureNativeHost = - new MainApplicationReactNativeHost(this); + new MainApplicationReactNativeHost(this); + @Override public ReactNativeHost getReactNativeHost() { if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { diff --git a/android/app/src/main/java/cn/toside/music/mobile/lyric/Lyric.java b/android/app/src/main/java/cn/toside/music/mobile/lyric/Lyric.java index 7045c3ff3..22202aa57 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/lyric/Lyric.java +++ b/android/app/src/main/java/cn/toside/music/mobile/lyric/Lyric.java @@ -196,8 +196,8 @@ public void toggleRoma(boolean isShowRoma) { refreshLyric(); } - public void setColor(String color) { - lyricView.setColor(color); + public void setPlayedColor(String unplayColor, String playedColor, String shadowColor) { + lyricView.setColor(unplayColor, playedColor, shadowColor); } public void setAlpha(float alpha) { lyricView.setAlpha(alpha); } diff --git a/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricModule.java b/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricModule.java index 6ce28a370..5ab196954 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricModule.java +++ b/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricModule.java @@ -107,8 +107,8 @@ public void toggleLock(boolean isLock, Promise promise) { } @ReactMethod - public void setColor(String themeColor, Promise promise) { - if (lyric != null) lyric.setColor(themeColor); + public void setColor(String unplayColor, String playedColor, String shadowColor, Promise promise) { + if (lyric != null) lyric.setPlayedColor(unplayColor, playedColor, shadowColor); promise.resolve(null); } diff --git a/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricPlayer.java b/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricPlayer.java index 3b2eee906..6400be140 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricPlayer.java +++ b/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricPlayer.java @@ -14,6 +14,8 @@ public class LyricPlayer { final String timeFieldExp = "^(?:\\[[\\d:.]+])+"; final String timeExp = "[\\d:.]+"; + final String timeLabelRxp = "^(\\[[\\d:]+\\.)0+(\\d+])"; + final String timeLabelFixRxp = "(?:\\.0+|0+)$"; // HashMap tagRegMap; Pattern timeFieldPattern; Pattern timePattern; @@ -124,8 +126,9 @@ private void parseExtendedLyric(HashMap linesMap, String extendedLyric) { Matcher timeMatchResult = timePattern.matcher(timeField); while (timeMatchResult.find()) { String timeStr = timeMatchResult.group(); - if (!timeStr.contains(".")) timeStr += ".0"; - timeStr = timeStr.replaceAll("(?:\\.0+|0+)$", ""); + if (timeStr.contains(".")) timeStr = timeStr.replaceAll(timeLabelRxp, "$1$2"); + else timeStr += ".0"; + timeStr = timeStr.replaceAll(timeLabelFixRxp, ""); HashMap targetLine = (HashMap) linesMap.get(timeStr); if (targetLine != null) ((ArrayList) targetLine.get("extendedLyrics")).add(text); } @@ -151,8 +154,9 @@ private void initLines() { Matcher timeMatchResult = timePattern.matcher(timeField); while (timeMatchResult.find()) { String timeStr = timeMatchResult.group(); - if (!timeStr.contains(".")) timeStr += ".0"; - timeStr = timeStr.replaceAll("(?:\\.0+|0+)$", ""); + if (timeStr.contains(".")) timeStr = timeStr.replaceAll(timeLabelRxp, "$1$2"); + else timeStr += ".0"; + timeStr = timeStr.replaceAll(timeLabelFixRxp, ""); if (linesMap.containsKey(timeStr)) { ((ArrayList) ((HashMap) linesMap.get(timeStr)).get("extendedLyrics")).add(text); continue; diff --git a/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricSwitchView.java b/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricSwitchView.java index 802ef4ea0..8175ccaa8 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricSwitchView.java +++ b/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricSwitchView.java @@ -27,10 +27,13 @@ public final class LyricSwitchView extends TextSwitcher { // private final boolean isSingleLine; private boolean isShowAnima; + private boolean isSingleLine; + public LyricSwitchView(Context context, boolean isSingleLine, boolean isShowAnima) { super(context); // this.isSingleLine = isSingleLine; this.isShowAnima = isShowAnima; + this.isSingleLine = isSingleLine; if (isSingleLine) { viewArray = new ArrayList<>(2); @@ -38,9 +41,9 @@ public LyricSwitchView(Context context, boolean isSingleLine, boolean isShowAnim textView2 = new LyricTextView(context); viewArray.add(textView); viewArray.add(textView2); - for (TextView v : viewArray) { - v.setShadowLayer(0.1f, 0, 0, Color.BLACK); - } +// for (TextView v : viewArray) { +// v.setShadowLayer(0.1f, 0, 0, Color.BLACK); +// } } else { viewArray = new ArrayList<>(2); textView = new TextView(context); @@ -48,7 +51,7 @@ public LyricSwitchView(Context context, boolean isSingleLine, boolean isShowAnim viewArray.add(textView); viewArray.add(textView2); for (TextView v : viewArray) { - v.setShadowLayer(0.2f, 0, 0, Color.BLACK); +// v.setShadowLayer(0.2f, 0, 0, Color.BLACK); v.setEllipsize(TextUtils.TruncateAt.END); } } @@ -149,6 +152,16 @@ public void setTextColor(int i) { for (TextView v : viewArray) v.setTextColor(i); } + public void setShadowColor(int i) { + float radius; + if (isSingleLine) { + radius = 0.1f; + } else { + radius = 0.2f; + } + for (TextView v : viewArray) v.setShadowLayer(radius, 0, 0, i); + } + public void setSourceText(CharSequence str) { for (TextView v : viewArray) v.setText(str); } diff --git a/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricTextView.java b/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricTextView.java index 62c3f95f5..f3c639234 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricTextView.java +++ b/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricTextView.java @@ -64,6 +64,12 @@ public void setTextColor(int color) { postInvalidate(); } + @Override + public void setShadowLayer(float radius, float dx, float dy, int shadowColor) { + if (mPaint != null) mPaint.setShadowLayer(radius, dx, dy, shadowColor); + post(mStartScrollRunnable); + } + @Override public void setTextSize(float size) { super.setTextSize(size); diff --git a/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricView.java b/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricView.java index 045efd59f..31624eca7 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricView.java +++ b/android/app/src/main/java/cn/toside/music/mobile/lyric/LyricView.java @@ -23,6 +23,8 @@ import com.facebook.react.bridge.WritableMap; import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import cn.toside.music.mobile.R; @@ -51,7 +53,9 @@ public class LyricView extends Activity implements View.OnTouchListener { private boolean isLock = false; private boolean isSingleLine = false; private boolean isShowToggleAnima = false; - private String themeColor = "#07c556"; + private String unplayColor = "rgba(255, 255, 255, 1)"; + private String playedColor = "rgba(7, 197, 86, 1)"; + private String shadowColor = "rgba(0, 0, 0, 0.15)"; // private String lastText = "LX Music ^-^"; private String textX = "LEFT"; private String textY = "TOP"; @@ -204,7 +208,9 @@ public void showLyricView(Bundle options) { isLock = options.getBoolean("isLock", isLock); isSingleLine = options.getBoolean("isSingleLine", isSingleLine); isShowToggleAnima = options.getBoolean("isShowToggleAnima", isShowToggleAnima); - themeColor = options.getString("themeColor", themeColor); + unplayColor = options.getString("unplayColor", unplayColor); + playedColor = options.getString("playedColor", playedColor); + shadowColor = options.getString("shadowColor", shadowColor); prevViewPercentageX = (float) options.getDouble("lyricViewX", 0f) / 100f; prevViewPercentageY = (float) options.getDouble("lyricViewY", 0f) / 100f; textX = options.getString("textX", textX); @@ -225,13 +231,28 @@ public void showLyricView() { } listenOrientationEvent(); } + public static int parseColor(String input) { + if (input.startsWith("#")) return Color.parseColor(input); + Pattern c = Pattern.compile("rgba? *\\( *(\\d+), *(\\d+), *(\\d+)(?:, *([\\d.]+))? *\\)"); + Matcher m = c.matcher(input); + if (m.matches()) { + int red = Integer.parseInt(m.group(1)); + int green = Integer.parseInt(m.group(2)); + int blue = Integer.parseInt(m.group(3)); + float a = 1; + if (m.group(4) != null) a = Float.parseFloat(m.group(4)); + return Color.argb((int) (a * 255), red, green, blue); + } + return Color.parseColor("#000000"); + } private void createTextView() { textView = new LyricSwitchView(reactContext, isSingleLine, isShowToggleAnima); textView.setText(""); textView.setText(currentLyric); - textView.setTextColor(Color.parseColor(themeColor)); + textView.setTextColor(parseColor(playedColor)); + textView.setShadowColor(parseColor(shadowColor)); textView.setAlpha(alpha); textView.setTextSize(textSize); // Log.d("Lyric", "alpha: " + alpha + " text size: " + textSize); @@ -248,7 +269,7 @@ private void createTextView() { case "RIGHT": textPositionX = Gravity.END; break; - case "left": + case "Left": default: textPositionX = Gravity.START; break; @@ -489,10 +510,13 @@ public void unlockView() { windowManager.updateViewLayout(textView, layoutParams); } - public void setColor(String color) { - themeColor = color; + public void setColor(String unplayColor, String playedColor, String shadowColor) { + this.unplayColor = unplayColor; + this.playedColor = playedColor; + this.shadowColor = shadowColor; if (textView == null) return; - textView.setTextColor(Color.parseColor(color)); + textView.setTextColor(parseColor(playedColor)); + textView.setShadowColor(parseColor(shadowColor)); // windowManager.updateViewLayout(textView, layoutParams); } @@ -510,7 +534,7 @@ public void setLyricTextPosition(String textX, String textY) { case "RIGHT": textPositionX = Gravity.END; break; - case "left": + case "LEFT": default: textPositionX = Gravity.START; break; diff --git a/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/MainApplicationReactNativeHost.java b/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/MainApplicationReactNativeHost.java index e0cb50cce..19f7bd497 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/MainApplicationReactNativeHost.java +++ b/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/MainApplicationReactNativeHost.java @@ -16,8 +16,8 @@ import com.facebook.react.bridge.UIManager; import com.facebook.react.fabric.ComponentFactory; import com.facebook.react.fabric.CoreComponentsRegistry; -import com.facebook.react.fabric.EmptyReactNativeConfig; import com.facebook.react.fabric.FabricJSIModuleProvider; +import com.facebook.react.fabric.ReactNativeConfig; import com.facebook.react.uimanager.ViewManagerRegistry; import cn.toside.music.mobile.BuildConfig; import cn.toside.music.mobile.newarchitecture.components.MainComponentsRegistry; @@ -105,7 +105,7 @@ public JSIModuleProvider getJSIModuleProvider() { return new FabricJSIModuleProvider( reactApplicationContext, componentFactory, - new EmptyReactNativeConfig(), + ReactNativeConfig.DEFAULT_CONFIG, viewManagerRegistry); } }); diff --git a/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/components/MainComponentsRegistry.java b/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/components/MainComponentsRegistry.java index 918c4a563..fe07f53db 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/components/MainComponentsRegistry.java +++ b/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/components/MainComponentsRegistry.java @@ -1,8 +1,10 @@ package cn.toside.music.mobile.newarchitecture.components; + import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; import com.facebook.react.fabric.ComponentFactory; import com.facebook.soloader.SoLoader; + /** * Class responsible to load the custom Fabric Components. This class has native methods and needs a * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ @@ -16,13 +18,17 @@ public class MainComponentsRegistry { static { SoLoader.loadLibrary("fabricjni"); } + @DoNotStrip private final HybridData mHybridData; + @DoNotStrip private native HybridData initHybrid(ComponentFactory componentFactory); + @DoNotStrip private MainComponentsRegistry(ComponentFactory componentFactory) { mHybridData = initHybrid(componentFactory); } + @DoNotStrip public static MainComponentsRegistry register(ComponentFactory componentFactory) { return new MainComponentsRegistry(componentFactory); diff --git a/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java b/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java index 025e13254..13122f0b7 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java +++ b/android/app/src/main/java/cn/toside/music/mobile/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java @@ -1,10 +1,12 @@ package cn.toside.music.mobile.newarchitecture.modules; + import com.facebook.jni.HybridData; import com.facebook.react.ReactPackage; import com.facebook.react.ReactPackageTurboModuleManagerDelegate; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.soloader.SoLoader; import java.util.List; + /** * Class responsible to load the TurboModules. This class has native methods and needs a * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ @@ -15,25 +17,31 @@ */ public class MainApplicationTurboModuleManagerDelegate extends ReactPackageTurboModuleManagerDelegate { + private static volatile boolean sIsSoLibraryLoaded; + protected MainApplicationTurboModuleManagerDelegate( ReactApplicationContext reactApplicationContext, List packages) { super(reactApplicationContext, packages); } + protected native HybridData initHybrid(); + native boolean canCreateTurboModule(String moduleName); + public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder { protected MainApplicationTurboModuleManagerDelegate build( ReactApplicationContext context, List packages) { return new MainApplicationTurboModuleManagerDelegate(context, packages); } } + @Override protected synchronized void maybeLoadOtherSoLibraries() { if (!sIsSoLibraryLoaded) { // If you change the name of your application .so file in the Android.mk file, // make sure you update the name here as well. - SoLoader.loadLibrary("lxmusic_appmodules"); + SoLoader.loadLibrary("cn_toside_music_mobile_appmodules"); sIsSoLibraryLoaded = true; } } diff --git a/android/app/src/main/java/cn/toside/music/mobile/utils/UtilsPackage.java b/android/app/src/main/java/cn/toside/music/mobile/utils/UtilsPackage.java index ebed47cb4..908002545 100644 --- a/android/app/src/main/java/cn/toside/music/mobile/utils/UtilsPackage.java +++ b/android/app/src/main/java/cn/toside/music/mobile/utils/UtilsPackage.java @@ -4,7 +4,6 @@ import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.ViewManager; -import cn.toside.music.mobile.gzip.GzipModule; import java.util.Arrays; import java.util.Collections; diff --git a/android/app/src/main/jni/Android.mk b/android/app/src/main/jni/Android.mk deleted file mode 100644 index d5540a4f2..000000000 --- a/android/app/src/main/jni/Android.mk +++ /dev/null @@ -1,40 +0,0 @@ -THIS_DIR := $(call my-dir) -include $(REACT_ANDROID_DIR)/Android-prebuilt.mk -# If you wish to add a custom TurboModule or Fabric component in your app you -# will have to include the following autogenerated makefile. -# include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk -include $(CLEAR_VARS) -LOCAL_PATH := $(THIS_DIR) -# You can customize the name of your application .so file here. -LOCAL_MODULE := lxmusic_appmodules -LOCAL_C_INCLUDES := $(LOCAL_PATH) -LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) -LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) -# If you wish to add a custom TurboModule or Fabric component in your app you -# will have to uncomment those lines to include the generated source -# files from the codegen (placed in $(GENERATED_SRC_DIR)/codegen/jni) -# -# LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni -# LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp) -# LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni -# Here you should add any native library you wish to depend on. -LOCAL_SHARED_LIBRARIES := \ - libfabricjni \ - libfbjni \ - libfolly_futures \ - libfolly_json \ - libglog \ - libjsi \ - libreact_codegen_rncore \ - libreact_debug \ - libreact_nativemodule_core \ - libreact_render_componentregistry \ - libreact_render_core \ - libreact_render_debug \ - libreact_render_graphics \ - librrc_view \ - libruntimeexecutor \ - libturbomodulejsijni \ - libyoga -LOCAL_CFLAGS := -DLOG_TAG=\"ReactNative\" -fexceptions -frtti -std=c++17 -Wall -include $(BUILD_SHARED_LIBRARY) diff --git a/android/app/src/main/jni/CMakeLists.txt b/android/app/src/main/jni/CMakeLists.txt new file mode 100644 index 000000000..b3ea3d09b --- /dev/null +++ b/android/app/src/main/jni/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.13) + +# Define the library name here. +project(cn_toside_music_mobile_appmodules) + +# This file includes all the necessary to let you build your application with the New Architecture. +include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake) diff --git a/android/app/src/main/jni/MainApplicationModuleProvider.cpp b/android/app/src/main/jni/MainApplicationModuleProvider.cpp index 640a5baac..26162dd87 100644 --- a/android/app/src/main/jni/MainApplicationModuleProvider.cpp +++ b/android/app/src/main/jni/MainApplicationModuleProvider.cpp @@ -1,9 +1,13 @@ #include "MainApplicationModuleProvider.h" + +#include #include + namespace facebook { namespace react { + std::shared_ptr MainApplicationModuleProvider( - const std::string moduleName, + const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { // Here you can provide your own module provider for TurboModules coming from // either your application or from external libraries. The approach to follow @@ -14,7 +18,15 @@ std::shared_ptr MainApplicationModuleProvider( // return module; // } // return rncore_ModuleProvider(moduleName, params); + + // Module providers autolinked by RN CLI + auto rncli_module = rncli_ModuleProvider(moduleName, params); + if (rncli_module != nullptr) { + return rncli_module; + } + return rncore_ModuleProvider(moduleName, params); } + } // namespace react } // namespace facebook diff --git a/android/app/src/main/jni/MainApplicationModuleProvider.h b/android/app/src/main/jni/MainApplicationModuleProvider.h index 522258e1f..b38ccf53f 100644 --- a/android/app/src/main/jni/MainApplicationModuleProvider.h +++ b/android/app/src/main/jni/MainApplicationModuleProvider.h @@ -1,11 +1,16 @@ #pragma once + #include #include + #include + namespace facebook { namespace react { + std::shared_ptr MainApplicationModuleProvider( - const std::string moduleName, + const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + } // namespace react } // namespace facebook diff --git a/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp b/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp index 88e992ce7..5fd688c50 100644 --- a/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp +++ b/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp @@ -1,12 +1,15 @@ #include "MainApplicationTurboModuleManagerDelegate.h" #include "MainApplicationModuleProvider.h" + namespace facebook { namespace react { + jni::local_ref MainApplicationTurboModuleManagerDelegate::initHybrid( jni::alias_ref) { return makeCxxInstance(); } + void MainApplicationTurboModuleManagerDelegate::registerNatives() { registerHybrid({ makeNativeMethod( @@ -16,23 +19,27 @@ void MainApplicationTurboModuleManagerDelegate::registerNatives() { MainApplicationTurboModuleManagerDelegate::canCreateTurboModule), }); } + std::shared_ptr MainApplicationTurboModuleManagerDelegate::getTurboModule( - const std::string name, - const std::shared_ptr jsInvoker) { + const std::string &name, + const std::shared_ptr &jsInvoker) { // Not implemented yet: provide pure-C++ NativeModules here. return nullptr; } + std::shared_ptr MainApplicationTurboModuleManagerDelegate::getTurboModule( - const std::string name, + const std::string &name, const JavaTurboModule::InitParams ¶ms) { return MainApplicationModuleProvider(name, params); } + bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule( - std::string name) { + const std::string &name) { return getTurboModule(name, nullptr) != nullptr || getTurboModule(name, {.moduleName = name}) != nullptr; } + } // namespace react } // namespace facebook diff --git a/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h b/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h index d870aac1d..5ad8072ec 100644 --- a/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h +++ b/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h @@ -1,9 +1,12 @@ #include #include + #include #include + namespace facebook { namespace react { + class MainApplicationTurboModuleManagerDelegate : public jni::HybridClass< MainApplicationTurboModuleManagerDelegate, @@ -11,20 +14,25 @@ class MainApplicationTurboModuleManagerDelegate public: // Adapt it to the package you used for your Java class. static constexpr auto kJavaDescriptor = - "Lcom/cn/toside/music/mobile/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; + "Lcn/toside/music/mobile/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; + static jni::local_ref initHybrid(jni::alias_ref); + static void registerNatives(); + std::shared_ptr getTurboModule( - const std::string name, - const std::shared_ptr jsInvoker) override; + const std::string &name, + const std::shared_ptr &jsInvoker) override; std::shared_ptr getTurboModule( - const std::string name, + const std::string &name, const JavaTurboModule::InitParams ¶ms) override; + /** * Test-only method. Allows user to verify whether a TurboModule can be * created by instances of this class. */ - bool canCreateTurboModule(std::string name); + bool canCreateTurboModule(const std::string &name); }; + } // namespace react } // namespace facebook diff --git a/android/app/src/main/jni/MainComponentsRegistry.cpp b/android/app/src/main/jni/MainComponentsRegistry.cpp index d62dcb558..54f598a48 100644 --- a/android/app/src/main/jni/MainComponentsRegistry.cpp +++ b/android/app/src/main/jni/MainComponentsRegistry.cpp @@ -1,14 +1,23 @@ #include "MainComponentsRegistry.h" + #include #include #include #include +#include + namespace facebook { namespace react { + MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {} + std::shared_ptr MainComponentsRegistry::sharedProviderRegistry() { auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); + + // Autolinked providers registered by RN CLI + rncli_registerProviders(providerRegistry); + // Custom Fabric Components go here. You can register custom // components coming from your App or from 3rd party libraries here. // @@ -16,11 +25,13 @@ MainComponentsRegistry::sharedProviderRegistry() { // AocViewerComponentDescriptor>()); return providerRegistry; } + jni::local_ref MainComponentsRegistry::initHybrid( jni::alias_ref, ComponentFactory *delegate) { auto instance = makeCxxInstance(delegate); + auto buildRegistryFunction = [](EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) @@ -28,21 +39,27 @@ MainComponentsRegistry::initHybrid( auto registry = MainComponentsRegistry::sharedProviderRegistry() ->createComponentDescriptorRegistry( {eventDispatcher, contextContainer}); + auto mutableRegistry = std::const_pointer_cast(registry); + mutableRegistry->setFallbackComponentDescriptor( std::make_shared( ComponentDescriptorParameters{ eventDispatcher, contextContainer, nullptr})); + return registry; }; + delegate->buildRegistryFunction = buildRegistryFunction; return instance; } + void MainComponentsRegistry::registerNatives() { registerHybrid({ makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid), }); } + } // namespace react } // namespace facebook diff --git a/android/app/src/main/jni/MainComponentsRegistry.h b/android/app/src/main/jni/MainComponentsRegistry.h index 425ee7471..979f971d5 100644 --- a/android/app/src/main/jni/MainComponentsRegistry.h +++ b/android/app/src/main/jni/MainComponentsRegistry.h @@ -1,24 +1,32 @@ #pragma once + #include #include #include #include + namespace facebook { namespace react { + class MainComponentsRegistry : public facebook::jni::HybridClass { public: // Adapt it to the package you used for your Java class. constexpr static auto kJavaDescriptor = - "Lcom/lxmusicmobile/newarchitecture/components/MainComponentsRegistry;"; + "Lcn/toside/music/mobile/newarchitecture/components/MainComponentsRegistry;"; + static void registerNatives(); + MainComponentsRegistry(ComponentFactory *delegate); + private: static std::shared_ptr sharedProviderRegistry(); + static jni::local_ref initHybrid( jni::alias_ref, ComponentFactory *delegate); }; + } // namespace react } // namespace facebook diff --git a/android/app/src/main/jni/OnLoad.cpp b/android/app/src/main/jni/OnLoad.cpp index ddd99a4c4..c569b6e86 100644 --- a/android/app/src/main/jni/OnLoad.cpp +++ b/android/app/src/main/jni/OnLoad.cpp @@ -1,6 +1,7 @@ #include #include "MainApplicationTurboModuleManagerDelegate.h" #include "MainComponentsRegistry.h" + JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { return facebook::jni::initialize(vm, [] { facebook::react::MainApplicationTurboModuleManagerDelegate:: diff --git a/android/app/src/main/res/layout/launch_screen.xml b/android/app/src/main/res/layout/launch_screen.xml deleted file mode 100644 index 4e32f5e43..000000000 --- a/android/app/src/main/res/layout/launch_screen.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - diff --git a/android/app/src/main/res/values-v29/styles.xml b/android/app/src/main/res/values-v29/styles.xml deleted file mode 100644 index 5c4a13b4b..000000000 --- a/android/app/src/main/res/values-v29/styles.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml deleted file mode 100644 index 041821fcd..000000000 --- a/android/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - #000000 - diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index 9e2622538..7ba83a2ad 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -6,10 +6,4 @@ @drawable/rn_edit_text_material - - diff --git a/android/build.gradle b/android/build.gradle index 74d5bfea8..9554c2556 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,15 +1,13 @@ -import org.apache.tools.ant.taskdefs.condition.Os - // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { ext { - buildToolsVersion = "31.0.0" + buildToolsVersion = "33.0.0" minSdkVersion = 21 - compileSdkVersion = 30 - // https://github.com/itinance/react-native-fs/issues/998#issuecomment-831337442 + compileSdkVersion = 33 targetSdkVersion = 29 - kotlinVersion = "1.5.31" // Or any version above 1.3.x + + kotlinVersion = "1.6.10" // Or any version above 1.3.x RNNKotlinVersion = kotlinVersion if (System.properties['os.arch'] == "aarch64") { @@ -19,16 +17,15 @@ buildscript { // Otherwise we default to the side-by-side NDK version from AGP. ndkVersion = "21.4.7075529" } - } repositories { google() mavenCentral() } dependencies { - classpath("com.android.tools.build:gradle:7.0.4") + classpath("com.android.tools.build:gradle:7.2.1") classpath("com.facebook.react:react-native-gradle-plugin") - classpath("de.undercouch:gradle-download-task:4.1.2") + classpath("de.undercouch:gradle-download-task:5.0.1") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/android/gradle.properties b/android/gradle.properties index eecd6094e..82d47835c 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -31,6 +31,7 @@ FLIPPER_VERSION=0.125.0 # You can also override it from the CLI using # ./gradlew -PreactNativeArchitectures=x86_64 reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + # Use this property to enable support to the new architecture. # This will allow you to use TurboModules and the Fabric render in # your application. You should enable this flag either if you want @@ -44,10 +45,11 @@ newArchEnabled=false # AsyncStorage_dedicatedExecutor = true +# https://react-native-async-storage.github.io/async-storage/docs/advanced/next AsyncStorage_useNextStorage=true -AsyncStorage_kotlinVersion=1.4.32 +AsyncStorage_kotlinVersion=1.6.10 +# https://developer.android.com/jetpack/androidx/releases/room +AsyncStorage_next_roomVersion=2.4.2 # https://github.com/wix/react-native-navigation/issues/7403 # android.jetifier.blacklist = bcprov-jdk15on - -AsyncStorage_next_roomVersion=2.3.0 diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar index 7454180f2..41d9927a4 100644 Binary files a/android/gradle/wrapper/gradle-wrapper.jar and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 669386b87..8fad3f5a9 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/android/settings.gradle b/android/settings.gradle index 71469f118..02ea79bd2 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,12 +1,11 @@ -rootProject.name = 'LxMusicMobile' -include ':react-native-splash-screen' -project(':react-native-splash-screen').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-splash-screen/android') -include ':react-native-vector-icons' -project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') +rootProject.name = 'cn.toside.music.mobile' apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) include ':app' includeBuild('../node_modules/react-native-gradle-plugin') + if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { include(":ReactAndroid") project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') + include(":ReactAndroid:hermes-engine") + project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine') } diff --git a/babel.config.js b/babel.config.js index 16958d574..4670ad1f6 100644 --- a/babel.config.js +++ b/babel.config.js @@ -7,6 +7,12 @@ module.exports = { { root: ['.'], extensions: [ + '.android.ts', + '.ios.ts', + '.android.tsx', + '.ios.tsx', + '.tsx', + '.ts', '.android.js', '.ios.js', '.android.jsx', diff --git a/index.js b/index.js index e34b06df5..0e003f6ad 100644 --- a/index.js +++ b/index.js @@ -1,158 +1,26 @@ /** * @format */ - - -// import '@/utils/log' import './shim' -import '@/utils/errorHandle' -import { init as initLog, log } from '@/utils/log' -import '@/config/globalData' -import SplashScreen from 'react-native-splash-screen' -import { init as initNavigation, navigations, showPactModal } from '@/navigation' -import { registerPlaybackService } from '@/plugins/player' -import { getStore } from '@/store' -import { action as commonAction } from '@/store/modules/common' -import { action as playerAction } from '@/store/modules/player' -import { action as listAction } from '@/store/modules/list' -import { init as initMusicTools } from '@/utils/music' -import { init as initLyric, toggleTranslation, toggleRoma } from '@/utils/lyric' -import { showLyric, onPositionChange } from '@/utils/lyricDesktop' -import { init as initI18n, supportedLngs } from '@/plugins/i18n' -import { deviceLanguage, getPlayInfo, toast, onAppearanceChange, getIsSupportedAutoTheme, getAppearance } from '@/utils/tools' -import { LIST_ID_PLAY_TEMP } from '@/config/constant' -import { connect, SYNC_CODE } from '@/plugins/sync' - -console.log('starting app...') - -let store -let isInited = false -let isFirstRun = true -initLog() - -const init = () => { - if (isInited) return Promise.resolve() - isInited = true - store = getStore() - // console.log('deviceLanguage', deviceLanguage) - return Promise.all([ - store.dispatch(commonAction.initSetting()), - store.dispatch(listAction.initList()), - initLyric(), - registerPlaybackService(), - ]).then(() => { - let setting = store.getState().common.setting - - if (getIsSupportedAutoTheme()) { - onAppearanceChange(color => { - store.dispatch(commonAction.setSystemColor(color)) - }) - } - - toggleTranslation(setting.player.isShowLyricTranslation) - toggleRoma(setting.player.isShowLyricRoma) - if (setting.sync.enable) { - connect().catch(err => { - if (err.message == SYNC_CODE.unknownServiceAddress) { - store.dispatch(commonAction.setIsEnableSync(false)) - } - }) - } - if (setting.desktopLyric.enable) { - showLyric({ - isShowToggleAnima: setting.desktopLyric.showToggleAnima, - isSingleLine: setting.desktopLyric.isSingleLine, - isLock: setting.desktopLyric.isLock, - themeId: setting.desktopLyric.theme, - opacity: setting.desktopLyric.style.opacity, - textSize: setting.desktopLyric.style.fontSize, - width: setting.desktopLyric.width, - maxLineNum: setting.desktopLyric.maxLineNum, - positionX: setting.desktopLyric.position.x, - positionY: setting.desktopLyric.position.y, - textPositionX: setting.desktopLyric.textPosition.x, - textPositionY: setting.desktopLyric.textPosition.y, - }).catch(() => { - store.dispatch(commonAction.setIsShowDesktopLyric(false)) - }) - } - onPositionChange(position => { - store.dispatch(commonAction.setDesktopLyricPosition(position)) - }) - - let lang = setting.langId - let needSetLang = false - if (!supportedLngs.includes(lang)) { - if (typeof deviceLanguage == 'string' && supportedLngs.includes(deviceLanguage)) { - lang = deviceLanguage - } else { - lang = 'en_us' - } - needSetLang = true - } - console.log(lang) - return initI18n(lang).then(() => { - if (needSetLang) return store.dispatch(commonAction.setLang(lang)) - }) - // .catch(_ => _) - // StatusBar.setHidden(false) - // console.log('init') - }).then(() => { - initMusicTools() - getPlayInfo().then(info => { - if (!info) return - if (info.listId != LIST_ID_PLAY_TEMP) { - info.list = global.allList[info.listId] - if (info.list) info.list = info.list.list - } - - if (!info.list || !info.list[info.index]) { - const info2 = { ...info } - if (info2.list) { - info2.music = info2.list[info2.index]?.name - info2.list = info2.list.length - } - toast('恢复播放数据失败,请去错误日志查看', 'long') - log.warn('Restore Play Info failed: ', JSON.stringify(info2, null, 2)) - - return - } - - let setting = store.getState().common.setting - global.restorePlayInfo = { - info, - startupAutoPlay: setting.startupAutoPlay, - } - - store.dispatch(playerAction.setList({ - list: { - list: info.list, - id: info.listId, - }, - index: info.index, - })) - }) - }) -} - -initNavigation(() => { - init().then(() => { - if (getIsSupportedAutoTheme()) store.dispatch(commonAction.setSystemColor(getAppearance())) - - return navigations.pushHomeScreen().then(() => { - SplashScreen.hide() - if (store.getState().common.setting.isAgreePact) { - if (isFirstRun) { - isFirstRun = false - store.dispatch(commonAction.checkVersion()) - } - } else { - if (isFirstRun) isFirstRun = false - showPactModal() - } - }) - }).catch(err => { - toast(err.stack, 'long') - }) -}) - +import './src/app' +// import './test' +// import '@/utils/errorHandle' +// import { Navigation } from 'react-native-navigation' +// import App from './App' + +// Navigation.registerComponent('com.myApp.WelcomeScreen', () => App) +// Navigation.events().registerAppLaunchedListener(() => { +// Navigation.setRoot({ +// root: { +// stack: { +// children: [ +// { +// component: { +// name: 'com.myApp.WelcomeScreen', +// }, +// }, +// ], +// }, +// }, +// }) +// }) diff --git a/ios/.xcode.env b/ios/.xcode.env new file mode 100644 index 000000000..3d5782c71 --- /dev/null +++ b/ios/.xcode.env @@ -0,0 +1,11 @@ +# This `.xcode.env` file is versioned and is used to source the environment +# used when running script phases inside Xcode. +# To customize your local environment, you can create an `.xcode.env.local` +# file that is not versioned. + +# NODE_BINARY variable contains the PATH to the node executable. +# +# Customize the NODE_BINARY variable here. +# For example, to use nvm with brew, add the following line +# . "$(brew --prefix nvm)/nvm.sh" --no-use +export NODE_BINARY=$(command -v node) diff --git a/ios/LxMusicMobile.xcodeproj/project.pbxproj b/ios/LxMusicMobile.xcodeproj/project.pbxproj index 84bdde7bd..0d1859d04 100644 --- a/ios/LxMusicMobile.xcodeproj/project.pbxproj +++ b/ios/LxMusicMobile.xcodeproj/project.pbxproj @@ -256,13 +256,15 @@ files = ( ); inputPaths = ( + "$(SRCROOT)/.xcode.env.local", + "$(SRCROOT)/.xcode.env", ); name = "Bundle React Native code and images"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n"; + shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; }; 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; @@ -436,7 +438,7 @@ "$(inherited)", ); INFOPLIST_FILE = LxMusicMobileTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -460,7 +462,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; INFOPLIST_FILE = LxMusicMobileTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -576,7 +578,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", @@ -640,7 +642,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", diff --git a/ios/LxMusicMobile/AppDelegate.mm b/ios/LxMusicMobile/AppDelegate.mm index 3cfb60de1..efbab261c 100644 --- a/ios/LxMusicMobile/AppDelegate.mm +++ b/ios/LxMusicMobile/AppDelegate.mm @@ -1,8 +1,11 @@ #import "AppDelegate.h" +#import + #import #import -#import + #import + #if RCT_NEW_ARCH_ENABLED #import #import @@ -10,7 +13,11 @@ #import #import #import + #import + +static NSString *const kRNConcurrentRoot = @"concurrentRoot"; + @interface AppDelegate () { RCTTurboModuleManager *_turboModuleManager; RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; @@ -19,11 +26,16 @@ @interface AppDelegate () } @end #endif + @implementation AppDelegate + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { RCTAppSetupPrepareApp(application); + RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; +[ReactNativeNavigation bootstrapWithBridge:bridge]; + #if RCT_NEW_ARCH_ENABLED _contextContainer = std::make_shared(); _reactNativeConfig = std::make_shared(); @@ -31,19 +43,40 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer]; bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; #endif - UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"LxMusicMobile", nil); - if (@available(iOS 13.0, *)) { - rootView.backgroundColor = [UIColor systemBackgroundColor]; - } else { - rootView.backgroundColor = [UIColor whiteColor]; - } - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *rootViewController = [UIViewController new]; - rootViewController.view = rootView; - self.window.rootViewController = rootViewController; - [self.window makeKeyAndVisible]; + + + + + return YES; } + +/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. +/// +/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html +/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). +/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`. +- (BOOL)concurrentRootEnabled +{ + // Switch this bool to turn on and off the concurrent root + return true; +} + +- (NSDictionary *)prepareInitialProps +{ + NSMutableDictionary *initProps = [NSMutableDictionary new]; + +#ifdef RCT_NEW_ARCH_ENABLED + initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]); +#endif + + return initProps; +} + +- (NSArray> *)extraModulesForBridge:(RCTBridge *)bridge { + return [ReactNativeNavigation extraModulesForBridge:bridge]; +} + - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG @@ -52,8 +85,11 @@ - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } + #if RCT_NEW_ARCH_ENABLED + #pragma mark - RCTCxxBridgeDelegate + - (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge { _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge @@ -61,25 +97,32 @@ - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge jsInvoker:bridge.jsCallInvoker]; return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); } + #pragma mark RCTTurboModuleManagerDelegate + - (Class)getModuleClassFromName:(const char *)name { return RCTCoreModulesClassProvider(name); } + - (std::shared_ptr)getTurboModule:(const std::string &)name jsInvoker:(std::shared_ptr)jsInvoker { return nullptr; } + - (std::shared_ptr)getTurboModule:(const std::string &)name initParams: (const facebook::react::ObjCTurboModule::InitParams &)params { return nullptr; } + - (id)getModuleInstanceFromClass:(Class)moduleClass { return RCTAppSetupDefaultModuleFromClass(moduleClass); } + #endif + @end diff --git a/ios/LxMusicMobile/Info.plist b/ios/LxMusicMobile/Info.plist index 1b3f410a2..b8381eb5d 100644 --- a/ios/LxMusicMobile/Info.plist +++ b/ios/LxMusicMobile/Info.plist @@ -50,6 +50,6 @@ UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance - + diff --git a/ios/LxMusicMobileTests/LxMusicMobileTests.m b/ios/LxMusicMobileTests/LxMusicMobileTests.m index 01fc06c3c..a3034d1ce 100644 --- a/ios/LxMusicMobileTests/LxMusicMobileTests.m +++ b/ios/LxMusicMobileTests/LxMusicMobileTests.m @@ -47,12 +47,12 @@ - (void)testRendersWelcomeScreen [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; foundElement = [self findSubviewInView:vc.view - matching:^BOOL(UIView *view) { - if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { - return YES; - } - return NO; - }]; + matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; } #ifdef DEBUG diff --git a/ios/Podfile b/ios/Podfile index 17cc8f14e..4f539afb7 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,7 +1,7 @@ require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' -platform :ios, '11.0' +platform :ios, '12.4' install! 'cocoapods', :deterministic_uuids => false target 'LxMusicMobile' do @@ -10,12 +10,18 @@ target 'LxMusicMobile' do # Flags change depending on the env values. flags = get_default_flags() - use_react_native!( :path => config[:reactNativePath], - # to enable hermes on iOS, change `false` to `true` and then install pods - :hermes_enabled => flags[:hermes_enabled], + # Hermes is now enabled by default. Disable by setting this flag to false. + # Upcoming versions of React Native may rely on get_default_flags(), but + # we make it explicit here to aid in the React Native upgrade process. + :hermes_enabled => true, :fabric_enabled => flags[:fabric_enabled], + # Enables Flipper. + # + # Note that if you have use_frameworks! enabled, Flipper will not work and + # you should disable the next line. + :flipper_configuration => FlipperConfiguration.enabled, # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) @@ -25,14 +31,13 @@ target 'LxMusicMobile' do # Pods for testing end - # Enables Flipper. - # - # Note that if you have use_frameworks! enabled, Flipper will not work and - # you should disable the next line. - use_flipper!() - post_install do |installer| - react_native_post_install(installer) + react_native_post_install( + installer, + # Set `mac_catalyst_enabled` to `true` in order to apply patches + # necessary for Mac Catalyst builds + :mac_catalyst_enabled => false + ) __apply_Xcode_12_5_M1_post_install_workaround(installer) end end diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index 76ec851e1..000000000 --- a/jsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "./", - "paths": { - "@/*": ["src/*"], - // "@config": ["src/config"], - // "@store": ["src/store"], - // "@components": ["src/components"], - // "@navigation": ["src/navigation"], - // "@screens": ["src/screens"], - // "@theme": ["src/theme"], - // "@utils": ["src/utils"], - } - }, - "exclude": ["node_modules"] -} diff --git a/metro.config.js b/metro.config.js index 59103f46a..db38965af 100644 --- a/metro.config.js +++ b/metro.config.js @@ -16,9 +16,9 @@ module.exports = { }, resolver: { extraNodeModules: { - console: require.resolve('console-browserify'), - crypto: require.resolve('react-native-crypto'), + crypto: require.resolve('react-native-quick-crypto'), stream: require.resolve('stream-browserify'), + buffer: require.resolve('@craftzdog/react-native-buffer'), }, }, } diff --git a/package-lock.json b/package-lock.json index 24005977c..6a1193c00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,75 +1,50 @@ { "name": "lx-music-mobile", - "version": "0.15.5", + "version": "1.0.0-beta.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "lx-music-mobile", - "version": "0.15.5", - "hasInstallScript": true, + "version": "1.0.0-beta.1", "license": "Apache-2.0", "dependencies": { + "@craftzdog/react-native-buffer": "^6.0.5", "@react-native-async-storage/async-storage": "^1.17.11", "@react-native-clipboard/clipboard": "^1.11.1", "@react-native-community/checkbox": "^0.5.14", - "@react-native-community/slider": "^4.3.3", - "buffer": "^6.0.3", - "console-browserify": "^1.2.0", - "events": "^3.3.0", - "i18next": "^22.1.5", - "js-htmlencode": "^0.3.0", - "lrc-file-parser": "^2.2.8", + "@react-native-community/slider": "^4.4.2", + "iconv-lite": "^0.6.3", + "lrc-file-parser": "^2.3.0", "pako": "^2.1.0", - "process": "^0.11.10", - "prop-types": "^15.8.1", - "react": "17.0.2", - "react-i18next": "^12.1.1", - "react-native": "0.68.5", + "react": "18.1.0", + "react-native": "0.70.7", "react-native-background-timer": "^2.4.1", - "react-native-crypto": "^2.2.0", "react-native-exception-handler": "^2.10.10", "react-native-fs": "^2.20.0", - "react-native-navigation": "^7.30.3", - "react-native-pager-view": "^6.1.2", - "react-native-randombytes": "^3.6.1", - "react-native-splash-screen": "^3.3.0", - "react-native-track-player": "git+https://github.com/lyswhut/react-native-track-player.git#5fb0bec8694d3783f32a1e4ed1251c163e9842f7", + "react-native-navigation": "^7.32.1", + "react-native-pager-view": "^6.1.4", + "react-native-quick-base64": "^2.0.5", + "react-native-quick-crypto": "^0.5.0", + "react-native-track-player": "github:lyswhut/react-native-track-player#38027954a5ac6e3d92961745e0a9633fc647f47a", "react-native-vector-icons": "^9.2.0", - "react-redux": "^8.0.5", - "readable-stream": "1.0.33", - "redux": "^4.2.0", - "redux-subscriber": "^1.1.0", - "redux-thunk": "^2.4.2", - "reselect": "^4.1.7", - "socket.io": "^4.5.4", - "stream-browserify": "^1.0.0", - "url": "~0.10.1", - "util": "~0.10.3" + "socket.io-client": "^4.6.0" }, "devDependencies": { - "@babel/core": "^7.20.5", - "@babel/eslint-parser": "^7.19.1", + "@babel/core": "^7.20.12", "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/runtime": "^7.20.6", - "babel-jest": "^26.6.3", - "babel-plugin-module-resolver": "^4.1.0", - "changelog-parser": "^2.8.1", - "cross-env": "^7.0.3", - "eslint": "^8.29.0", - "eslint-config-standard": "^17.0.0", - "eslint-plugin-html": "^7.1.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-react": "^7.31.11", + "@babel/runtime": "^7.20.13", + "@tsconfig/react-native": "^2.0.3", + "@types/react": "^18.0.28", + "@types/react-native": "^0.70.11", + "@types/react-native-background-timer": "^2.0.0", + "@types/react-native-vector-icons": "^6.4.13", + "babel-plugin-module-resolver": "^5.0.0", + "eslint-config-standard-with-typescript": "^34.0.0", + "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", - "jest": "^26.6.3", - "metro-react-native-babel-preset": "^0.67.0", - "react-native-clean-project": "^4.0.1", - "react-test-renderer": "17.0.2", - "redux-logger": "^3.0.6", - "rn-nodeify": "^10.3.0" + "metro-react-native-babel-preset": "0.72.3", + "typescript": "^4.9.5" }, "engines": { "node": ">= 16", @@ -77,11 +52,12 @@ } }, "node_modules/@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" @@ -99,32 +75,32 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", - "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", + "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz", - "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==", + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.0", - "@babel/helper-module-transforms": "^7.20.2", - "@babel/helpers": "^7.20.5", - "@babel/parser": "^7.20.5", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", + "json5": "^2.2.2", "semver": "^6.3.0" }, "engines": { @@ -135,60 +111,30 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/eslint-parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", - "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", - "dev": true, + "node_modules/@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", "dependencies": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" }, - "peerDependencies": { - "@babel/core": ">=7.11.0", - "eslint": "^7.5.0 || ^8.0.0" - } - }, - "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, "engines": { - "node": ">=10" + "node": ">=6.9.0" } }, - "node_modules/@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", "dependencies": { - "@babel/types": "^7.20.5", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { - "node": ">=6.9.0" + "node": ">=6.0.0" } }, "node_modules/@babel/helper-annotate-as-pure": { @@ -215,13 +161,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", "dependencies": { - "@babel/compat-data": "^7.20.0", + "@babel/compat-data": "^7.20.5", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", "semver": "^6.3.0" }, "engines": { @@ -231,6 +178,19 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.20.2", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.2.tgz", @@ -267,14 +227,12 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -284,22 +242,6 @@ "@babel/core": "^7.4.0-0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@babel/helper-environment-visitor": { "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", @@ -365,18 +307,18 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", - "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.2" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" @@ -505,13 +447,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", - "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", + "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" @@ -530,66 +472,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -633,7 +519,6 @@ "version": "7.20.1", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz", "integrity": "sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g==", - "peer": true, "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-plugin-utils": "^7.19.0", @@ -696,12 +581,12 @@ } }, "node_modules/@babel/plugin-proposal-export-default-from": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.14.5.tgz", - "integrity": "sha512-T8KZ5abXvKMjF6JcoXjgac3ElmXf0AWzJwi2O/42Jk+HmCky3D9+i1B7NPP1FblyceqTevKeV/9szeikFoaMDg==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.18.10.tgz", + "integrity": "sha512-5H2N3R2aQFxkV4PIBUR/i7PUSwgTZjouJKzI8eKswfIjT0PhvzkPn0t0wIS5zn6maQuvtT0t1oHtMUz61LOuow==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-export-default-from": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-default-from": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -898,18 +783,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", @@ -948,11 +821,11 @@ } }, "node_modules/@babel/plugin-syntax-export-default-from": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.14.5.tgz", - "integrity": "sha512-snWDxjuaPEobRBnhpqEfZ8RMxDbHt8+87fiEioGuE+Uc0xAKgSD8QiuL3lF93hPVQfZFAcYwrrf+H5qUhike3Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.18.6.tgz", + "integrity": "sha512-Kr//z3ujSVNx6E9z9ih5xXXMqK07VVTuqPmqGe6Mss/zW5XPeLZeSDZoP9ab/hT4wPKqAgjl2PnhPrcpk8Seew==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1001,22 +874,11 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1025,11 +887,11 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz", - "integrity": "sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1042,6 +904,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1064,6 +927,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1123,6 +987,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1444,7 +1309,6 @@ "version": "7.19.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.19.0", "@babel/helper-plugin-utils": "^7.19.0" @@ -1471,20 +1335,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-object-assign": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.14.5.tgz", - "integrity": "sha512-lvhjk4UN9xJJYB1mI5KC0/o1D5EcJXdbhVe+4fSk08D6ZN+iuAIs7LJC+71h8av9Ew4+uRq9452v9R93SFmQlQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-object-super": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", @@ -1529,11 +1379,11 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.15.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.15.1.tgz", - "integrity": "sha512-yQZ/i/pUCJAHI/LbtZr413S3VT26qNrEm0M5RRxQJA947/YNYwbZbBaXGDrq6CG5QsZycI1VIP6d7pQaBfP+8Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", + "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1543,15 +1393,15 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.9.tgz", - "integrity": "sha512-30PeETvS+AeD1f58i1OVyoDlVYQhap/K20ZrMjLmmzmC2AYR/G43D4sdJAaDAqCD3MYpSWbmrz3kES158QSLjw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz", + "integrity": "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-jsx": "^7.14.5", - "@babel/types": "^7.14.9" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1561,11 +1411,11 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.14.9.tgz", - "integrity": "sha512-Fqqu0f8zv9W+RyOnx29BX/RlEsBRANbOf5xs5oxb2aHP4FKbLXxIaVPUiCti56LAR1IixMH4EyaixhUsKqoBHw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz", + "integrity": "sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1575,11 +1425,11 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.14.5.tgz", - "integrity": "sha512-1TpSDnD9XR/rQ2tzunBVPThF5poaYT9GqP+of8fAtguYuI/dm2RkrMBDemsxtY0XBzvW7nXjYM0hRyKX9QYj7Q==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz", + "integrity": "sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1592,6 +1442,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "regenerator-transform": "^0.15.0" @@ -1619,15 +1470,15 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz", - "integrity": "sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw==", - "dependencies": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", - "babel-plugin-polyfill-regenerator": "^0.2.2", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", "semver": "^6.3.0" }, "engines": { @@ -1844,122 +1695,49 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "peer": true, + "node_modules/@babel/preset-flow": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.18.6.tgz", + "integrity": "sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ==", "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-flow-strip-types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.4.0-0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "peer": true, "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "peer": true, + "node_modules/@babel/preset-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", + "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "peer": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "peer": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/preset-flow": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.18.6.tgz", - "integrity": "sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-flow-strip-types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", - "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-typescript": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-typescript": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -1984,9 +1762,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz", - "integrity": "sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -1995,31 +1773,31 @@ } }, "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", + "@babel/generator": "^7.20.7", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2027,26 +1805,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -2056,26 +1818,27 @@ "node": ">=6.9.0" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "dev": true, + "node_modules/@craftzdog/react-native-buffer": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@craftzdog/react-native-buffer/-/react-native-buffer-6.0.5.tgz", + "integrity": "sha512-Av+YqfwA9e7jhgI9GFE/gTpwl/H+dRRLmZyJPOpKTy107j9Oj7oXlm3/YiMNz+C/CEGqcKAOqnXDLs4OL6AAFw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - }, - "bin": { - "watch": "cli.js" - }, - "engines": { - "node": ">=0.1.95" + "ieee754": "^1.2.1", + "react-native-quick-base64": "^2.0.5" } }, "node_modules/@eslint/eslintrc": { @@ -2083,6 +1846,7 @@ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", "dev": true, + "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -2101,34 +1865,12 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.17.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, + "peer": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -2139,48 +1881,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "peer": true, "engines": { "node": ">=10" }, @@ -2189,9 +1895,9 @@ } }, "node_modules/@hapi/hoek": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", - "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==" + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" }, "node_modules/@hapi/topo": { "version": "5.1.0", @@ -2202,41 +1908,26 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.6", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.6.tgz", - "integrity": "sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==", + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", + "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", "dev": true, + "peer": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "peer": true, "engines": { "node": ">=12.22" }, @@ -2249,403 +1940,115 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "peer": true + }, + "node_modules/@jest/create-cache-key-function": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz", + "integrity": "sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==", "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "@jest/types": "^27.5.1" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, + "node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", - "dev": true, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 10.14.2" + "node": ">=7.0.0" } }, - "node_modules/@jest/core/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/@jest/core/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, - "node_modules/@jest/create-cache-key-function": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz", - "integrity": "sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==", - "dependencies": { - "@jest/types": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" - }, - "engines": { - "node": ">= 10.14.2" - }, - "optionalDependencies": { - "node-notifier": "^8.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/source-map/node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@jest/source-map/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/transform/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@jest/transform/node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "engines": { "node": ">=6.0.0" } @@ -2659,26 +2062,17 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", - "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", - "dev": true, + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dependencies": { - "eslint-scope": "5.1.1" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "node_modules/@nodelib/fs.scandir": { @@ -2752,2399 +2146,1366 @@ } }, "node_modules/@react-native-community/cli": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-7.0.3.tgz", - "integrity": "sha512-WyJOA829KAhU1pw2MDQt0YhOS9kyR2KqyqgJyTuQhzFVCBPX4F5aDEkZYYn4jdldaDHCPrLJ3ho3gxYTXy+x7w==", - "dependencies": { - "@react-native-community/cli-debugger-ui": "^7.0.3", - "@react-native-community/cli-hermes": "^6.3.0", - "@react-native-community/cli-plugin-metro": "^7.0.3", - "@react-native-community/cli-server-api": "^7.0.3", - "@react-native-community/cli-tools": "^6.2.0", - "@react-native-community/cli-types": "^6.0.0", - "appdirsjs": "^1.2.4", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-9.3.2.tgz", + "integrity": "sha512-IAW4X0vmX/xozNpp/JVZaX7MrC85KV0OP2DF4o7lNGOfpUhzJAEWqTfkxFYS+VsRjZHDve4wSTiGIuXwE7FG1w==", + "dependencies": { + "@react-native-community/cli-clean": "^9.2.1", + "@react-native-community/cli-config": "^9.2.1", + "@react-native-community/cli-debugger-ui": "^9.0.0", + "@react-native-community/cli-doctor": "^9.3.0", + "@react-native-community/cli-hermes": "^9.3.1", + "@react-native-community/cli-plugin-metro": "^9.2.1", + "@react-native-community/cli-server-api": "^9.2.1", + "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-types": "^9.1.0", "chalk": "^4.1.2", - "command-exists": "^1.2.8", - "commander": "^2.19.0", - "cosmiconfig": "^5.1.0", - "deepmerge": "^3.2.0", - "envinfo": "^7.7.2", + "commander": "^9.4.0", "execa": "^1.0.0", "find-up": "^4.1.0", "fs-extra": "^8.1.0", - "glob": "^7.1.3", "graceful-fs": "^4.1.3", - "joi": "^17.2.1", - "leven": "^3.1.0", - "lodash": "^4.17.15", - "minimist": "^1.2.0", - "node-stream-zip": "^1.9.1", - "ora": "^3.4.0", - "pretty-format": "^26.6.2", "prompts": "^2.4.0", - "semver": "^6.3.0", - "serve-static": "^1.13.1", - "strip-ansi": "^5.2.0", - "sudo-prompt": "^9.0.0", - "wcwidth": "^1.0.1" + "semver": "^6.3.0" }, "bin": { "react-native": "build/bin.js" }, "engines": { - "node": ">=12" - }, - "peerDependencies": { - "react-native": "*" + "node": ">=14" } }, - "node_modules/@react-native-community/cli-debugger-ui": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-7.0.3.tgz", - "integrity": "sha512-G4SA6jFI0j22o+j+kYP8/7sxzbCDqSp2QiHA/X5E0lsGEd2o9qN2zbIjiFr8b8k+VVAYSUONhoC0+uKuINvmkA==", + "node_modules/@react-native-community/cli-clean": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-9.2.1.tgz", + "integrity": "sha512-dyNWFrqRe31UEvNO+OFWmQ4hmqA07bR9Ief/6NnGwx67IO9q83D5PEAf/o96ML6jhSbDwCmpPKhPwwBbsyM3mQ==", "dependencies": { - "serve-static": "^1.13.1" + "@react-native-community/cli-tools": "^9.2.1", + "chalk": "^4.1.2", + "execa": "^1.0.0", + "prompts": "^2.4.0" } }, - "node_modules/@react-native-community/cli-hermes": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-6.3.0.tgz", - "integrity": "sha512-Uhbm9bubyZLZ12vFCIfWbE/Qi3SBTbYIN/TC08EudTLhv/KbPomCQnmFsnJ7AXQFuOZJs73mBxoEAYSbRbwyVA==", + "node_modules/@react-native-community/cli-clean/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "@react-native-community/cli-platform-android": "^6.3.0", - "@react-native-community/cli-tools": "^6.2.0", - "chalk": "^4.1.2", - "hermes-profile-transformer": "^0.0.6", - "ip": "^1.1.5" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@react-native-community/cli-hermes/node_modules/@react-native-community/cli-platform-android": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-6.3.0.tgz", - "integrity": "sha512-d5ufyYcvrZoHznYm5bjBXaiHIJv552t5gYtQpnUsxBhHSQ8QlaNmlLUyeSPRDfOw4ND9b0tPHqs4ufwx6vp/fQ==", + "node_modules/@react-native-community/cli-clean/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "@react-native-community/cli-tools": "^6.2.0", - "chalk": "^4.1.2", - "execa": "^1.0.0", - "fs-extra": "^8.1.0", - "glob": "^7.1.3", - "jetifier": "^1.6.2", - "lodash": "^4.17.15", - "logkitty": "^0.7.1", - "slash": "^3.0.0", - "xmldoc": "^1.1.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@react-native-community/cli-platform-android": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-7.0.1.tgz", - "integrity": "sha512-nOr0aMkxAymCnbtsQwXBlyoRN2Y+IzC7Qz5T+/zyWwEbTY8SKQI8uV+8+qttUvzSvuXa2PeXsTWluuliOS8KCw==", + "node_modules/@react-native-community/cli-clean/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "@react-native-community/cli-tools": "^7.0.1", - "chalk": "^4.1.2", - "execa": "^1.0.0", - "fs-extra": "^8.1.0", - "glob": "^7.1.3", - "jetifier": "^1.6.2", - "lodash": "^4.17.15", - "logkitty": "^0.7.1", - "slash": "^3.0.0", - "xmldoc": "^1.1.2" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@react-native-community/cli-platform-android/node_modules/@react-native-community/cli-tools": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-7.0.1.tgz", - "integrity": "sha512-0xra4hKNA5PR2zYVXsDMNiXMGaDNoNRYMY6eTP2aVIxQbqIcVMDWSyCA8wMWX5iOpMWg0cZGaQ6a77f3Rlb34g==", - "dependencies": { - "appdirsjs": "^1.2.4", - "chalk": "^4.1.2", - "lodash": "^4.17.15", - "mime": "^2.4.1", - "node-fetch": "^2.6.0", - "open": "^6.2.0", - "ora": "^5.4.1", - "semver": "^6.3.0", - "shell-quote": "^1.7.3" - } + "node_modules/@react-native-community/cli-clean/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/@react-native-community/cli-platform-android/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@react-native-community/cli-clean/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, - "node_modules/@react-native-community/cli-platform-android/node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "node_modules/@react-native-community/cli-clean/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "restore-cursor": "^3.1.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/@react-native-community/cli-platform-android/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "node_modules/@react-native-community/cli-config": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-9.2.1.tgz", + "integrity": "sha512-gHJlBBXUgDN9vrr3aWkRqnYrPXZLztBDQoY97Mm5Yo6MidsEpYo2JIP6FH4N/N2p1TdjxJL4EFtdd/mBpiR2MQ==", "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@react-native-community/cli-tools": "^9.2.1", + "cosmiconfig": "^5.1.0", + "deepmerge": "^3.2.0", + "glob": "^7.1.3", + "joi": "^17.2.1" } }, - "node_modules/@react-native-community/cli-platform-android/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/@react-native-community/cli-debugger-ui": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-9.0.0.tgz", + "integrity": "sha512-7hH05ZwU9Tp0yS6xJW0bqcZPVt0YCK7gwj7gnRu1jDNN2kughf6Lg0Ys29rAvtZ7VO1PK5c1O+zs7yFnylQDUA==", + "dependencies": { + "serve-static": "^1.13.1" + } + }, + "node_modules/@react-native-community/cli-doctor": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-9.3.0.tgz", + "integrity": "sha512-/fiuG2eDGC2/OrXMOWI5ifq4X1gdYTQhvW2m0TT5Lk1LuFiZsbTCp1lR+XILKekuTvmYNjEGdVpeDpdIWlXdEA==", + "dependencies": { + "@react-native-community/cli-config": "^9.2.1", + "@react-native-community/cli-platform-ios": "^9.3.0", + "@react-native-community/cli-tools": "^9.2.1", + "chalk": "^4.1.2", + "command-exists": "^1.2.8", + "envinfo": "^7.7.2", + "execa": "^1.0.0", + "hermes-profile-transformer": "^0.0.6", + "ip": "^1.1.5", + "node-stream-zip": "^1.9.1", + "ora": "^5.4.1", + "prompts": "^2.4.0", + "semver": "^6.3.0", + "strip-ansi": "^5.2.0", + "sudo-prompt": "^9.0.0", + "wcwidth": "^1.0.1" + } + }, + "node_modules/@react-native-community/cli-doctor/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "engines": { "node": ">=6" } }, - "node_modules/@react-native-community/cli-platform-android/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/@react-native-community/cli-doctor/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "mimic-fn": "^2.1.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@react-native-community/cli-platform-android/node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "node_modules/@react-native-community/cli-doctor/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "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" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@react-native-community/cli-platform-android/node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "node_modules/@react-native-community/cli-doctor/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8" + "node": ">=7.0.0" } }, - "node_modules/@react-native-community/cli-platform-android/node_modules/shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" + "node_modules/@react-native-community/cli-doctor/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/@react-native-community/cli-platform-android/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "node_modules/@react-native-community/cli-doctor/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, - "node_modules/@react-native-community/cli-platform-ios": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-7.0.1.tgz", - "integrity": "sha512-PLRIbzrCzSedmpjuFtQqcqUD45G8q7sEciI1lf5zUbVMXqjIBwJWS7iz8235PyWwj8J4MNHohLC+oyRueFtbGg==", - "dependencies": { - "@react-native-community/cli-tools": "^7.0.1", - "chalk": "^4.1.2", - "execa": "^1.0.0", - "glob": "^7.1.3", - "js-yaml": "^3.13.1", - "lodash": "^4.17.15", - "ora": "^5.4.1", - "plist": "^3.0.2", - "xcode": "^3.0.0" - } - }, - "node_modules/@react-native-community/cli-platform-ios/node_modules/@react-native-community/cli-tools": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-7.0.1.tgz", - "integrity": "sha512-0xra4hKNA5PR2zYVXsDMNiXMGaDNoNRYMY6eTP2aVIxQbqIcVMDWSyCA8wMWX5iOpMWg0cZGaQ6a77f3Rlb34g==", + "node_modules/@react-native-community/cli-doctor/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dependencies": { - "appdirsjs": "^1.2.4", - "chalk": "^4.1.2", - "lodash": "^4.17.15", - "mime": "^2.4.1", - "node-fetch": "^2.6.0", - "open": "^6.2.0", - "ora": "^5.4.1", - "semver": "^6.3.0", - "shell-quote": "^1.7.3" - } - }, - "node_modules/@react-native-community/cli-platform-ios/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "ansi-regex": "^4.1.0" + }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/@react-native-community/cli-platform-ios/node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "node_modules/@react-native-community/cli-doctor/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "restore-cursor": "^3.1.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/@react-native-community/cli-platform-ios/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "node_modules/@react-native-community/cli-hermes": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-9.3.1.tgz", + "integrity": "sha512-Mq4PK8m5YqIdaVq5IdRfp4qK09aVO+aiCtd6vjzjNUgk1+1X5cgUqV6L65h4N+TFJYJHcp2AnB+ik1FAYXvYPQ==", "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@react-native-community/cli-platform-ios/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "engines": { - "node": ">=6" + "@react-native-community/cli-platform-android": "^9.3.1", + "@react-native-community/cli-tools": "^9.2.1", + "chalk": "^4.1.2", + "hermes-profile-transformer": "^0.0.6", + "ip": "^1.1.5" } }, - "node_modules/@react-native-community/cli-platform-ios/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/@react-native-community/cli-hermes/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "mimic-fn": "^2.1.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@react-native-community/cli-platform-ios/node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "node_modules/@react-native-community/cli-hermes/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "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" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@react-native-community/cli-platform-ios/node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "node_modules/@react-native-community/cli-hermes/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8" + "node": ">=7.0.0" } }, - "node_modules/@react-native-community/cli-platform-ios/node_modules/shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" + "node_modules/@react-native-community/cli-hermes/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/@react-native-community/cli-platform-ios/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/@react-native-community/cli-hermes/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native-community/cli-hermes/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "ansi-regex": "^5.0.1" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/@react-native-community/cli-plugin-metro": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-7.0.3.tgz", - "integrity": "sha512-HJrEkFbxv9DNixsGwO+Q0zCcZMghDltyzeB9yQ//D5ZR4ZUEuAIPrRDdEp9xVw0WkBxAIZs6KXLux2/yPMwLhA==", + "node_modules/@react-native-community/cli-platform-android": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-9.3.1.tgz", + "integrity": "sha512-m0bQ6Twewl7OEZoVf79I2GZmsDqh+Gh0bxfxWgwxobsKDxLx8/RNItAo1lVtTCgzuCR75cX4EEO8idIF9jYhew==", "dependencies": { - "@react-native-community/cli-server-api": "^7.0.3", - "@react-native-community/cli-tools": "^6.2.0", + "@react-native-community/cli-tools": "^9.2.1", "chalk": "^4.1.2", - "metro": "^0.67.0", - "metro-config": "^0.67.0", - "metro-core": "^0.67.0", - "metro-react-native-babel-transformer": "^0.67.0", - "metro-resolver": "^0.67.0", - "metro-runtime": "^0.67.0", - "readline": "^1.3.0" + "execa": "^1.0.0", + "fs-extra": "^8.1.0", + "glob": "^7.1.3", + "logkitty": "^0.7.1", + "slash": "^3.0.0" } }, - "node_modules/@react-native-community/cli-server-api": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-7.0.3.tgz", - "integrity": "sha512-JDrLsrkBgNxbG2u3fouoVGL9tKrXUrTsaNwr+oCV+3XyMwbVe42r/OaQ681/iW/7mHXjuVkDnMcp7BMg7e2yJg==", + "node_modules/@react-native-community/cli-platform-android/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "@react-native-community/cli-debugger-ui": "^7.0.3", - "@react-native-community/cli-tools": "^6.2.0", - "compression": "^1.7.1", - "connect": "^3.6.5", - "errorhandler": "^1.5.0", - "nocache": "^2.1.0", - "pretty-format": "^26.6.2", - "serve-static": "^1.13.1", - "ws": "^7.5.1" - } - }, - "node_modules/@react-native-community/cli-server-api/node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "engines": { - "node": ">=8.3.0" + "color-convert": "^2.0.1" }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "engines": { + "node": ">=8" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@react-native-community/cli-tools": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-6.2.0.tgz", - "integrity": "sha512-08ssz4GMEnRxC/1FgTTN/Ud7mExQi5xMphItPjfHiTxpZPhrFn+IMx6mya0ncFEhhxQ207wYlJMRLPRRdBZ8oA==", + "node_modules/@react-native-community/cli-platform-android/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "appdirsjs": "^1.2.4", - "chalk": "^4.1.2", - "lodash": "^4.17.15", - "mime": "^2.4.1", - "node-fetch": "^2.6.0", - "open": "^6.2.0", - "semver": "^6.3.0", - "shell-quote": "1.6.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@react-native-community/cli-types": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-6.0.0.tgz", - "integrity": "sha512-K493Fk2DMJC0ZM8s8gnfseKxGasIhuDaCUDeLZcoCSFlrjKEuEs1BKKEJiev0CARhKEXKOyyp/uqYM9nWhisNw==", + "node_modules/@react-native-community/cli-platform-android/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "ora": "^3.4.0" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@react-native-community/slider": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-4.3.3.tgz", - "integrity": "sha512-eVhMaVR08wWlseVWlDS7zgdhbVY0n2i7BF1qRxK+2N1VIKd7NsTIRzL57sFLgHVjbUmu/+hHfxCzLHmEaGxIQg==" - }, - "node_modules/@react-native/assets": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@react-native/assets/-/assets-1.0.0.tgz", - "integrity": "sha512-KrwSpS1tKI70wuKl68DwJZYEvXktDHdZMG0k2AXD/rJVSlB23/X2CB2cutVR0HwNMJIal9HOUOBB2rVfa6UGtQ==" - }, - "node_modules/@react-native/normalize-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.0.0.tgz", - "integrity": "sha512-Wip/xsc5lw8vsBlmY2MO/gFLp3MvuZ2baBZjDeTjjndMgM0h5sxz7AZR62RDPGgstp8Np7JzjvVqVT7tpFZqsw==" + "node_modules/@react-native-community/cli-platform-android/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/@react-native/polyfills": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-native/polyfills/-/polyfills-2.0.0.tgz", - "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==" + "node_modules/@react-native-community/cli-platform-android/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } }, - "node_modules/@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "node_modules/@react-native-community/cli-platform-android/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "@hapi/hoek": "^9.0.0" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, + "node_modules/@react-native-community/cli-platform-ios": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-9.3.0.tgz", + "integrity": "sha512-nihTX53BhF2Q8p4B67oG3RGe1XwggoGBrMb6vXdcu2aN0WeXJOXdBLgR900DAA1O8g7oy1Sudu6we+JsVTKnjw==", "dependencies": { - "type-detect": "4.0.8" + "@react-native-community/cli-tools": "^9.2.1", + "chalk": "^4.1.2", + "execa": "^1.0.0", + "glob": "^7.1.3", + "ora": "^5.4.1" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, + "node_modules/@react-native-community/cli-platform-ios/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "@sinonjs/commons": "^1.7.0" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, + "node_modules/@react-native-community/cli-platform-ios/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">= 6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@types/babel__core": { - "version": "7.1.14", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", - "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", - "dev": true, + "node_modules/@react-native-community/cli-platform-ios/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" + "node_modules/@react-native-community/cli-platform-ios/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@react-native-community/cli-platform-ios/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" } }, - "node_modules/@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", - "dev": true, + "node_modules/@react-native-community/cli-platform-ios/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@types/babel__traverse": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", - "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", - "dev": true, + "node_modules/@react-native-community/cli-plugin-metro": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-9.2.1.tgz", + "integrity": "sha512-byBGBH6jDfUvcHGFA45W/sDwMlliv7flJ8Ns9foCh3VsIeYYPoDjjK7SawE9cPqRdMAD4SY7EVwqJnOtRbwLiQ==", "dependencies": { - "@babel/types": "^7.3.0" + "@react-native-community/cli-server-api": "^9.2.1", + "@react-native-community/cli-tools": "^9.2.1", + "chalk": "^4.1.2", + "metro": "0.72.3", + "metro-config": "0.72.3", + "metro-core": "0.72.3", + "metro-react-native-babel-transformer": "0.72.3", + "metro-resolver": "0.72.3", + "metro-runtime": "0.72.3", + "readline": "^1.3.0" } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" - }, - "node_modules/@types/cors": { - "version": "2.8.13", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", - "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "node_modules/@react-native-community/cli-plugin-metro/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "@types/node": "*" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "node_modules/@react-native-community/cli-plugin-metro/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "@types/node": "*" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "node_modules/@react-native-community/cli-plugin-metro/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==" + "node_modules/@react-native-community/cli-plugin-metro/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dependencies": { - "@types/istanbul-lib-coverage": "*" + "node_modules/@react-native-community/cli-plugin-metro/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "node_modules/@react-native-community/cli-plugin-metro/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "@types/istanbul-lib-report": "*" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "node_modules/@types/node": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", - "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", - "dev": true - }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "node_modules/@types/react": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.5.tgz", - "integrity": "sha512-UPxNGInDCIKlfqBrm8LDXYWNfLHwIdisWcsH5GpMyGjhEDLFgTtlRBaoWuCua9HcyuE0rMkmAeZ3FXV1pYLIYQ==", + "node_modules/@react-native-community/cli-server-api": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-9.2.1.tgz", + "integrity": "sha512-EI+9MUxEbWBQhWw2PkhejXfkcRqPl+58+whlXJvKHiiUd7oVbewFs0uLW0yZffUutt4FGx6Uh88JWEgwOzAdkw==", "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" + "@react-native-community/cli-debugger-ui": "^9.0.0", + "@react-native-community/cli-tools": "^9.2.1", + "compression": "^1.7.1", + "connect": "^3.6.5", + "errorhandler": "^1.5.0", + "nocache": "^3.0.1", + "pretty-format": "^26.6.2", + "serve-static": "^1.13.1", + "ws": "^7.5.1" } }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + "node_modules/@react-native-community/cli-server-api/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } }, - "node_modules/@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "node_modules/@react-native-community/cli-tools": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-9.2.1.tgz", + "integrity": "sha512-bHmL/wrKmBphz25eMtoJQgwwmeCylbPxqFJnFSbkqJPXQz3ManQ6q/gVVMqFyz7D3v+riaus/VXz3sEDa97uiQ==", "dependencies": { - "@types/yargs-parser": "*" + "appdirsjs": "^1.2.4", + "chalk": "^4.1.2", + "find-up": "^5.0.0", + "mime": "^2.4.1", + "node-fetch": "^2.6.0", + "open": "^6.2.0", + "ora": "^5.4.1", + "semver": "^6.3.0", + "shell-quote": "^1.7.3" } }, - "node_modules/@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" - }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "node_modules/@react-native-community/cli-tools/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "event-target-shim": "^5.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=6.5" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/absolute-path": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz", - "integrity": "sha1-p4di+9rftSl76ZsV01p4Wy8JW/c=" - }, - "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "node_modules/@react-native-community/cli-tools/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 0.6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" + "node_modules/@react-native-community/cli-tools/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.4.0" + "node": ">=7.0.0" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } + "node_modules/@react-native-community/cli-tools/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node_modules/@react-native-community/cli-tools/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" } }, - "node_modules/acorn-walk": { + "node_modules/@react-native-community/cli-tools/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, + "node_modules/@react-native-community/cli-types": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-9.1.0.tgz", + "integrity": "sha512-KDybF9XHvafLEILsbiKwz5Iobd+gxRaPyn4zSaAerBxedug4er5VUWa8Szy+2GeYKZzMh/gsb1o9lCToUwdT/g==", + "dependencies": { + "joi": "^17.2.1" + } + }, + "node_modules/@react-native-community/cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "debug": "4" + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 6.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/agent-base/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, + "node_modules/@react-native-community/cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "ms": "2.1.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=6.0" + "node": ">=10" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, + "node_modules/@react-native-community/cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "color-name": "~1.1.4" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=7.0.0" } }, - "node_modules/anser": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", - "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==" + "node_modules/@react-native-community/cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, + "node_modules/@react-native-community/cli/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dependencies": { - "type-fest": "^0.21.3" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, + "node_modules/@react-native-community/cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/ansi-fragments": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansi-fragments/-/ansi-fragments-0.2.1.tgz", - "integrity": "sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==", + "node_modules/@react-native-community/cli/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dependencies": { - "colorette": "^1.0.7", - "slice-ansi": "^2.0.0", - "strip-ansi": "^5.0.0" - } - }, - "node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "p-locate": "^4.1.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@react-native-community/cli/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dependencies": { - "color-convert": "^2.0.1" + "p-try": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=6" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "node_modules/@react-native-community/cli/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "p-limit": "^2.2.0" }, "engines": { - "node": ">= 8" + "node": ">=8" } }, - "node_modules/appdirsjs": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.6.tgz", - "integrity": "sha512-D8wJNkqMCeQs3kLasatELsddox/Xqkhp+J07iXGyL54fVN7oc+nmNfYzGuCs1IEP6uBw+TfpuO3JKwc+lECy4w==" - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/arr-diff": { + "node_modules/@react-native-community/cli/node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "node_modules/@react-native-community/cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "engines": { - "node": ">=0.10.0" - } + "node_modules/@react-native-community/slider": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-4.4.2.tgz", + "integrity": "sha512-D9bv+3Vd2gairAhnRPAghwccgEmoM7g562pm8i4qB3Esrms5mggF81G3UvCyc0w3jjtFHh8dpQkfEoKiP0NW/Q==" }, - "node_modules/array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=" + "node_modules/@react-native/assets": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@react-native/assets/-/assets-1.0.0.tgz", + "integrity": "sha512-KrwSpS1tKI70wuKl68DwJZYEvXktDHdZMG0k2AXD/rJVSlB23/X2CB2cutVR0HwNMJIal9HOUOBB2rVfa6UGtQ==" }, - "node_modules/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "dev": true, + "node_modules/@react-native/normalize-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.0.0.tgz", + "integrity": "sha512-Wip/xsc5lw8vsBlmY2MO/gFLp3MvuZ2baBZjDeTjjndMgM0h5sxz7AZR62RDPGgstp8Np7JzjvVqVT7tpFZqsw==" + }, + "node_modules/@react-native/polyfills": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-native/polyfills/-/polyfills-2.0.0.tgz", + "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==" + }, + "node_modules/@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@hapi/hoek": "^9.0.0" } }, - "node_modules/array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=" + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" }, - "node_modules/array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=" + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "engines": { - "node": ">=0.10.0" - } + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, - "node_modules/array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", - "dev": true, + "node_modules/@tsconfig/react-native": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/react-native/-/react-native-2.0.3.tgz", + "integrity": "sha512-jE58snEKBd9DXfyR4+ssZmYJ/W2mOSnNrvljR0aLyQJL9JKX6vlWELHkRjb3HBbcM9Uy0hZGijXbqEAjOERW2A==", + "dev": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@types/istanbul-lib-coverage": "*" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "dev": true, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@types/istanbul-lib-report": "*" } }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", - "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" - } + "peer": true }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "peer": true }, - "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } + "node_modules/@types/node": { + "version": "18.11.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz", + "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==" }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "dev": true }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "engines": { - "node": ">=0.10.0" + "node_modules/@types/react": { + "version": "18.0.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", + "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" } }, - "node_modules/ast-types": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", - "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "node_modules/@types/react-native": { + "version": "0.70.11", + "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.70.11.tgz", + "integrity": "sha512-FobPtzoNPNHugBKMfzs4Li0Q9ei4tgU8SI1M5Ayg7+t5/+noCm2sknI8uwij22wMkcHcefv8RFx4q28nNVJtCQ==", + "dev": true, "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" + "@types/react": "*" } }, - "node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "engines": { - "node": ">=4" - } + "node_modules/@types/react-native-background-timer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/react-native-background-timer/-/react-native-background-timer-2.0.0.tgz", + "integrity": "sha512-y5VW82dL/ESOLg+5QQHyBdsFVA4ZklENxmOyxv8o06T+3HBG2JOSuz/CIPz1vKdB7dmWDGPZNuPosdtnp+xv2A==", + "dev": true }, - "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "node_modules/@types/react-native-vector-icons": { + "version": "6.4.13", + "resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.13.tgz", + "integrity": "sha512-1PqFoKuXTSzMHwGMAr+REdYJBQAbe9xrww3ecZR0FsHcD1K+vGS/rxuAriL4rsI6+p69sZQjDzpEVAbDQcjSwA==", + "dev": true, "dependencies": { - "lodash": "^4.17.14" + "@types/react": "*", + "@types/react-native": "^0.70" } }, - "node_modules/async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", "dev": true }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true, + "peer": true }, - "node_modules/babel-core": { - "version": "7.0.0-bridge.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", - "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node_modules/@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dependencies": { + "@types/yargs-parser": "*" } }, - "node_modules/babel-jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz", + "integrity": "sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==", "dev": true, + "peer": true, "dependencies": { - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/type-utils": "5.51.0", + "@typescript-eslint/utils": "5.51.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, + "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "node_modules/@typescript-eslint/parser": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz", + "integrity": "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==", "dev": true, "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/typescript-estree": "5.51.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 10.14.2" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/babel-plugin-module-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz", - "integrity": "sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz", + "integrity": "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==", "dev": true, "dependencies": { - "find-babel-config": "^1.2.0", - "glob": "^7.1.6", - "pkg-up": "^3.1.0", - "reselect": "^4.0.0", - "resolve": "^1.13.1" + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.0" }, "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", - "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", - "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.2.2", - "semver": "^6.1.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.4.tgz", - "integrity": "sha512-z3HnJE5TY/j4EFEa/qpQMSbcUJZ5JQi+3UFjXzn6pQCmIKc5Ug5j98SuYyH+m4xQnvKlMDIW4plLfgyVnd0IcQ==", + "node_modules/@typescript-eslint/type-utils": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz", + "integrity": "sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==", + "dev": true, + "peer": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.14.0" + "@typescript-eslint/typescript-estree": "5.51.0", + "@typescript-eslint/utils": "5.51.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz", - "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.2.2" + "node_modules/@typescript-eslint/types": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz", + "integrity": "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/babel-plugin-syntax-trailing-function-commas": { - "version": "7.0.0-beta.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz", - "integrity": "sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==" - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz", + "integrity": "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==", "dev": true, "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/babel-preset-fbjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz", - "integrity": "sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, "dependencies": { - "@babel/plugin-proposal-class-properties": "^7.0.0", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0", - "@babel/plugin-syntax-class-properties": "^7.0.0", - "@babel/plugin-syntax-flow": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "@babel/plugin-transform-arrow-functions": "^7.0.0", - "@babel/plugin-transform-block-scoped-functions": "^7.0.0", - "@babel/plugin-transform-block-scoping": "^7.0.0", - "@babel/plugin-transform-classes": "^7.0.0", - "@babel/plugin-transform-computed-properties": "^7.0.0", - "@babel/plugin-transform-destructuring": "^7.0.0", - "@babel/plugin-transform-flow-strip-types": "^7.0.0", - "@babel/plugin-transform-for-of": "^7.0.0", - "@babel/plugin-transform-function-name": "^7.0.0", - "@babel/plugin-transform-literals": "^7.0.0", - "@babel/plugin-transform-member-expression-literals": "^7.0.0", - "@babel/plugin-transform-modules-commonjs": "^7.0.0", - "@babel/plugin-transform-object-super": "^7.0.0", - "@babel/plugin-transform-parameters": "^7.0.0", - "@babel/plugin-transform-property-literals": "^7.0.0", - "@babel/plugin-transform-react-display-name": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-shorthand-properties": "^7.0.0", - "@babel/plugin-transform-spread": "^7.0.0", - "@babel/plugin-transform-template-literals": "^7.0.0", - "babel-plugin-syntax-trailing-function-commas": "^7.0.0-beta.0" + "lru-cache": "^6.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/babel-preset-jest": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "node_modules/@typescript-eslint/utils": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.51.0.tgz", + "integrity": "sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==", "dev": true, + "peer": true, "dependencies": { - "babel-plugin-jest-hoist": "^26.6.2", - "babel-preset-current-node-syntax": "^1.0.0" + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/typescript-estree": "5.51.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" }, "engines": { - "node": ">= 10.14.2" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "peer": true, "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "lru-cache": "^6.0.0" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base-64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", - "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dependencies": { - "is-descriptor": "^1.0.0" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz", + "integrity": "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==", + "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "@typescript-eslint/types": "5.51.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "dependencies": { - "kind-of": "^6.0.0" + "event-target-shim": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.5" } }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/absolute-path": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz", + "integrity": "sha512-HQiug4c+/s3WOvEnDRxXVmNtSG5s2gJM9r19BTcqjp7BWcE48PB+Y2G6jE65kqI0LpsQeMZygt/b60Gi4KxGyA==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": "^4.5.0 || >= 5.9" + "node": ">=0.4.0" } }, - "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "engines": { - "node": ">=0.6" + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "peer": true, "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/bl/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "node_modules/bplist-creator": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", - "integrity": "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==", - "dependencies": { - "stream-buffers": "2.2.x" - } - }, - "node_modules/bplist-parser": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", - "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", - "dependencies": { - "big-integer": "1.6.x" - }, - "engines": { - "node": ">= 5.10.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "node_modules/browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "dependencies": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/browserify-sign/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "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" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "node_modules/builtins": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-4.1.0.tgz", - "integrity": "sha512-1bPRZQtmKaO6h7qV1YHXNtr6nCK28k0Zo95KM4dXfILcZZwoHJBN1m3lfLv9LPkcOZlrSr+J1bzMaZFO98Yq0w==", - "dev": true, - "peer": true, - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/builtins/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "peer": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "engines": { - "node": ">=4" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001412", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001412.tgz", - "integrity": "sha512-+TeEIee1gS5bYOiuf+PS/kp2mrXic37Hl66VY6EAfxasIk5fELTktK2oOezYed12H8w7jt3s512PpulQidPjwA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "dependencies": { - "rsvp": "^4.8.4" - }, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/changelog-parser": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/changelog-parser/-/changelog-parser-2.8.1.tgz", - "integrity": "sha512-tNUYFRCEeWTXmwLqoNtOEzx9wcytg72MmGQqsEs14ClYwIDln7sbQw7FJj/dulXgSlsxkemc9gpPQhZYZx1TPw==", - "dev": true, - "dependencies": { - "line-reader": "^0.2.4", - "remove-markdown": "^0.2.2" - }, - "bin": { - "changelog-parser": "bin/cli.js" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", - "dev": true - }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" - }, - "node_modules/convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/core-js-compat": { - "version": "3.26.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", - "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", - "dependencies": { - "browserslist": "^4.21.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/cross-env/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cross-env/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/anser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", + "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==" }, - "node_modules/cross-env/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, + "node_modules/ansi-fragments": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-fragments/-/ansi-fragments-0.2.1.tgz", + "integrity": "sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==", "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cross-env/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" + "colorette": "^1.0.7", + "slice-ansi": "^2.0.0", + "strip-ansi": "^5.0.0" } }, - "node_modules/cross-env/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, + "node_modules/ansi-fragments/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "engines": { - "node": ">= 8" + "node": ">=6" } }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "node_modules/ansi-fragments/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "ansi-regex": "^4.1.0" }, "engines": { - "node": ">=4.8" - } - }, - "node_modules/cross-spawn/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" + "node": ">=6" } }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "engines": { "node": ">=8" } }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/csstype": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", - "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" - }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/dayjs": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.0.tgz", - "integrity": "sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==" - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "color-convert": "^1.9.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, "engines": { - "node": ">=0.10" + "node": ">= 8" } }, - "node_modules/deep-diff": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz", - "integrity": "sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ=", - "dev": true + "node_modules/appdirsjs": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.7.tgz", + "integrity": "sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==" }, - "node_modules/deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "dependencies": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "peer": true }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/deepmerge": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz", - "integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==", + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "engines": { "node": ">=0.10.0" } }, - "node_modules/defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dependencies": { - "clone": "^1.0.2" + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", "dev": true, "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" }, "engines": { "node": ">= 0.4" @@ -5153,1090 +3514,1084 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/define-property/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dependencies": { - "kind-of": "^6.0.0" - }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "engines": { "node": ">=0.10.0" } }, - "node_modules/define-property/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "peer": true, "dependencies": { - "kind-of": "^6.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-property/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "node_modules/array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/denodeify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", - "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=" - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/deprecated-react-native-prop-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz", - "integrity": "sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==", "dependencies": { - "@react-native/normalize-color": "*", - "invariant": "*", - "prop-types": "*" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" } }, - "node_modules/des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "dependencies": { + "bn.js": "^4.0.0", "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=0.10.0" } }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, + "node_modules/ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "dependencies": { + "tslib": "^2.0.1" + }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "engines": { - "node": ">= 10.14.2" + "node": ">=4" } }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "bin": { + "atob": "bin/atob.js" }, "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "node": ">= 4.5.0" } }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] + "node_modules/babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "node_modules/babel-plugin-module-resolver": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz", + "integrity": "sha512-g0u+/ChLSJ5+PzYwLwP8Rp8Rcfowz58TJNCe+L/ui4rpzE/mg//JVX0EWBUYoxaextqnwuGHzfGp2hh0PPV25Q==", "dev": true, "dependencies": { - "webidl-conversions": "^5.0.0" + "find-babel-config": "^2.0.0", + "glob": "^8.0.3", + "pkg-up": "^3.1.0", + "reselect": "^4.1.7", + "resolve": "^1.22.1" }, "engines": { - "node": ">=8" + "node": ">= 16" } }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "node_modules/babel-plugin-module-resolver/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "node_modules/babel-plugin-module-resolver/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { - "domelementtype": "^2.3.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": ">= 4" + "node": ">=12" }, "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "node_modules/babel-plugin-module-resolver/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "brace-expansion": "^2.0.1" }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "engines": { + "node": ">=10" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.265", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.265.tgz", - "integrity": "sha512-38KaYBNs0oCzWCpr6j7fY/W9vF0vSp4tKFIshQTgdZMhUpkxgotkQgjJP6iGMdmlsgMs3i0/Hkko4UXLTrkYVQ==" - }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", - "dev": true, - "engines": { - "node": ">=10" + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "engines": { - "node": ">= 0.8" + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "node_modules/babel-plugin-syntax-trailing-function-commas": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz", + "integrity": "sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==" + }, + "node_modules/babel-preset-fbjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz", + "integrity": "sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow==", "dependencies": { - "once": "^1.4.0" + "@babel/plugin-proposal-class-properties": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-syntax-class-properties": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-block-scoped-functions": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-flow-strip-types": "^7.0.0", + "@babel/plugin-transform-for-of": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-member-expression-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-object-super": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-property-literals": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-template-literals": "^7.0.0", + "babel-plugin-syntax-trailing-function-commas": "^7.0.0-beta.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/engine.io": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz", - "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dependencies": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.0.3", - "ws": "~8.2.3" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=0.10.0" } }, - "node_modules/engine.io-parser": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", - "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", - "engines": { - "node": ">=10.0.0" - } + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dependencies": { - "ms": "2.1.2" + "is-descriptor": "^1.0.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=0.10.0" } }, - "node_modules/engine.io/node_modules/ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "utf-8-validate": { - "optional": true + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "node_modules/entities": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz", - "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==", - "dev": true, - "engines": { - "node": ">=0.12" + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "node_modules/envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dependencies": { - "is-arrayish": "^0.2.1" + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "node_modules/error-stack-parser": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.7.tgz", - "integrity": "sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA==", + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", "dependencies": { - "stackframe": "^1.1.1" + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" } }, - "node_modules/errorhandler": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.1.tgz", - "integrity": "sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==", + "node_modules/browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", "dependencies": { - "accepts": "~1.3.7", - "escape-html": "~1.0.3" - }, - "engines": { - "node": ">= 0.8" + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" } }, - "node_modules/es-abstract": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", - "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", - "dev": true, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" }, - "engines": { - "node": ">= 0.4" + "bin": { + "browserslist": "cli.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dependencies": { - "has": "^1.0.3" + "node-int64": "^0.4.0" } }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "node_modules/escape-html": { + "node_modules/buffer-xor": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "engines": { - "node": ">=0.8.0" + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "peer": true, + "dependencies": { + "semver": "^7.0.0" } }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "node_modules/builtins/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, + "peer": true, "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" + "lru-cache": "^6.0.0" }, "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "semver": "bin/semver.js" }, "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" + "node": ">=10" } }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "engines": { - "node": ">=4.0" + "node": ">= 0.8" } }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.10.0" } }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dev": true, "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", + "dependencies": { + "callsites": "^2.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=4" } }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, + "node_modules/caller-callsite/node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", "engines": { - "node": ">= 0.8.0" + "node": ">=4" } }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", + "dependencies": { + "caller-callsite": "^2.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, + "peer": true, "engines": { - "node": ">= 0.8.0" + "node": ">=6" } }, - "node_modules/eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-config-standard": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", - "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==", - "dev": true, + "node_modules/caniuse-lite": { + "version": "1.0.30001431", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", + "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" + "type": "opencollective", + "url": "https://opencollective.com/browserslist" }, { - "type": "consulting", - "url": "https://feross.org/support" + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" } - ], - "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0", - "eslint-plugin-promise": "^6.0.0" - } + ] }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dependencies": { - "ms": "^2.1.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "node_modules/eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", - "dev": true, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dependencies": { - "ms": "^2.1.1" + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/eslint-module-utils/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, + "node_modules/class-utils/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dependencies": { - "locate-path": "^2.0.0" + "kind-of": "^3.0.2" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/eslint-module-utils/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, + "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/eslint-module-utils/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, + "node_modules/class-utils/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dependencies": { - "p-try": "^1.0.0" + "kind-of": "^3.0.2" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/eslint-module-utils/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, + "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { - "p-limit": "^1.1.0" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/eslint-module-utils/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/eslint-module-utils/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, + "node_modules/class-utils/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", - "dev": true, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" + "restore-cursor": "^3.1.0" }, "engines": { - "node": ">=8.10.0" + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "engines": { + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-html": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-7.1.0.tgz", - "integrity": "sha512-fNLRraV/e6j8e3XYOC9xgND4j+U7b1Rq+OygMlLcMg+wI/IpVbF+ubQa3R78EjKB9njT6TQOlcK5rFKBVVtdfg==", - "dev": true, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dependencies": { - "htmlparser2": "^8.0.1" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" } }, - "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", - "dev": true, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" }, "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "node": ">=6" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "dependencies": { - "esutils": "^2.0.2" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-n": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.2.0.tgz", - "integrity": "sha512-lWLg++jGwC88GDGGBX3CMkk0GIWq0y41aH51lavWApOKcMQcYoL3Ayd0lEdtD3SnQtR+3qBvWQS3qGbR2BxRWg==", - "dev": true, - "peer": true, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dependencies": { - "builtins": "^4.0.0", - "eslint-plugin-es": "^4.1.0", - "eslint-utils": "^3.0.0", - "ignore": "^5.1.1", - "is-core-module": "^2.3.0", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=12.22.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=7.0.0" + "color-name": "1.1.3" } }, - "node_modules/eslint-plugin-n/node_modules/eslint-plugin-es": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", - "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", - "dev": true, - "peer": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==" + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" + }, + "node_modules/commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" + "node": "^12.20.0 || >=14" } }, - "node_modules/eslint-plugin-n/node_modules/eslint-plugin-es/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "peer": true, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "mime-db": ">= 1.43.0 < 2" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "node": ">= 0.6" } }, - "node_modules/eslint-plugin-n/node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "peer": true, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "node": ">= 0.8.0" } }, - "node_modules/eslint-plugin-n/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dependencies": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "engines": { - "node": ">=8.10.0" + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" }, - "peerDependencies": { - "eslint": ">=5.16.0" - } - }, - "node_modules/eslint-plugin-promise": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", - "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", - "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "node": ">= 0.10.0" } }, - "node_modules/eslint-plugin-react": { - "version": "7.31.11", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz", - "integrity": "sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw==", - "dev": true, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.8" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "ms": "2.0.0" } }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, + "node_modules/core-js-compat": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", + "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", "dependencies": { - "esutils": "^2.0.2" + "browserslist": "^4.21.4" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/eslint-plugin-react/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, "engines": { - "node": ">=4.0" + "node": ">=4" } }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", - "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", - "dev": true, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "sprintf-js": "~1.0.2" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, + "node_modules/cosmiconfig/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=4" } }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, + "node_modules/cosmiconfig/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", "engines": { "node": ">=4" } }, - "node_modules/eslint/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" } }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } }, - "node_modules/eslint/node_modules/cross-spawn": { + "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "peer": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -6246,11 +4601,42 @@ "node": ">= 8" } }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "dev": true + }, + "node_modules/dayjs": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", + "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -6263,279 +4649,410 @@ } } }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, + "peer": true + }, + "node_modules/deepmerge": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz", + "integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==", "engines": { - "node": ">=10" + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "node": ">=0.10.0" } }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, + "node_modules/denodeify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", + "integrity": "sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "engines": { - "node": ">=10" + "node": ">= 0.8" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "engines": { - "node": ">=4.0" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", - "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "dependencies": { - "type-fest": "^0.20.2" + "path-type": "^4.0.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "peer": true, "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "esutils": "^2.0.2" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.0.0" } }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.8" } }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "once": "^1.4.0" } }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, + "node_modules/engine.io-client": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.4.0.tgz", + "integrity": "sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==", "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" } }, - "node_modules/eslint/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "engines": { - "node": ">=8" + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "node_modules/eslint/node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, + "node_modules/engine.io-parser": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz", + "integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "node": ">=10.0.0" } }, - "node_modules/eslint/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "bin": { + "envinfo": "dist/cli.js" + }, "engines": { "node": ">=4" } }, - "node_modules/eslint/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" + "is-arrayish": "^0.2.1" } }, - "node_modules/eslint/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dependencies": { + "stackframe": "^1.3.4" } }, - "node_modules/eslint/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "node_modules/errorhandler": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.1.tgz", + "integrity": "sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==", "dependencies": { - "ansi-regex": "^5.0.1" + "accepts": "~1.3.7", + "escape-html": "~1.0.3" }, "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/es-abstract": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", "dev": true, "dependencies": { - "isexe": "^2.0.0" + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" }, - "bin": { - "node-which": "bin/node-which" + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "engines": { - "node": ">= 8" + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" } }, - "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "node_modules/eslint": { + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz", + "integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==", "dev": true, + "peer": true, "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6544,1342 +5061,1365 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/espree/node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "node_modules/eslint-config-standard": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", + "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0", + "eslint-plugin-promise": "^6.0.0" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "node_modules/eslint-config-standard-with-typescript": { + "version": "34.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-34.0.0.tgz", + "integrity": "sha512-zhCsI4/A0rJ1ma8sf3RLXYc0gc7yPmdTWRVXMh9dtqeUx3yBQyALH0wosHhk1uQ9QyItynLdNOtcHKNw8G7lQw==", "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "dependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint-config-standard": "17.0.0" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0", + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0", + "eslint-plugin-promise": "^6.0.0", + "typescript": "*" } }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, + "peer": true, "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "engines": { - "node": ">=4.0" + "peer": true, + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, + "peer": true, "dependencies": { - "estraverse": "^5.2.0" + "debug": "^3.2.7" }, "engines": { - "node": ">=4.0" + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "engines": { - "node": ">=4.0" + "peer": true, + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/eslint-plugin-es": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", + "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", "dev": true, + "peer": true, + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "engines": { - "node": ">= 0.6" + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "node_modules/eslint-plugin-es/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "peer": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "peer": true, "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" + "node": ">=4" } }, - "node_modules/exec-sh": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", - "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", - "dev": true - }, - "node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "node_modules/eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dev": true, + "peer": true, "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" + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" }, "engines": { - "node": ">=6" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true, - "engines": { - "node": ">= 0.8.0" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "peer": true, "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "ms": "^2.1.1" } }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "peer": true, "dependencies": { - "is-descriptor": "^0.1.0" + "esutils": "^2.0.2" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "node_modules/eslint-plugin-n": { + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.6.1.tgz", + "integrity": "sha512-R9xw9OtCRxxaxaszTQmQAlPgM+RdGjaL1akWuY/Fv9fRAi8Wj4CUKc6iYVG8QNRjRuo8/BqVYIpfqberJUEacA==", + "dev": true, + "peer": true, "dependencies": { - "is-extendable": "^0.1.0" + "builtins": "^5.0.1", + "eslint-plugin-es": "^4.1.0", + "eslint-utils": "^3.0.0", + "ignore": "^5.1.1", + "is-core-module": "^2.11.0", + "minimatch": "^3.1.2", + "resolve": "^1.22.1", + "semver": "^7.3.8" }, "engines": { - "node": ">=0.10.0" + "node": ">=12.22.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", + "node_modules/eslint-plugin-n/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, + "peer": true, "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 10.14.2" + "node": ">=10" } }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, + "node_modules/eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/extend-shallow/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dev": true, "dependencies": { - "is-plain-object": "^2.0.4" + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" } }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, "dependencies": { - "is-descriptor": "^1.0.0" + "esutils": "^2.0.2" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, "dependencies": { - "is-extendable": "^0.1.0" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "peer": true, "dependencies": { - "kind-of": "^6.0.0" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.0.0" } }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dependencies": { - "kind-of": "^6.0.0" - }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=4.0" } }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "peer": true, "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "eslint-visitor-keys": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dependencies": { - "bser": "2.1.1" + "peer": true, + "engines": { + "node": ">=10" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, "dependencies": { - "to-regex-range": "^5.0.1" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 0.8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/find-babel-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", - "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "peer": true, "dependencies": { - "json5": "^0.5.1", - "path-exists": "^3.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=4.0.0" + "node": ">=7.0.0" } }, - "node_modules/find-babel-config/node_modules/json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "bin": { - "json5": "lib/cli.js" - } + "peer": true }, - "node_modules/find-babel-config/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "peer": true, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "peer": true, "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/eslint/node_modules/globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "dev": true, + "peer": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "type-fest": "^0.20.2" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/findit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", - "integrity": "sha1-ZQnwEmr0wXhVHPqZOU4DLhOk1W4=", - "dev": true - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, + "peer": true, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=8" } }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "peer": true, "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "has-flag": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "node_modules/flow-parser": { - "version": "0.121.0", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.121.0.tgz", - "integrity": "sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg==", "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, + "peer": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">= 6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dependencies": { - "map-cache": "^0.2.2" + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "peer": true, + "dependencies": { + "estraverse": "^5.1.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=0.10" } }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "peer": true, "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=4.0" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=4.0" } }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "engines": { - "node": ">=6.9.0" + "node": ">=6" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=0.8.x" } }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dev": true, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "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" + }, "engines": { - "node": ">=8.0.0" + "node": ">=6" } }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "node_modules/execa/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dependencies": { - "pump": "^3.0.0" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" }, "engines": { - "node": ">=6" + "node": ">=4.8" } }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, + "node_modules/execa/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/execa/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "shebang-regex": "^1.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "node_modules/execa/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "engines": { "node": ">=0.10.0" } }, - "node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "node_modules/execa/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" + "isexe": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "bin": { + "which": "bin/which" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "dependencies": { - "is-glob": "^4.0.3" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "engines": { - "node": ">=10.13.0" + "node": ">=0.10.0" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dependencies": { - "function-bind": "^1.1.1" + "is-descriptor": "^0.1.0" }, "engines": { - "node": ">= 0.4.0" + "node": ">=0.10.0" } }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { - "get-intrinsic": "^1.1.1" + "is-buffer": "^1.1.5" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" + "node_modules/expand-brackets/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, + "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { - "has-symbols": "^1.0.2" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, + "node_modules/expand-brackets/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "engines": { "node": ">=0.10.0" } }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dependencies": { - "kind-of": "^3.0.2" - }, + "node_modules/expand-brackets/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "engines": { "node": ">=0.10.0" } }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dependencies": { - "is-buffer": "^1.1.5" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dependencies": { - "is-buffer": "^1.1.5" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" + "is-descriptor": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/hash-base/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "is-extendable": "^0.1.0" }, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/hash-base/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" + "node_modules/extglob/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/hermes-engine": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/hermes-engine/-/hermes-engine-0.11.0.tgz", - "integrity": "sha512-7aMUlZja2IyLYAcZ69NBnwJAR5ZOYlSllj0oMpx08a8HzxHOys0eKCzfphrf6D0vX1JGO1QQvVsQKe6TkYherw==" - }, - "node_modules/hermes-estree": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.5.0.tgz", - "integrity": "sha512-1h8rvG23HhIR5K6Kt0e5C7BC72J1Ath/8MmSta49vxXp/j6wl7IMHvIRFYBQr35tWnQY97dSGR2uoAJ5pHUQkg==" - }, - "node_modules/hermes-parser": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.5.0.tgz", - "integrity": "sha512-ARnJBScKAkkq8j3BHrNGBUv/4cSpZNbKDsVizEtzmsFeqC67Dopa5s4XRe+e3wN52Dh5Mj2kDB5wJvhcxwDkPg==", - "dependencies": { - "hermes-estree": "0.5.0" - } + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "peer": true }, - "node_modules/hermes-profile-transformer": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/hermes-profile-transformer/-/hermes-profile-transformer-0.0.6.tgz", - "integrity": "sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==", + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, "dependencies": { - "source-map": "^0.7.3" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "peer": true }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "peer": true }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" + "reusify": "^1.0.4" } }, - "node_modules/html-escaper": { + "node_modules/fb-watchman": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/html-parse-stringify": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", - "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dependencies": { - "void-elements": "3.1.0" + "bser": "2.1.1" } }, - "node_modules/htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], + "peer": true, "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "entities": "^4.3.0" + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, "engines": { "node": ">= 0.8" } }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-babel-config": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.0.0.tgz", + "integrity": "sha512-dOKT7jvF3hGzlW60Gc3ONox/0rRZ/tz7WCil0bqA1In/3I8f1BctpXahRnEKDySZqci7u+dqq93sZST9fOJpFw==", "dev": true, "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "json5": "^2.1.1", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">=16.0.0" } }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "node_modules/find-babel-config/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "dependencies": { - "ms": "2.1.2" + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=6" } }, - "node_modules/https-proxy-agent": { + "node_modules/find-up": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dependencies": { - "agent-base": "6", - "debug": "4" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" } }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, + "peer": true, "dependencies": { - "ms": "2.1.2" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true, + "peer": true + }, + "node_modules/flow-parser": { + "version": "0.121.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.121.0.tgz", + "integrity": "sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg==", "engines": { - "node": ">=8.12.0" + "node": ">=0.4.0" } }, - "node_modules/i18next": { - "version": "22.1.5", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.1.5.tgz", - "integrity": "sha512-Mjj45PbpZByE+c6ddLEkkj0LUyzJP1cRGeC/+O6mvp1+GAwW7rIx6aOPW9+Zxe+JO3EcJCAkibwbZrgBRF/qRA==", - "funding": [ - { - "type": "individual", - "url": "https://locize.com" - }, - { - "type": "individual", - "url": "https://locize.com/i18next.html" - }, - { - "type": "individual", - "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" - } - ], - "dependencies": { - "@babel/runtime": "^7.20.6" + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "map-cache": "^0.2.2" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "engines": { - "node": ">= 4" + "node": ">= 0.6" } }, - "node_modules/image-size": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz", - "integrity": "sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA==", - "bin": { - "image-size": "bin/image-size.js" + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">=4.0" + "node": ">=6 <7 || >=8" } }, - "node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", "dev": true, "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/import-local/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "engines": { - "node": ">=0.8.19" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dependencies": { - "loose-envify": "^1.0.0" + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dependencies": { - "kind-of": "^3.0.2" + "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" }, "engines": { - "node": ">=0.10.0" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "peer": true, "dependencies": { - "is-buffer": "^1.1.5" + "is-glob": "^4.0.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13.0" } }, - "node_modules/is-arguments": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", - "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { - "call-bind": "^1.0.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, - "node_modules/is-bigint": { + "node_modules/grapheme-splitter": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true, + "peer": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dependencies": { - "has-bigints": "^1.0.1" + "function-bind": "^1.1.1" }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "get-intrinsic": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, "engines": { "node": ">= 0.4" @@ -7888,1267 +6428,913 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dev": true, "dependencies": { - "ci-info": "^2.0.0" + "has-symbols": "^1.0.2" }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dependencies": { - "has": "^1.0.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "dependencies": { - "kind-of": "^3.0.2" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "dependencies": { - "is-buffer": "^1.1.5" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-date-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", - "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "kind-of": "^3.0.2" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "optional": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "engines": { - "node": ">=4" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "dependencies": { - "is-extglob": "^2.1.1" + "is-buffer": "^1.1.5" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "engines": { - "node": ">=0.12.0" + "node": ">=4" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/hermes-estree": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.8.0.tgz", + "integrity": "sha512-W6JDAOLZ5pMPMjEiQGLCXSSV7pIBEgRR5zGkxgmzGSXHOxqV5dC/M1Zevqpbm9TZDE5tu358qZf8Vkzmsc+u7Q==" }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" + "node_modules/hermes-parser": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.8.0.tgz", + "integrity": "sha512-yZKalg1fTYG5eOiToLUaw69rQfZq/fi+/NtEXRU7N87K/XobNRhRWorh80oSge2lWUiZfTgUvRJH+XgZWrhoqA==", + "dependencies": { + "hermes-estree": "0.8.0" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/hermes-profile-transformer": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/hermes-profile-transformer/-/hermes-profile-transformer-0.0.6.tgz", + "integrity": "sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==", "dependencies": { - "isobject": "^3.0.1" + "source-map": "^0.7.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/is-potential-custom-element-name": { + "node_modules/hmac-drbg": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "react-is": "^16.7.0" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dependencies": { - "call-bind": "^1.0.2" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.8" } }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dependencies": { - "has-tostringtag": "^1.0.0" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 4" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "engines": { - "node": ">=10" + "node_modules/image-size": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz", + "integrity": "sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA==", + "bin": { + "image-size": "bin/image-size.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=4.0" } }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "peer": true, "dependencies": { - "call-bind": "^1.0.2" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "engines": { - "node": ">=4" + "node": ">=0.8.19" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "engines": { - "node": ">=0.10.0" + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "dev": true, "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" + "loose-envify": "^1.0.0" } }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, + "node_modules/ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dependencies": { - "semver": "^6.0.0" + "kind-of": "^6.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "has-bigints": "^1.0.1" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/istanbul-lib-source-maps/node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, "dependencies": { - "ms": "2.1.2" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=6.0" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, - "node_modules/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", - "dev": true, - "dependencies": { - "@jest/core": "^26.6.3", - "import-local": "^3.0.2", - "jest-cli": "^26.6.3" - }, - "bin": { - "jest": "bin/jest.js" + "node": ">= 0.4" }, - "engines": { - "node": ">= 10.14.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-changed-files": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", - "dev": true, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dependencies": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" + "has": "^1.0.3" }, - "engines": { - "node": ">= 10.14.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-changed-files/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, + "node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "kind-of": "^6.0.0" }, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, + "node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-changed-files/node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dependencies": { - "path-key": "^3.0.0" + "is-plain-object": "^2.0.4" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/jest-changed-files/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { - "shebang-regex": "^3.0.0" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-changed-files/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "engines": { "node": ">=8" } }, - "node_modules/jest-changed-files/node_modules/which": { + "node_modules/is-negative-zero": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "engines": { - "node": ">= 8" + "node": ">=0.12.0" } }, - "node_modules/jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "dependencies": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, + "peer": true, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-environment-jsdom": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", - "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2", - "jsdom": "^16.4.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "call-bind": "^1.0.2" }, - "engines": { - "node": ">= 10.14.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, "dependencies": { - "@jest/types": "^26.6.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 0.4" }, - "optionalDependencies": { - "fsevents": "^2.1.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-jasmine2": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", - "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "dependencies": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^26.6.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2", - "throat": "^5.0.0" + "has-symbols": "^1.0.2" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", - "dev": true, - "dependencies": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "engines": { - "node": ">= 10.14.2" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "call-bind": "^1.0.2" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, + "node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", "engines": { - "node": ">= 10.14.2" + "node": ">=4" } }, - "node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, + "node_modules/jest-get-type": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } + "node": ">= 10.14.2" } }, "node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true, + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "engines": { - "node": ">= 10.14.2" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" + "@types/node": "*", + "graceful-fs": "^4.2.9" }, "engines": { - "node": ">= 10.14.2" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-resolve-dependencies": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", - "dev": true, + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", "dependencies": { - "@jest/types": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.6.2" + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">= 10.14.2" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-resolve/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-resolve/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-resolve/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.6.1.tgz", + "integrity": "sha512-up5ggbaDqOqJ4UqLKZ2naVkyqSJQgJi5lwD6b6mM748ysrghDBX0bx/qJTUHzw7zu6Mq4gycviSF5hJnwceD8w==", "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-resolve/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=8" + "node": ">=7.0.0" } }, - "node_modules/jest-resolve/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, - "node_modules/jest-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", - "dev": true, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.7.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "source-map-support": "^0.5.6", - "throat": "^5.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", - "dev": true, + "node_modules/jest-validate": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", + "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", + "camelcase": "^6.0.0", "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.4.1" - }, - "bin": { - "jest-runtime": "bin/jest-runtime.js" + "jest-get-type": "^26.3.0", + "leven": "^3.1.0", + "pretty-format": "^26.6.2" }, "engines": { "node": ">= 10.14.2" } }, - "node_modules/jest-runtime/node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-serializer": { + "node_modules/jest-validate/node_modules/@jest/types": { "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", - "dev": true, + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "graceful-fs": "^4.2.4" + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" }, "engines": { "node": ">= 10.14.2" } }, - "node_modules/jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, + "node_modules/jest-validate/node_modules/@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", "dependencies": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 10.14.2" + "@types/yargs-parser": "*" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "leven": "^3.1.0", - "pretty-format": "^26.6.2" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 10.14.2" + "node": ">=7.0.0" } }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/jest-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", - "dev": true, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^26.6.2", - "string-length": "^4.0.1" + "has-flag": "^4.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, "node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "supports-color": "^8.0.0" }, "engines": { "node": ">= 10.13.0" } }, - "node_modules/jest/node_modules/jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", - "dev": true, - "dependencies": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "prompts": "^2.0.1", - "yargs": "^15.4.1" - }, - "bin": { - "jest": "bin/jest.js" - }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/jetifier": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/jetifier/-/jetifier-1.6.8.tgz", - "integrity": "sha512-3Zi16h6L5tXDRQJTb221cnRoVG9/9OvreLdLU2/ZjRv/GILL+2Cemt0IKvkowwkDpvouAU1DQPOJ7qaiHeIdrw==", - "bin": { - "jetifier": "bin/jetify", - "jetifier-standalone": "bin/jetifier-standalone", - "jetify": "bin/jetify" + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz", + "integrity": "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==", "dependencies": { "@hapi/hoek": "^9.0.0", "@hapi/topo": "^5.0.0", @@ -9157,16 +7343,12 @@ "@sideway/pinpoint": "^2.0.0" } }, - "node_modules/js-htmlencode": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/js-htmlencode/-/js-htmlencode-0.3.0.tgz", - "integrity": "sha1-sc4pPflOlviooIsfM2j5d70lVzE=" - }, "node_modules/js-sdsl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", - "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==", - "dev": true + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "dev": true, + "peer": true }, "node_modules/js-tokens": { "version": "4.0.0", @@ -9174,12 +7356,13 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -9222,6 +7405,20 @@ "@babel/preset-env": "^7.1.6" } }, + "node_modules/jscodeshift/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/jscodeshift/node_modules/braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", @@ -9253,6 +7450,37 @@ "node": ">=0.10.0" } }, + "node_modules/jscodeshift/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jscodeshift/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jscodeshift/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/jscodeshift/node_modules/fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -9278,6 +7506,22 @@ "node": ">=0.10.0" } }, + "node_modules/jscodeshift/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jscodeshift/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jscodeshift/node_modules/is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -9334,6 +7578,17 @@ "rimraf": "bin.js" } }, + "node_modules/jscodeshift/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jscodeshift/node_modules/temp": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", @@ -9357,85 +7612,6 @@ "node": ">=0.10.0" } }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/jsdom/node_modules/ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -9452,28 +7628,24 @@ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "peer": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -9484,27 +7656,19 @@ "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "optionalDependencies": { "graceful-fs": "^4.1.6" } }, - "node_modules/jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "engines": { - "node": "*" - } - }, "node_modules/jsx-ast-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", - "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", "dev": true, "dependencies": { - "array-includes": "^3.1.3", - "object.assign": "^4.1.2" + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" }, "engines": { "node": ">=4.0" @@ -9521,7 +7685,7 @@ "node_modules/klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", "optionalDependencies": { "graceful-fs": "^4.1.9" } @@ -9547,6 +7711,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "peer": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -9555,27 +7720,18 @@ "node": ">= 0.8.0" } }, - "node_modules/line-reader": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/line-reader/-/line-reader-0.2.4.tgz", - "integrity": "sha1-xDkrWH3qOFgMlnhXDm6OSfzlJiI=", - "dev": true - }, - "node_modules/lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dependencies": { - "p-locate": "^4.1.0" + "p-locate": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash": { @@ -9586,84 +7742,97 @@ "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/lodash.throttle": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" }, "node_modules/log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dependencies": { - "chalk": "^2.0.1" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/log-symbols/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/log-symbols/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/log-symbols/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/log-symbols/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/logkitty": { @@ -9691,9 +7860,9 @@ } }, "node_modules/lrc-file-parser": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/lrc-file-parser/-/lrc-file-parser-2.2.8.tgz", - "integrity": "sha512-Uq2boQVg4Ll4Csthq0ZJ+4Nn8sBfOJwceFsJGGfOxcpKSYpEMmDRsinuVnhNVJe4x/jD1HJr9xWzDqgo+8WMTw==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lrc-file-parser/-/lrc-file-parser-2.3.0.tgz", + "integrity": "sha512-EX+Dnvwqgb8q3mf7WYIR4flOzwrOp9vE2MU+eyRZO0rFUF5BIZgN52SSGXFhfnHd5tUmo7VnLrpCFdURe3O2KQ==" }, "node_modules/lru-cache": { "version": "6.0.0", @@ -9728,17 +7897,17 @@ } }, "node_modules/makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dependencies": { - "tmpl": "1.0.x" + "tmpl": "1.0.5" } }, "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "engines": { "node": ">=0.10.0" } @@ -9746,7 +7915,7 @@ "node_modules/map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dependencies": { "object-visit": "^1.0.0" }, @@ -9764,6 +7933,11 @@ "safe-buffer": "^5.1.2" } }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "node_modules/merge-options": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", @@ -9780,10 +7954,19 @@ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/metro": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.67.0.tgz", - "integrity": "sha512-DwuBGAFcAivoac/swz8Lp7Y5Bcge1tzT7T6K0nf1ubqJP8YzBUtyR4pkjEYVUzVu/NZf7O54kHSPVu1ibYzOBQ==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.72.3.tgz", + "integrity": "sha512-Hb3xTvPqex8kJ1hutQNZhQadUKUwmns/Du9GikmWKBFrkiG3k3xstGAyO5t5rN9JSUEzQT6y9SWzSSOGogUKIg==", "dependencies": { "@babel/code-frame": "^7.0.0", "@babel/core": "^7.14.0", @@ -9794,7 +7977,7 @@ "@babel/types": "^7.0.0", "absolute-path": "^0.0.0", "accepts": "^1.3.7", - "async": "^2.4.0", + "async": "^3.2.2", "chalk": "^4.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", @@ -9802,30 +7985,29 @@ "denodeify": "^1.2.1", "error-stack-parser": "^2.0.6", "fs-extra": "^1.0.0", - "graceful-fs": "^4.1.3", - "hermes-parser": "0.5.0", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.8.0", "image-size": "^0.6.0", "invariant": "^2.2.4", - "jest-haste-map": "^27.3.1", - "jest-worker": "^26.0.0", + "jest-worker": "^27.2.0", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.67.0", - "metro-cache": "0.67.0", - "metro-cache-key": "0.67.0", - "metro-config": "0.67.0", - "metro-core": "0.67.0", - "metro-hermes-compiler": "0.67.0", - "metro-inspector-proxy": "0.67.0", - "metro-minify-uglify": "0.67.0", - "metro-react-native-babel-preset": "0.67.0", - "metro-resolver": "0.67.0", - "metro-runtime": "0.67.0", - "metro-source-map": "0.67.0", - "metro-symbolicate": "0.67.0", - "metro-transform-plugins": "0.67.0", - "metro-transform-worker": "0.67.0", + "metro-babel-transformer": "0.72.3", + "metro-cache": "0.72.3", + "metro-cache-key": "0.72.3", + "metro-config": "0.72.3", + "metro-core": "0.72.3", + "metro-file-map": "0.72.3", + "metro-hermes-compiler": "0.72.3", + "metro-inspector-proxy": "0.72.3", + "metro-minify-uglify": "0.72.3", + "metro-react-native-babel-preset": "0.72.3", + "metro-resolver": "0.72.3", + "metro-runtime": "0.72.3", + "metro-source-map": "0.72.3", + "metro-symbolicate": "0.72.3", + "metro-transform-plugins": "0.72.3", + "metro-transform-worker": "0.72.3", "mime-types": "^2.1.27", - "mkdirp": "^0.5.1", "node-fetch": "^2.2.0", "nullthrows": "^1.1.1", "rimraf": "^2.5.4", @@ -9842,179 +8024,107 @@ } }, "node_modules/metro-babel-transformer": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.67.0.tgz", - "integrity": "sha512-SBqc4nq/dgsPNFm+mpWcQQzJaXnh0nrfz2pSnZC4i6zMtIakrTWb8SQ78jOU1FZVEZ3nu9xCYVHS9Tbr/LoEuw==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.72.3.tgz", + "integrity": "sha512-PTOR2zww0vJbWeeM3qN90WKENxCLzv9xrwWaNtwVlhcV8/diNdNe82sE1xIxLFI6OQuAVwNMv1Y7VsO2I7Ejrw==", "dependencies": { "@babel/core": "^7.14.0", - "hermes-parser": "0.5.0", - "metro-source-map": "0.67.0", + "hermes-parser": "0.8.0", + "metro-source-map": "0.72.3", "nullthrows": "^1.1.1" } }, "node_modules/metro-cache": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.67.0.tgz", - "integrity": "sha512-IY5dXiR76L75b2ue/mv+9vW8g5hdQJU6YEe81lj6gTSoUrhcONT0rzY+Gh5QOS2Kk6z9utZQMvd9PRKL9/635A==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.72.3.tgz", + "integrity": "sha512-++eyZzwkXvijWRV3CkDbueaXXGlVzH9GA52QWqTgAOgSHYp5jWaDwLQ8qpsMkQzpwSyIF4LLK9aI3eA7Xa132A==", "dependencies": { - "metro-core": "0.67.0", - "mkdirp": "^0.5.1", + "metro-core": "0.72.3", "rimraf": "^2.5.4" } }, "node_modules/metro-cache-key": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.67.0.tgz", - "integrity": "sha512-FNJe5Rcb2uzY6G6tsqCf0RV4t2rCeX6vSHBxmP7k+4aI4NqX4evtPI0K82r221nBzm5DqNWCURZ0RYUT6jZMGA==" + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.72.3.tgz", + "integrity": "sha512-kQzmF5s3qMlzqkQcDwDxrOaVxJ2Bh6WRXWdzPnnhsq9LcD3B3cYqQbRBS+3tSuXmathb4gsOdhWslOuIsYS8Rg==" + }, + "node_modules/metro-cache/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } }, "node_modules/metro-config": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.67.0.tgz", - "integrity": "sha512-ThAwUmzZwTbKyyrIn2bKIcJDPDBS0LKAbqJZQioflvBGfcgA21h3fdL3IxRmvCEl6OnkEWI0Tn1Z9w2GLAjf2g==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.72.3.tgz", + "integrity": "sha512-VEsAIVDkrIhgCByq8HKTWMBjJG6RlYwWSu1Gnv3PpHa0IyTjKJtB7wC02rbTjSaemcr82scldf2R+h6ygMEvsw==", "dependencies": { "cosmiconfig": "^5.0.5", "jest-validate": "^26.5.2", - "metro": "0.67.0", - "metro-cache": "0.67.0", - "metro-core": "0.67.0", - "metro-runtime": "0.67.0" + "metro": "0.72.3", + "metro-cache": "0.72.3", + "metro-core": "0.72.3", + "metro-runtime": "0.72.3" } }, "node_modules/metro-core": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.67.0.tgz", - "integrity": "sha512-TOa/ShE1bUq83fGNfV6rFwyfZ288M8ydmWN3g9C2OW8emOHLhJslYD/SIU4DhDkP/99yaJluIALdZ2g0+pCrvQ==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.72.3.tgz", + "integrity": "sha512-KuYWBMmLB4+LxSMcZ1dmWabVExNCjZe3KysgoECAIV+wyIc2r4xANq15GhS94xYvX1+RqZrxU1pa0jQ5OK+/6A==", "dependencies": { - "jest-haste-map": "^27.3.1", "lodash.throttle": "^4.1.1", - "metro-resolver": "0.67.0" - } - }, - "node_modules/metro-core/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/metro-core/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dependencies": { - "@types/yargs-parser": "*" + "metro-resolver": "0.72.3" } }, - "node_modules/metro-core/node_modules/ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==" - }, - "node_modules/metro-core/node_modules/jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "node_modules/metro-file-map": { + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.72.3.tgz", + "integrity": "sha512-LhuRnuZ2i2uxkpFsz1XCDIQSixxBkBG7oICAFyLyEMDGbcfeY6/NexphfLdJLTghkaoJR5ARFMiIxUg9fIY/pA==", "dependencies": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", + "abort-controller": "^3.0.0", "anymatch": "^3.0.3", + "debug": "^2.2.0", "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-regex-util": "^27.0.6", + "jest-serializer": "^27.0.6", + "jest-util": "^27.2.0", + "jest-worker": "^27.2.0", "micromatch": "^4.0.4", "walker": "^1.0.7" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/metro-core/node_modules/jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/metro-core/node_modules/jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/metro-core/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "fsevents": "^2.1.2" } }, - "node_modules/metro-core/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "node_modules/metro-file-map/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" + "ms": "2.0.0" } }, - "node_modules/metro-core/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } + "node_modules/metro-file-map/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/metro-hermes-compiler": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-hermes-compiler/-/metro-hermes-compiler-0.67.0.tgz", - "integrity": "sha512-X5Pr1jC8/kO6d1EBDJ6yhtuc5euHX89UDNv8qdPJHAET03xfFnlojRPwOw6il2udAH20WLBv+F5M9VY+58zspQ==" + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-hermes-compiler/-/metro-hermes-compiler-0.72.3.tgz", + "integrity": "sha512-QWDQASMiXNW3j8uIQbzIzCdGYv5PpAX/ZiF4/lTWqKRWuhlkP4auhVY4eqdAKj5syPx45ggpjkVE0p8hAPDZYg==" }, "node_modules/metro-inspector-proxy": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.67.0.tgz", - "integrity": "sha512-5Ubjk94qpNaU3OT2IZa4/dec09bauic1hzWms4czorBzDenkp4kYXG9/aWTmgQLtCk92H3Q8jKl1PQRxUSkrOQ==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.72.3.tgz", + "integrity": "sha512-UPFkaq2k93RaOi+eqqt7UUmqy2ywCkuxJLasQ55+xavTUS+TQSyeTnTczaYn+YKw+izLTLllGcvqnQcZiWYhGw==", "dependencies": { "connect": "^3.6.5", "debug": "^2.2.0", @@ -10025,10 +8135,23 @@ "metro-inspector-proxy": "src/cli.js" } }, + "node_modules/metro-inspector-proxy/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/metro-inspector-proxy/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/metro-inspector-proxy/node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "engines": { "node": ">=8.3.0" }, @@ -10046,19 +8169,20 @@ } }, "node_modules/metro-minify-uglify": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.67.0.tgz", - "integrity": "sha512-4CmM5b3MTAmQ/yFEfsHOhD2SuBObB2YF6PKzXZc4agUsQVVtkrrNElaiWa8w26vrTzA9emwcyurxMf4Nl3lYPQ==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.72.3.tgz", + "integrity": "sha512-dPXqtMI8TQcj0g7ZrdhC8X3mx3m3rtjtMuHKGIiEXH9CMBvrET8IwrgujQw2rkPcXiSiX8vFDbGMIlfxefDsKA==", "dependencies": { "uglify-es": "^3.1.9" } }, "node_modules/metro-react-native-babel-preset": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.67.0.tgz", - "integrity": "sha512-tgTG4j0SKwLHbLRELMmgkgkjV1biYkWlGGKOmM484/fJC6bpDikdaFhfjsyE+W+qt7I5szbCPCickMTNQ+zwig==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.72.3.tgz", + "integrity": "sha512-uJx9y/1NIqoYTp6ZW1osJ7U5ZrXGAJbOQ/Qzl05BdGYvN1S7Qmbzid6xOirgK0EIT0pJKEEh1s8qbassYZe4cw==", "dependencies": { "@babel/core": "^7.14.0", + "@babel/plugin-proposal-async-generator-functions": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-export-default-from": "^7.0.0", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", @@ -10078,17 +8202,15 @@ "@babel/plugin-transform-destructuring": "^7.0.0", "@babel/plugin-transform-exponentiation-operator": "^7.0.0", "@babel/plugin-transform-flow-strip-types": "^7.0.0", - "@babel/plugin-transform-for-of": "^7.0.0", "@babel/plugin-transform-function-name": "^7.0.0", "@babel/plugin-transform-literals": "^7.0.0", "@babel/plugin-transform-modules-commonjs": "^7.0.0", - "@babel/plugin-transform-object-assign": "^7.0.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", "@babel/plugin-transform-parameters": "^7.0.0", "@babel/plugin-transform-react-display-name": "^7.0.0", "@babel/plugin-transform-react-jsx": "^7.0.0", "@babel/plugin-transform-react-jsx-self": "^7.0.0", "@babel/plugin-transform-react-jsx-source": "^7.0.0", - "@babel/plugin-transform-regenerator": "^7.0.0", "@babel/plugin-transform-runtime": "^7.0.0", "@babel/plugin-transform-shorthand-properties": "^7.0.0", "@babel/plugin-transform-spread": "^7.0.0", @@ -10104,16 +8226,16 @@ } }, "node_modules/metro-react-native-babel-transformer": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.67.0.tgz", - "integrity": "sha512-P0JT09n7T01epUtgL9mH6BPat3xn4JjBakl4lWHdL61cvEGcrxuIom1eoFFKkgU/K5AVLU4aCAttHS7nSFCcEQ==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.72.3.tgz", + "integrity": "sha512-Ogst/M6ujYrl/+9mpEWqE3zF7l2mTuftDTy3L8wZYwX1pWUQWQpfU1aJBeWiLxt1XlIq+uriRjKzKoRoIK57EA==", "dependencies": { "@babel/core": "^7.14.0", "babel-preset-fbjs": "^3.4.0", - "hermes-parser": "0.5.0", - "metro-babel-transformer": "0.67.0", - "metro-react-native-babel-preset": "0.67.0", - "metro-source-map": "0.67.0", + "hermes-parser": "0.8.0", + "metro-babel-transformer": "0.72.3", + "metro-react-native-babel-preset": "0.72.3", + "metro-source-map": "0.72.3", "nullthrows": "^1.1.1" }, "peerDependencies": { @@ -10121,29 +8243,33 @@ } }, "node_modules/metro-resolver": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.67.0.tgz", - "integrity": "sha512-d2KS/zAyOA/z/q4/ff41rAp+1txF4H6qItwpsls/RHStV2j6PqgRHUzq/3ga+VIeoUJntYJ8nGW3+3qSrhFlig==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.72.3.tgz", + "integrity": "sha512-wu9zSMGdxpKmfECE7FtCdpfC+vrWGTdVr57lDA0piKhZV6VN6acZIvqQ1yZKtS2WfKsngncv5VbB8Y5eHRQP3w==", "dependencies": { "absolute-path": "^0.0.0" } }, "node_modules/metro-runtime": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.67.0.tgz", - "integrity": "sha512-IFtSL0JUt1xK3t9IoLflTDft82bjieSzdIJWLzrRzBMlesz8ox5bVmnpQbVQEwfYUpEOxbM3VOZauVbdCmXA7g==" + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.72.3.tgz", + "integrity": "sha512-3MhvDKfxMg2u7dmTdpFOfdR71NgNNo4tzAyJumDVQKwnHYHN44f2QFZQqpPBEmqhWlojNeOxsqFsjYgeyMx6VA==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "react-refresh": "^0.4.0" + } }, "node_modules/metro-source-map": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.67.0.tgz", - "integrity": "sha512-yxypInsRo3SfS00IgTuL6a2W2tfwLY//vA2E+GeqGBF5zTbJZAhwNGIEl8S87XXZhwzJcxf5/8LjJC1YDzabww==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.72.3.tgz", + "integrity": "sha512-eNtpjbjxSheXu/jYCIDrbNEKzMGOvYW6/ePYpRM7gDdEagUOqKOCsi3St8NJIQJzZCsxD2JZ2pYOiomUSkT1yQ==", "dependencies": { "@babel/traverse": "^7.14.0", "@babel/types": "^7.0.0", "invariant": "^2.2.4", - "metro-symbolicate": "0.67.0", + "metro-symbolicate": "0.72.3", "nullthrows": "^1.1.1", - "ob1": "0.67.0", + "ob1": "0.72.3", "source-map": "^0.5.6", "vlq": "^1.0.0" } @@ -10151,18 +8277,18 @@ "node_modules/metro-source-map/node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "engines": { "node": ">=0.10.0" } }, "node_modules/metro-symbolicate": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.67.0.tgz", - "integrity": "sha512-ZqVVcfa0xSz40eFzA5P8pCF3V6Tna9RU1prFzAJTa3j9dCGqwh0HTXC8AIkMtgX7hNdZrCJI1YipzUBlwkT0/A==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.72.3.tgz", + "integrity": "sha512-eXG0NX2PJzJ/jTG4q5yyYeN2dr1cUqUaY7worBB0SP5bRWRc3besfb+rXwfh49wTFiL5qR0oOawkU4ZiD4eHXw==", "dependencies": { "invariant": "^2.2.4", - "metro-source-map": "0.67.0", + "metro-source-map": "0.72.3", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "through2": "^2.0.1", @@ -10178,15 +8304,15 @@ "node_modules/metro-symbolicate/node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "engines": { "node": ">=0.10.0" } }, "node_modules/metro-transform-plugins": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.67.0.tgz", - "integrity": "sha512-DQFoSDIJdTMPDTUlKaCNJjEXiHGwFNneAF9wDSJ3luO5gigM7t7MuSaPzF4hpjmfmcfPnRhP6AEn9jcza2Sh8Q==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.72.3.tgz", + "integrity": "sha512-D+TcUvCKZbRua1+qujE0wV1onZvslW6cVTs7dLCyC2pv20lNHjFr1GtW01jN2fyKR2PcRyMjDCppFd9VwDKnSg==", "dependencies": { "@babel/core": "^7.14.0", "@babel/generator": "^7.14.0", @@ -10195,191 +8321,144 @@ "nullthrows": "^1.1.1" } }, - "node_modules/metro-transform-worker": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.67.0.tgz", - "integrity": "sha512-29n+JdTb80ROiv/wDiBVlY/xRAF/nrjhp/Udv/XJl1DZb+x7JEiPxpbpthPhwwl+AYxVrostGB0W06WJ61hfiw==", - "dependencies": { - "@babel/core": "^7.14.0", - "@babel/generator": "^7.14.0", - "@babel/parser": "^7.14.0", - "@babel/types": "^7.0.0", - "babel-preset-fbjs": "^3.4.0", - "metro": "0.67.0", - "metro-babel-transformer": "0.67.0", - "metro-cache": "0.67.0", - "metro-cache-key": "0.67.0", - "metro-hermes-compiler": "0.67.0", - "metro-source-map": "0.67.0", - "metro-transform-plugins": "0.67.0", - "nullthrows": "^1.1.1" - } - }, - "node_modules/metro/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/metro/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/metro-transform-worker": { + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.72.3.tgz", + "integrity": "sha512-WsuWj9H7i6cHuJuy+BgbWht9DK5FOgJxHLGAyULD5FJdTG9rSMFaHDO5WfC0OwQU5h4w6cPT40iDuEGksM7+YQ==", "dependencies": { - "@types/yargs-parser": "*" + "@babel/core": "^7.14.0", + "@babel/generator": "^7.14.0", + "@babel/parser": "^7.14.0", + "@babel/types": "^7.0.0", + "babel-preset-fbjs": "^3.4.0", + "metro": "0.72.3", + "metro-babel-transformer": "0.72.3", + "metro-cache": "0.72.3", + "metro-cache-key": "0.72.3", + "metro-hermes-compiler": "0.72.3", + "metro-source-map": "0.72.3", + "metro-transform-plugins": "0.72.3", + "nullthrows": "^1.1.1" } }, - "node_modules/metro/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/metro/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/metro/node_modules/fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" - } - }, - "node_modules/metro/node_modules/jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "node_modules/metro/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "micromatch": "^4.0.4", - "walker": "^1.0.7" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/metro/node_modules/jest-haste-map/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "node_modules/metro/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 10.13.0" + "node": ">=7.0.0" } }, - "node_modules/metro/node_modules/jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } + "node_modules/metro/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/metro/node_modules/jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "node_modules/metro/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "ms": "2.0.0" } }, - "node_modules/metro/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "node_modules/metro/node_modules/fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha512-VerQV6vEKuhDWD2HGOybV6v5I73syoc/cXAbKlgTC7M/oFVEtklWlp9QH2Ijw3IaWDOQcMkldSPa7zXy79Z/UQ==", "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" } }, - "node_modules/metro/node_modules/jest-util/node_modules/ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==" + "node_modules/metro/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } }, "node_modules/metro/node_modules/jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", "optionalDependencies": { "graceful-fs": "^4.1.6" } }, + "node_modules/metro/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/metro/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/metro/node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "engines": { "node": ">=0.10.0" } }, - "node_modules/metro/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/metro/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=8" } }, "node_modules/metro/node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "engines": { "node": ">=8.3.0" }, @@ -10397,12 +8476,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" @@ -10437,30 +8516,30 @@ } }, "node_modules/mime-db": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", - "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", - "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.47.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" } }, "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/minimalistic-assert": { @@ -10471,7 +8550,7 @@ "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" }, "node_modules/minimatch": { "version": "3.1.2", @@ -10485,9 +8564,12 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mixin-deep": { "version": "1.3.2", @@ -10501,17 +8583,6 @@ "node": ">=0.10.0" } }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -10552,13 +8623,21 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "peer": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true, + "peer": true }, "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "engines": { "node": ">= 0.6" } @@ -10574,11 +8653,11 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, "node_modules/nocache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz", - "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/nocache/-/nocache-3.0.4.tgz", + "integrity": "sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==", "engines": { - "node": ">=4.0.0" + "node": ">=12.0.0" } }, "node_modules/node-dir": { @@ -10611,99 +8690,10 @@ } } }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" - }, - "node_modules/node-notifier": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", - "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", - "dev": true, - "optional": true, - "dependencies": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" - } - }, - "node_modules/node-notifier/node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "optional": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-notifier/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-notifier/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "optional": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/node-notifier/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "optional": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node_modules/node-releases": { "version": "2.0.6", @@ -10722,27 +8712,6 @@ "url": "https://github.com/sponsors/antelle" } }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -10754,7 +8723,7 @@ "node_modules/npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", "dependencies": { "path-key": "^2.0.0" }, @@ -10762,26 +8731,28 @@ "node": ">=4" } }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "engines": { + "node": ">=4" + } + }, "node_modules/nullthrows": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", - "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" - }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" }, "node_modules/ob1": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.67.0.tgz", - "integrity": "sha512-YvZtX8HKYackQ5PwdFIuuNFVsMChRPHvnARRRT0Vk59xsBvL5t9U1Ock3M1sYrKj+Gp73+0q9xcHLAxI+xLi5g==" + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.72.3.tgz", + "integrity": "sha512-OnVto25Sj7Ghp0vVm2THsngdze3tVq0LOg9LUHsAVXMecpqOP0Y8zaATW8M9gEgs2lNEAcCqV0P/hlmOPhVRvg==" }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "engines": { "node": ">=0.10.0" } @@ -10789,7 +8760,7 @@ "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dependencies": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", @@ -10802,7 +8773,7 @@ "node_modules/object-copy/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dependencies": { "is-descriptor": "^0.1.0" }, @@ -10810,10 +8781,53 @@ "node": ">=0.10.0" } }, + "node_modules/object-copy/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-copy/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { "is-buffer": "^1.1.5" }, @@ -10830,22 +8844,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -10855,18 +8853,10 @@ "node": ">= 0.4" } }, - "node_modules/object-path": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", - "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", - "engines": { - "node": ">= 10.12.0" - } - }, "node_modules/object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dependencies": { "isobject": "^3.0.0" }, @@ -10939,7 +8929,7 @@ "node_modules/object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dependencies": { "isobject": "^3.0.1" }, @@ -10967,7 +8957,7 @@ "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dependencies": { "ee-first": "1.1.1" }, @@ -10986,20 +8976,23 @@ "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dependencies": { "wrappy": "1" } }, "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dependencies": { - "mimic-fn": "^1.0.0" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">=4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/open": { @@ -11018,6 +9011,7 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, + "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -11031,128 +9025,133 @@ } }, "node_modules/ora": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", - "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dependencies": { - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-spinners": "^2.0.0", - "log-symbols": "^2.2.0", - "strip-ansi": "^5.2.0", + "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" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/ora/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/ora/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/ora/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/ora/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/ora/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/ora/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "engines": { "node": ">=0.10.0" } }, - "node_modules/p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", "engines": { "node": ">=4" } }, "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dependencies": { - "p-limit": "^2.2.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-try": { @@ -11173,6 +9172,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "peer": true, "dependencies": { "callsites": "^3.0.0" }, @@ -11180,15 +9180,6 @@ "node": ">=6" } }, - "node_modules/parent-module/node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/parse-asn1": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", @@ -11204,7 +9195,7 @@ "node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -11213,12 +9204,6 @@ "node": ">=4" } }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -11230,33 +9215,35 @@ "node_modules/pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", "engines": { "node": ">=0.10.0" } }, "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "engines": { "node": ">=0.10.0" } }, "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "peer": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/path-parse": { @@ -11264,12 +9251,25 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pbkdf2": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.8.tgz", - "integrity": "sha1-L4q/FuvsyCJ3lF10irodeHYfYeI=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "dependencies": { - "create-hmac": "^1.1.2" + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" }, "engines": { "node": ">=0.12" @@ -11281,9 +9281,9 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "engines": { "node": ">=8.6" }, @@ -11341,6 +9341,20 @@ "node": ">=6" } }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pkg-dir/node_modules/p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -11352,14 +9366,6 @@ "node": ">=6" } }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "engines": { - "node": ">=4" - } - }, "node_modules/pkg-up": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", @@ -11397,34 +9403,28 @@ "node": ">=6" } }, - "node_modules/pkg-up/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "dependencies": { - "p-limit": "^2.0.0" + "p-try": "^2.0.0" }, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/plist": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz", - "integrity": "sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==", + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, "dependencies": { - "base64-js": "^1.5.1", - "xmlbuilder": "^9.0.7" + "p-limit": "^2.0.0" }, "engines": { "node": ">=6" @@ -11433,7 +9433,7 @@ "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "engines": { "node": ">=0.10.0" } @@ -11443,6 +9443,7 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "peer": true, "engines": { "node": ">= 0.8.0" } @@ -11461,10 +9462,78 @@ "node": ">= 10" } }, - "node_modules/pretty-format/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/pretty-format/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/pretty-format/node_modules/@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pretty-format/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/pretty-format/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } @@ -11474,12 +9543,15 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "node_modules/pretty-format/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">= 0.6.0" + "node": ">=8" } }, "node_modules/process-nextick-args": { @@ -11496,9 +9568,9 @@ } }, "node_modules/prompts": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", - "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -11517,12 +9589,6 @@ "react-is": "^16.13.1" } }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -11551,17 +9617,13 @@ } }, "node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "peer": true, "engines": { - "node": ">=0.4.x" + "node": ">=6" } }, "node_modules/queue-microtask": { @@ -11610,30 +9672,29 @@ } }, "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.1.0.tgz", + "integrity": "sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-devtools-core": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.24.4.tgz", - "integrity": "sha512-jbX8Yqyq4YvFEobHyXVlGaH0Cs/+EOdb3PL911bxaR5BnzbB5TE4RFHC1iOgT4vRH3VxIIrVQ7lR9vsiFFCYCA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.24.0.tgz", + "integrity": "sha512-Rw7FzYOOzcfyUPaAm9P3g0tFdGqGq2LLiAI+wjYcp6CsF3DeeMrRS3HZAho4s273C29G/DJhx0e8BpRE/QZNGg==", "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" } }, "node_modules/react-devtools-core/node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "engines": { "node": ">=8.3.0" }, @@ -11650,27 +9711,6 @@ } } }, - "node_modules/react-i18next": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz", - "integrity": "sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==", - "dependencies": { - "@babel/runtime": "^7.14.5", - "html-parse-stringify": "^3.0.1" - }, - "peerDependencies": { - "i18next": ">= 19.0.0", - "react": ">= 16.8.0" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -11682,40 +9722,40 @@ "integrity": "sha512-txfpPCQYiazVdcbMRhatqWKcAxJweUu2wDXvts5/7Wyp6+Y9cHojqXHsLPEckzutfHlxZhG8Oiundbmp8Fd6eQ==" }, "node_modules/react-native": { - "version": "0.68.5", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.68.5.tgz", - "integrity": "sha512-t3kiQ/gumFV+0r/NRSIGtYxanjY4da0utFqHgkMcRPJVwXFWC0Fr8YiOeRGYO1dp8EfrSsOjtfWic/inqVYlbQ==", + "version": "0.70.7", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.70.7.tgz", + "integrity": "sha512-MvnJJXiEPuOBbf1VPY5WXIUR/n6QB/DAk5XtBz3bzinpy9YBXiiQkhGIrTpVdVt37JeHOzafhfxAMf+Rs8jpvA==", "dependencies": { "@jest/create-cache-key-function": "^27.0.1", - "@react-native-community/cli": "^7.0.3", - "@react-native-community/cli-platform-android": "^7.0.1", - "@react-native-community/cli-platform-ios": "^7.0.1", + "@react-native-community/cli": "9.3.2", + "@react-native-community/cli-platform-android": "9.3.1", + "@react-native-community/cli-platform-ios": "9.3.0", "@react-native/assets": "1.0.0", "@react-native/normalize-color": "2.0.0", "@react-native/polyfills": "2.0.0", "abort-controller": "^3.0.0", "anser": "^1.4.9", "base64-js": "^1.1.2", - "deprecated-react-native-prop-types": "^2.3.0", "event-target-shim": "^5.0.1", - "hermes-engine": "~0.11.0", "invariant": "^2.2.4", "jsc-android": "^250230.2.1", - "metro-react-native-babel-transformer": "0.67.0", - "metro-runtime": "0.67.0", - "metro-source-map": "0.67.0", + "memoize-one": "^5.0.0", + "metro-react-native-babel-transformer": "0.72.3", + "metro-runtime": "0.72.3", + "metro-source-map": "0.72.3", + "mkdirp": "^0.5.1", "nullthrows": "^1.1.1", "pretty-format": "^26.5.2", - "promise": "^8.2.0", - "react-devtools-core": "^4.23.0", - "react-native-codegen": "^0.0.18", - "react-native-gradle-plugin": "^0.0.6", + "promise": "^8.3.0", + "react-devtools-core": "4.24.0", + "react-native-codegen": "^0.70.6", + "react-native-gradle-plugin": "^0.70.3", "react-refresh": "^0.4.0", - "react-shallow-renderer": "16.14.1", + "react-shallow-renderer": "^16.15.0", "regenerator-runtime": "^0.13.2", - "scheduler": "^0.20.2", + "scheduler": "^0.22.0", "stacktrace-parser": "^0.1.3", - "use-subscription": ">=1.0.0 <1.6.0", + "use-sync-external-store": "^1.0.0", "whatwg-fetch": "^3.0.0", "ws": "^6.1.4" }, @@ -11726,7 +9766,7 @@ "node": ">=14" }, "peerDependencies": { - "react": "17.0.2" + "react": "18.1.0" } }, "node_modules/react-native-background-timer": { @@ -11737,22 +9777,10 @@ "react-native": ">=0.47.0" } }, - "node_modules/react-native-clean-project": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/react-native-clean-project/-/react-native-clean-project-4.0.1.tgz", - "integrity": "sha512-B7rXdFC4bfA+Vv7lZ9bKS6cUDgqg04OR5D69sNnhheFBJQ1V04cIfJ1Fu0sbqRsIehqlOcySQRpp8tm7r7PvLQ==", - "dev": true, - "bin": { - "react-native-clean-project": "source/index.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/react-native-codegen": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.0.18.tgz", - "integrity": "sha512-XPI9aVsFy3dvgDZvyGWrFnknNiyb22kg5nHgxa0vjWTH9ENLBgVRZt9A64xHZ8BYihH+gl0p/1JNOCIEUzRPBg==", + "version": "0.70.6", + "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.70.6.tgz", + "integrity": "sha512-kdwIhH2hi+cFnG5Nb8Ji2JwmcCxnaOOo9440ov7XDzSvGfmUStnCzl+MCW8jLjqHcE4icT7N9y+xx4f50vfBTw==", "dependencies": { "@babel/parser": "^7.14.0", "flow-parser": "^0.121.0", @@ -11760,29 +9788,6 @@ "nullthrows": "^1.1.1" } }, - "node_modules/react-native-crypto": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/react-native-crypto/-/react-native-crypto-2.2.0.tgz", - "integrity": "sha512-eZu9Y8pa8BN9FU2pIex7MLRAi+Cd1Y6bsxfiufKh7sfraAACJvjQTeW7/zcQAT93WMfM+D0OVk+bubvkrbrUkw==", - "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.4", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "3.0.8", - "public-encrypt": "^4.0.0", - "randomfill": "^1.0.3" - }, - "engines": { - "node": "*" - }, - "peerDependencies": { - "react-native-randombytes": ">=2.0.0 <4.0.0" - } - }, "node_modules/react-native-exception-handler": { "version": "2.10.10", "resolved": "https://registry.npmjs.org/react-native-exception-handler/-/react-native-exception-handler-2.10.10.tgz", @@ -11811,14 +9816,14 @@ } }, "node_modules/react-native-gradle-plugin": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.0.6.tgz", - "integrity": "sha512-eIlgtsmDp1jLC24dRn43hB3kEcZVqx6DUQbR0N1ABXGnMEafm9I3V3dUUeD1vh+Dy5WqijSoEwLNUPLgu5zDMg==" + "version": "0.70.3", + "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz", + "integrity": "sha512-oOanj84fJEXUg9FoEAQomA8ISG+DVIrTZ3qF7m69VQUJyOGYyDZmPqKcjvRku4KXlEH6hWO9i4ACLzNBh8gC0A==" }, "node_modules/react-native-navigation": { - "version": "7.30.3", - "resolved": "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-7.30.3.tgz", - "integrity": "sha512-4XTeq60YxAsp8zeUeIMedUduQ9blUjPlhAgxKCj5ekam5GoHwqq7iKtQr43+rYbOp0+eATGAqdZ8H/+ZXP9EFw==", + "version": "7.32.1", + "resolved": "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-7.32.1.tgz", + "integrity": "sha512-qqpccWh6MqTG0hn/XeggKonSYg+h64kOsYBot/+g2EUC/Usp8TZsKi1B2gzsUrDQy8EmsF9iTBoZMIgjxFG/WQ==", "dependencies": { "hoist-non-react-statics": "3.x.x", "lodash": "4.17.x", @@ -11846,45 +9851,53 @@ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" }, "node_modules/react-native-pager-view": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.1.2.tgz", - "integrity": "sha512-qs2KSFc+7N7B+UZ6SG2sTvCkppagm5fVyRclv1KFKc7lDtrhXLzN59tXJw575LDP/dRJoXsNwqUAhZJdws6ABQ==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.1.4.tgz", + "integrity": "sha512-fmTwgGwPxGCBusKAq7gHzm+s1Yp0qh5rKPoQszaCuxrb+76KgK4Qe82jJNPUp2xTZOKSw+FbJU2QahF8ncTl+w==", "peerDependencies": { "react": "*", "react-native": "*" } }, - "node_modules/react-native-randombytes": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/react-native-randombytes/-/react-native-randombytes-3.6.1.tgz", - "integrity": "sha512-qxkwMbOZ0Hff1V7VqpaWrR6ItkA+oF6bnI79Qp9F3Tk8WBsdKDi6m1mi3dEdFWePoRLrhJ2L03rU0yabst1tVw==", + "node_modules/react-native-quick-base64": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/react-native-quick-base64/-/react-native-quick-base64-2.0.5.tgz", + "integrity": "sha512-waRcIlchdLCSzpWYqRNIN5NyE5PxKyedMQ/sTgA/fcEkBzwp3EOwjhsfVuJuBtc1bHL2Mg34pxDVBxyLU3Mu2Q==", "dependencies": { - "buffer": "^4.9.1", - "sjcl": "^1.0.3" + "base64-js": "^1.5.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" } }, - "node_modules/react-native-randombytes/node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "node_modules/react-native-quick-crypto": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/react-native-quick-crypto/-/react-native-quick-crypto-0.5.0.tgz", + "integrity": "sha512-NYc8r97UaKOfkHj0iyM8OD+S5U+8mTKheb/BYpu7CNJ0qt1VkwFEaWkJtOUWSRbyd24d0AKrC9+97UkroBs9JA==", "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/react-native-splash-screen": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/react-native-splash-screen/-/react-native-splash-screen-3.3.0.tgz", - "integrity": "sha512-rGjt6HkoSXxMqH4SQUJ1gnPQlPJV8+J47+4yhgTIan4bVvAwJhEeJH7wWt9hXSdH4+VfwTS0GTaflj1Tw83IhA==", + "@craftzdog/react-native-buffer": "^6.0.4", + "@types/node": "^17.0.31", + "crypto-browserify": "^3.12.0", + "events": "^3.3.0", + "react-native-quick-base64": "^2.0.2", + "stream-browserify": "^3.0.0", + "string_decoder": "^1.3.0" + }, "peerDependencies": { - "react-native": ">=0.57.0" + "react": "*", + "react-native": "*" } }, + "node_modules/react-native-quick-crypto/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + }, "node_modules/react-native-track-player": { "version": "2.1.2", - "resolved": "git+ssh://git@github.com/lyswhut/react-native-track-player.git#5fb0bec8694d3783f32a1e4ed1251c163e9842f7", - "integrity": "sha512-n48QN+6YlCXRyzkBy6h5zal9jBNoTC4ti5r2sbH+9oVcYFR1r9grjKw24B9m/1tL2gdeLj/OuoPD9l5HpUF2ZA==", + "resolved": "git+ssh://git@github.com/lyswhut/react-native-track-player.git#38027954a5ac6e3d92961745e0a9633fc647f47a", + "integrity": "sha512-WLUJIbfNPTudwEhr8D70U0kwg3sQsivdFHCGjiq9ko44PmxlINFty+0g1/DmFdWZOAKUrq8y3/e6S+Uj7Uv7Bw==", "license": "Apache-2.0", "peerDependencies": { "react": ">=16.8.6", @@ -11910,12 +9923,18 @@ "generate-icon": "bin/generate-icon.js" } }, - "node_modules/react-native-vector-icons/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/react-native-vector-icons/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/react-native-vector-icons/node_modules/cliui": { @@ -11928,17 +9947,22 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/react-native-vector-icons/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/react-native-vector-icons/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "ansi-regex": "^5.0.1" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8" + "node": ">=7.0.0" } }, + "node_modules/react-native-vector-icons/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/react-native-vector-icons/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -11988,49 +10012,6 @@ "node": ">=10" } }, - "node_modules/react-redux": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", - "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", - "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", - "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", - "use-sync-external-store": "^1.0.0" - }, - "peerDependencies": { - "@types/react": "^16.8 || ^17.0 || ^18.0", - "@types/react-dom": "^16.8 || ^17.0 || ^18.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0", - "react-native": ">=0.59", - "redux": "^4" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, - "node_modules/react-redux/node_modules/react-is": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.0.0.tgz", - "integrity": "sha512-yUcBYdBBbo3QiPsgYDcfQcIkGZHfxOaoE6HLSnr1sPzMhdyxusbfKOSUbSd/ocGi32dxcj366PsTj+5oggeKKw==" - }, "node_modules/react-refresh": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz", @@ -12040,63 +10021,34 @@ } }, "node_modules/react-shallow-renderer": { - "version": "16.14.1", - "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz", - "integrity": "sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==", - "dependencies": { - "object-assign": "^4.1.1", - "react-is": "^16.12.0 || ^17.0.0" - }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0" - } - }, - "node_modules/react-test-renderer": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz", - "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==", - "dev": true, + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", "dependencies": { "object-assign": "^4.1.1", - "react-is": "^17.0.2", - "react-shallow-renderer": "^16.13.1", - "scheduler": "^0.20.2" + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" }, "peerDependencies": { - "react": "17.0.2" + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/react-test-renderer/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, "node_modules/readable-stream": { - "version": "1.0.33", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", - "integrity": "sha1-OjYN1mwbHX/UcFOJhg7aHQ9hEmw=", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/readable-stream/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/readable-stream/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "node_modules/readline": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", - "integrity": "sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw=" + "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==" }, "node_modules/recast": { "version": "0.20.5", @@ -12120,39 +10072,6 @@ "node": ">=0.10.0" } }, - "node_modules/redux": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", - "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, - "node_modules/redux-logger": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz", - "integrity": "sha1-91VZZvMJjzyIYExEnPC69XeCdL8=", - "dev": true, - "dependencies": { - "deep-diff": "^0.3.5" - } - }, - "node_modules/redux-subscriber": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/redux-subscriber/-/redux-subscriber-1.1.0.tgz", - "integrity": "sha1-PKwopnTOwHtungFcp6q7vawVVUM=", - "dependencies": { - "object-path": "^0.11.3" - } - }, - "node_modules/redux-thunk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", - "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", - "peerDependencies": { - "redux": "^4" - } - }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -12178,6 +10097,7 @@ "version": "0.15.0", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "peer": true, "dependencies": { "@babel/runtime": "^7.8.4" } @@ -12212,10 +10132,11 @@ } }, "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, + "peer": true, "engines": { "node": ">=8" }, @@ -12263,18 +10184,6 @@ "jsesc": "bin/jsesc" } }, - "node_modules/remove-markdown": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/remove-markdown/-/remove-markdown-0.2.2.tgz", - "integrity": "sha1-ZrDO66n7d8qWNrsbAwfOIaMqEqY=", - "dev": true - }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, "node_modules/repeat-element": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", @@ -12286,7 +10195,7 @@ "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "engines": { "node": ">=0.10" } @@ -12294,7 +10203,7 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "engines": { "node": ">=0.10.0" } @@ -12307,49 +10216,31 @@ "node_modules/reselect": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", - "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==" + "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==", + "dev": true }, "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dependencies": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.9.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" + "bin": { + "resolve": "bin/resolve" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "peer": true, "engines": { "node": ">=4" } @@ -12357,19 +10248,19 @@ "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", "deprecated": "https://github.com/lydell/resolve-url#deprecated" }, "node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dependencies": { - "onetime": "^2.0.0", + "onetime": "^5.1.0", "signal-exit": "^3.0.2" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/ret": { @@ -12391,14 +10282,19 @@ } }, "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/ripemd160": { @@ -12410,64 +10306,6 @@ "inherits": "^2.0.1" } }, - "node_modules/rn-nodeify": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/rn-nodeify/-/rn-nodeify-10.3.0.tgz", - "integrity": "sha512-EZB3M4M5i8yySCWF7AAZ31xU7cpdLuIKMlVxXji9t0aY8Ojy3BAyRt1sTp0OwBgy1ejShmlIu2L4f8mToJ+uvg==", - "dev": true, - "dependencies": { - "@yarnpkg/lockfile": "^1.0.0", - "deep-equal": "^1.0.0", - "findit": "^2.0.0", - "fs-extra": "^0.22.1", - "minimist": "^1.1.2", - "object.pick": "^1.1.1", - "run-parallel": "^1.1.2", - "semver": "^5.0.1", - "xtend": "^4.0.0" - }, - "bin": { - "rn-nodeify": "cmd.js" - } - }, - "node_modules/rn-nodeify/node_modules/fs-extra": { - "version": "0.22.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.22.1.tgz", - "integrity": "sha1-X9b4BJ3JdsoZ6yNV1lgXPKvM4FY=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "rimraf": "^2.2.8" - } - }, - "node_modules/rn-nodeify/node_modules/jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/rn-nodeify/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true, - "engines": { - "node": "6.* || >= 7.*" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -12499,7 +10337,7 @@ "node_modules/safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dependencies": { "ret": "~0.1.10" } @@ -12523,197 +10361,12 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "deprecated": "some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added", - "dev": true, - "dependencies": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "bin": { - "sane": "src/cli.js" - }, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/sane/node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/sane/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.22.0.tgz", + "integrity": "sha512-6QAm1BgQI88NPYymgGQLCZgvep4FyePDWFpXVK+zNSUgHwlqpJy8VEh8Et0KxTACS4VWwMousBElAZOH9nkkoQ==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "node_modules/semver": { @@ -12747,6 +10400,19 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/send/node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -12785,7 +10451,7 @@ "node_modules/serialize-error": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", - "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", "engines": { "node": ">=0.10.0" } @@ -12807,7 +10473,7 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "node_modules/set-value": { "version": "2.0.1", @@ -12826,7 +10492,7 @@ "node_modules/set-value/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dependencies": { "is-extendable": "^0.1.0" }, @@ -12834,6 +10500,14 @@ "node": ">=0.10.0" } }, + "node_modules/set-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -12863,42 +10537,36 @@ } }, "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "peer": true, "dependencies": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "dependencies": { - "array-filter": "~0.0.0", - "array-map": "~0.0.0", - "array-reduce": "~0.0.0", - "jsonify": "~0.0.0" + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz", + "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true - }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -12914,33 +10582,15 @@ } }, "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" - }, - "node_modules/simple-plist": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz", - "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==", - "dependencies": { - "bplist-creator": "0.1.0", - "bplist-parser": "0.3.1", - "plist": "^3.0.5" - } + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, - "node_modules/sjcl": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.8.tgz", - "integrity": "sha512-LzIjEQ0S0DpIgnxMEayM1rq9aGwGRG4OnZhCdjx7glTaJtf4zRfpg87ImfjSJjoW9vKpagd82McDOwbRT5kQKQ==", - "engines": { - "node": "*" - } - }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -12962,30 +10612,6 @@ "node": ">=6" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -13020,7 +10646,7 @@ "node_modules/snapdragon-node/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dependencies": { "is-descriptor": "^1.0.0" }, @@ -13028,56 +10654,73 @@ "node": ">=0.10.0" } }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dependencies": { - "kind-of": "^6.0.0" + "kind-of": "^3.2.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { - "kind-of": "^6.0.0" + "is-buffer": "^1.1.5" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dependencies": { - "kind-of": "^3.2.0" + "is-extendable": "^0.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/snapdragon-util/node_modules/kind-of": { + "node_modules/snapdragon/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { "is-buffer": "^1.1.5" }, @@ -13085,57 +10728,84 @@ "node": ">=0.10.0" } }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "node_modules/snapdragon/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dependencies": { - "is-descriptor": "^0.1.0" + "kind-of": "^3.0.2" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { - "is-extendable": "^0.1.0" + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "engines": { "node": ">=0.10.0" } }, + "node_modules/snapdragon/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/snapdragon/node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "engines": { "node": ">=0.10.0" } }, - "node_modules/socket.io": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.4.tgz", - "integrity": "sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ==", + "node_modules/socket.io-client": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.6.0.tgz", + "integrity": "sha512-2XOp18xnGghUICSd5ziUIS4rB0dhr6S8OvAps8y+HhOjFQlqGcf+FIh6fCIsKKZyWFxJeFPrZRNPGsHDTsz1Ug==", "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", - "engine.io": "~6.2.1", - "socket.io-adapter": "~2.4.0", + "engine.io-client": "~6.4.0", "socket.io-parser": "~4.2.1" }, "engines": { "node": ">=10.0.0" } }, - "node_modules/socket.io-adapter": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", - "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==" - }, "node_modules/socket.io-parser": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", @@ -13148,42 +10818,10 @@ "node": ">=10.0.0" } }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "engines": { "node": ">= 8" } @@ -13202,9 +10840,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -13224,38 +10862,6 @@ "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "deprecated": "See https://github.com/lydell/source-map-url#deprecated" }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, "node_modules/split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -13270,33 +10876,12 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/stackframe": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.1.tgz", - "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==" + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" }, "node_modules/stacktrace-parser": { "version": "0.1.10", @@ -13312,7 +10897,7 @@ "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "dependencies": { "define-property": "^0.2.5", "object-copy": "^0.1.0" @@ -13324,7 +10909,7 @@ "node_modules/static-extend/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dependencies": { "is-descriptor": "^0.1.0" }, @@ -13332,94 +10917,128 @@ "node": ">=0.10.0" } }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "node_modules/static-extend/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/stream-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-1.0.0.tgz", - "integrity": "sha1-v5tKv7QrJ011FHnkTg/yZWtvEZM=", + "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "^1.0.27-1" + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/stream-buffers": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", - "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=", + "node_modules/static-extend/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, "engines": { - "node": ">= 0.10.0" + "node": ">=0.10.0" } }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { - "safe-buffer": "~5.1.0" + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/string-length/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, + "node_modules/static-extend/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/string-length/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "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==", + "dependencies": { + "safe-buffer": "~5.2.0" } }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, "node_modules/string-width/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -13428,17 +11047,6 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string.prototype.matchall": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", @@ -13459,49 +11067,50 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dependencies": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "peer": true, "engines": { "node": ">=4" } @@ -13509,25 +11118,17 @@ "node_modules/strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", "engines": { "node": ">=0.10.0" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "peer": true, "engines": { "node": ">=8" }, @@ -13541,27 +11142,14 @@ "integrity": "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==" }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -13575,16 +11163,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, "node_modules/temp": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", - "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", + "integrity": "sha512-jtnWJs6B1cZlHs9wPG7BrowKxZw/rf6+UpGAkr8AaYmiTyTO7zQlLoST8zx/8TcUPnZmeBoB+H8ARuHZaSijVw==", "engines": [ "node >=0.8.0" ], @@ -13596,46 +11178,17 @@ "node_modules/temp/node_modules/rimraf": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", "bin": { "rimraf": "bin.js" } }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "peer": true }, "node_modules/throat": { "version": "5.0.0", @@ -13665,6 +11218,14 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -13673,7 +11234,7 @@ "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "engines": { "node": ">=4" } @@ -13681,7 +11242,7 @@ "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dependencies": { "kind-of": "^3.0.2" }, @@ -13692,7 +11253,7 @@ "node_modules/to-object-path/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { "is-buffer": "^1.1.5" }, @@ -13733,55 +11294,17 @@ "node": ">=0.6" } }, - "node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie/node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tr46/node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, + "peer": true, "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.1", @@ -13790,10 +11313,11 @@ } }, "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, + "peer": true, "dependencies": { "minimist": "^1.2.0" }, @@ -13806,11 +11330,33 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "peer": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -13818,15 +11364,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/type-fest": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", @@ -13835,13 +11372,17 @@ "node": ">=8" } }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" } }, "node_modules/uglify-es": { @@ -13938,6 +11479,14 @@ "node": ">=0.10.0" } }, + "node_modules/union-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -13949,7 +11498,7 @@ "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "engines": { "node": ">= 0.8" } @@ -13957,7 +11506,7 @@ "node_modules/unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dependencies": { "has-value": "^0.3.1", "isobject": "^3.0.0" @@ -13969,7 +11518,7 @@ "node_modules/unset-value/node_modules/has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", "dependencies": { "get-value": "^2.0.3", "has-values": "^0.1.4", @@ -13982,7 +11531,7 @@ "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "dependencies": { "isarray": "1.0.0" }, @@ -13993,15 +11542,15 @@ "node_modules/unset-value/node_modules/has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", "engines": { "node": ">=0.10.0" } }, "node_modules/update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "funding": [ { "type": "opencollective", @@ -14028,34 +11577,17 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "peer": true, "dependencies": { "punycode": "^2.1.0" } }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", "deprecated": "Please see https://github.com/lydell/urix#deprecated" }, - "node_modules/url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, "node_modules/use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -14064,23 +11596,12 @@ "node": ">=0.10.0" } }, - "node_modules/use-subscription": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz", - "integrity": "sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA==", - "dependencies": { - "object-assign": "^4.1.1" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0" - } - }, "node_modules/use-sync-external-store": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.0.0.tgz", - "integrity": "sha512-AFVsxg5GkFg8GDcxnl+Z0lMAz9rE8DGJCc28qnBuQF7lac57B5smLcT37aXpXIIPz75rW4g3eXHPjhHwdGskOw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0-rc" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/utf8": { @@ -14088,174 +11609,81 @@ "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" }, - "node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dependencies": { - "inherits": "2.0.3" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "engines": { "node": ">= 0.4.0" } - }, - "node_modules/uuid": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", - "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-to-istanbul": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", - "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vlq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", - "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==" - }, - "node_modules/void-elements": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "engines": { - "node": ">=10" + "node": ">= 0.8" } }, + "node_modules/vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==" + }, "node_modules/walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dependencies": { - "makeerror": "1.0.x" + "makeerror": "1.0.12" } }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dependencies": { "defaults": "^1.0.3" } }, "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatwg-fetch": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "peer": true, "dependencies": { "isexe": "^2.0.0" }, "bin": { - "which": "bin/which" + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, "node_modules/which-boxed-primitive": { @@ -14277,13 +11705,14 @@ "node_modules/which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -14301,29 +11730,40 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "ansi-regex": "^5.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8" + "node": ">=7.0.0" } }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "2.4.3", @@ -14343,44 +11783,12 @@ "async-limiter": "~1.0.0" } }, - "node_modules/xcode": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", - "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", - "dependencies": { - "simple-plist": "^1.1.0", - "uuid": "^7.0.3" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", "engines": { - "node": ">=4.0" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/xmldoc": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-1.1.2.tgz", - "integrity": "sha512-ruPC/fyPNck2BD1dpz0AZZyrEwMOrWTO5lDdIXS91rs3wtm4j+T8Rp2o+zoOYkkAxJTZRPOSnOGei1egoRmKMQ==", - "dependencies": { - "sax": "^1.2.1" + "node": ">=0.4.0" } }, "node_modules/xtend": { @@ -14435,11 +11843,74 @@ "node": ">=6" } }, + "node_modules/yargs-parser/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, "engines": { "node": ">=10" }, @@ -14450,11 +11921,12 @@ }, "dependencies": { "@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "requires": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" } }, "@babel/code-frame": { @@ -14466,69 +11938,52 @@ } }, "@babel/compat-data": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", - "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==" + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", + "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==" }, "@babel/core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz", - "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==", + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.0", - "@babel/helper-module-transforms": "^7.20.2", - "@babel/helpers": "^7.20.5", - "@babel/parser": "^7.20.5", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - } - } - }, - "@babel/eslint-parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", - "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", - "dev": true, - "requires": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", + "json5": "^2.2.2", "semver": "^6.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } } }, "@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", "requires": { - "@babel/types": "^7.20.5", + "@babel/types": "^7.20.7", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } } }, "@babel/helper-annotate-as-pure": { @@ -14549,14 +12004,30 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", "requires": { - "@babel/compat-data": "^7.20.0", + "@babel/compat-data": "^7.20.5", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", "semver": "^6.3.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } } }, "@babel/helper-create-class-features-plugin": { @@ -14583,28 +12054,16 @@ } }, "@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", - "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", "semver": "^6.1.2" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - } } }, "@babel/helper-environment-visitor": { @@ -14654,18 +12113,18 @@ } }, "@babel/helper-module-transforms": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", - "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", "requires": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.2" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" } }, "@babel/helper-optimise-call-expression": { @@ -14755,13 +12214,13 @@ } }, "@babel/helpers": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", - "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", + "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7" } }, "@babel/highlight": { @@ -14772,58 +12231,12 @@ "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } } }, "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==" + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", @@ -14849,7 +12262,6 @@ "version": "7.20.1", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz", "integrity": "sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g==", - "peer": true, "requires": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-plugin-utils": "^7.19.0", @@ -14888,12 +12300,12 @@ } }, "@babel/plugin-proposal-export-default-from": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.14.5.tgz", - "integrity": "sha512-T8KZ5abXvKMjF6JcoXjgac3ElmXf0AWzJwi2O/42Jk+HmCky3D9+i1B7NPP1FblyceqTevKeV/9szeikFoaMDg==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.18.10.tgz", + "integrity": "sha512-5H2N3R2aQFxkV4PIBUR/i7PUSwgTZjouJKzI8eKswfIjT0PhvzkPn0t0wIS5zn6maQuvtT0t1oHtMUz61LOuow==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-export-default-from": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-default-from": "^7.18.6" } }, "@babel/plugin-proposal-export-namespace-from": { @@ -15015,15 +12427,6 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, "@babel/plugin-syntax-class-properties": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", @@ -15050,11 +12453,11 @@ } }, "@babel/plugin-syntax-export-default-from": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.14.5.tgz", - "integrity": "sha512-snWDxjuaPEobRBnhpqEfZ8RMxDbHt8+87fiEioGuE+Uc0xAKgSD8QiuL3lF93hPVQfZFAcYwrrf+H5qUhike3Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.18.6.tgz", + "integrity": "sha512-Kr//z3ujSVNx6E9z9ih5xXXMqK07VVTuqPmqGe6Mss/zW5XPeLZeSDZoP9ab/hT4wPKqAgjl2PnhPrcpk8Seew==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-syntax-export-namespace-from": { @@ -15082,35 +12485,28 @@ "@babel/helper-plugin-utils": "^7.19.0" } }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, "@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-jsx": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz", - "integrity": "sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -15127,6 +12523,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -15168,6 +12565,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" } @@ -15363,7 +12761,6 @@ "version": "7.19.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", - "peer": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.19.0", "@babel/helper-plugin-utils": "^7.19.0" @@ -15378,14 +12775,6 @@ "@babel/helper-plugin-utils": "^7.18.6" } }, - "@babel/plugin-transform-object-assign": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.14.5.tgz", - "integrity": "sha512-lvhjk4UN9xJJYB1mI5KC0/o1D5EcJXdbhVe+4fSk08D6ZN+iuAIs7LJC+71h8av9Ew4+uRq9452v9R93SFmQlQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, "@babel/plugin-transform-object-super": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", @@ -15412,45 +12801,46 @@ } }, "@babel/plugin-transform-react-display-name": { - "version": "7.15.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.15.1.tgz", - "integrity": "sha512-yQZ/i/pUCJAHI/LbtZr413S3VT26qNrEm0M5RRxQJA947/YNYwbZbBaXGDrq6CG5QsZycI1VIP6d7pQaBfP+8Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", + "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-react-jsx": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.9.tgz", - "integrity": "sha512-30PeETvS+AeD1f58i1OVyoDlVYQhap/K20ZrMjLmmzmC2AYR/G43D4sdJAaDAqCD3MYpSWbmrz3kES158QSLjw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz", + "integrity": "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==", "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-jsx": "^7.14.5", - "@babel/types": "^7.14.9" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.19.0" } }, "@babel/plugin-transform-react-jsx-self": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.14.9.tgz", - "integrity": "sha512-Fqqu0f8zv9W+RyOnx29BX/RlEsBRANbOf5xs5oxb2aHP4FKbLXxIaVPUiCti56LAR1IixMH4EyaixhUsKqoBHw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz", + "integrity": "sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-react-jsx-source": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.14.5.tgz", - "integrity": "sha512-1TpSDnD9XR/rQ2tzunBVPThF5poaYT9GqP+of8fAtguYuI/dm2RkrMBDemsxtY0XBzvW7nXjYM0hRyKX9QYj7Q==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz", + "integrity": "sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-regenerator": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.18.6", "regenerator-transform": "^0.15.0" @@ -15466,15 +12856,15 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz", - "integrity": "sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw==", - "requires": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", - "babel-plugin-polyfill-regenerator": "^0.2.2", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", "semver": "^6.3.0" } }, @@ -15629,61 +13019,6 @@ "babel-plugin-polyfill-regenerator": "^0.4.1", "core-js-compat": "^3.25.1", "semver": "^6.3.0" - }, - "dependencies": { - "@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "peer": true, - "requires": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - } - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "peer": true, - "requires": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "peer": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "peer": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "peer": true, - "requires": { - "ms": "2.1.2" - } - } } }, "@babel/preset-flow": { @@ -15732,74 +13067,57 @@ } }, "@babel/runtime": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz", - "integrity": "sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", "requires": { "regenerator-runtime": "^0.13.11" } }, "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" } }, "@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", + "@babel/generator": "^7.20.7", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", "debug": "^4.1.0", "globals": "^11.1.0" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - } } }, "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", "requires": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "dev": true, + "@craftzdog/react-native-buffer": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@craftzdog/react-native-buffer/-/react-native-buffer-6.0.5.tgz", + "integrity": "sha512-Av+YqfwA9e7jhgI9GFE/gTpwl/H+dRRLmZyJPOpKTy107j9Oj7oXlm3/YiMNz+C/CEGqcKAOqnXDLs4OL6AAFw==", "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" + "ieee754": "^1.2.1", + "react-native-quick-base64": "^2.0.5" } }, "@eslint/eslintrc": { @@ -15807,6 +13125,7 @@ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", "dev": true, + "peer": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -15819,440 +13138,142 @@ "strip-json-comments": "^3.1.1" }, "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "globals": { "version": "13.17.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, + "peer": true, "requires": { "type-fest": "^0.20.2" - } - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } - } - }, - "@hapi/hoek": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", - "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==" - }, - "@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@humanwhocodes/config-array": { - "version": "0.11.6", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.6.tgz", - "integrity": "sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - } - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "@jest/create-cache-key-function": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz", - "integrity": "sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==", - "requires": { - "@jest/types": "^27.5.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - } - }, - "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - } - }, - "@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", - "dev": true, - "requires": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" - } - }, - "@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "node-notifier": "^8.0.0", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "peer": true } } }, - "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, + "@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@hapi/hoek": "^9.0.0" } }, - "@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "@humanwhocodes/config-array": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", + "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", "dev": true, + "peer": true, "requires": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" } }, - "@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "peer": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true, + "peer": true + }, + "@jest/create-cache-key-function": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz", + "integrity": "sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==", "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - } + "@jest/types": "^27.5.1" } }, "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^15.0.0", + "@types/yargs": "^16.0.0", "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" }, "@jridgewell/set-array": { "version": "1.1.2", @@ -16260,26 +13281,17 @@ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" }, "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "@jridgewell/trace-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", - "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", - "dev": true, + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "requires": { - "eslint-scope": "5.1.1" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "@nodelib/fs.scandir": { @@ -16329,365 +13341,601 @@ "requires": {} }, "@react-native-community/cli": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-7.0.3.tgz", - "integrity": "sha512-WyJOA829KAhU1pw2MDQt0YhOS9kyR2KqyqgJyTuQhzFVCBPX4F5aDEkZYYn4jdldaDHCPrLJ3ho3gxYTXy+x7w==", - "requires": { - "@react-native-community/cli-debugger-ui": "^7.0.3", - "@react-native-community/cli-hermes": "^6.3.0", - "@react-native-community/cli-plugin-metro": "^7.0.3", - "@react-native-community/cli-server-api": "^7.0.3", - "@react-native-community/cli-tools": "^6.2.0", - "@react-native-community/cli-types": "^6.0.0", - "appdirsjs": "^1.2.4", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-9.3.2.tgz", + "integrity": "sha512-IAW4X0vmX/xozNpp/JVZaX7MrC85KV0OP2DF4o7lNGOfpUhzJAEWqTfkxFYS+VsRjZHDve4wSTiGIuXwE7FG1w==", + "requires": { + "@react-native-community/cli-clean": "^9.2.1", + "@react-native-community/cli-config": "^9.2.1", + "@react-native-community/cli-debugger-ui": "^9.0.0", + "@react-native-community/cli-doctor": "^9.3.0", + "@react-native-community/cli-hermes": "^9.3.1", + "@react-native-community/cli-plugin-metro": "^9.2.1", + "@react-native-community/cli-server-api": "^9.2.1", + "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-types": "^9.1.0", "chalk": "^4.1.2", - "command-exists": "^1.2.8", - "commander": "^2.19.0", - "cosmiconfig": "^5.1.0", - "deepmerge": "^3.2.0", - "envinfo": "^7.7.2", + "commander": "^9.4.0", "execa": "^1.0.0", "find-up": "^4.1.0", "fs-extra": "^8.1.0", - "glob": "^7.1.3", "graceful-fs": "^4.1.3", - "joi": "^17.2.1", - "leven": "^3.1.0", - "lodash": "^4.17.15", - "minimist": "^1.2.0", - "node-stream-zip": "^1.9.1", - "ora": "^3.4.0", - "pretty-format": "^26.6.2", "prompts": "^2.4.0", - "semver": "^6.3.0", - "serve-static": "^1.13.1", - "strip-ansi": "^5.2.0", - "sudo-prompt": "^9.0.0", - "wcwidth": "^1.0.1" + "semver": "^6.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@react-native-community/cli-clean": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-9.2.1.tgz", + "integrity": "sha512-dyNWFrqRe31UEvNO+OFWmQ4hmqA07bR9Ief/6NnGwx67IO9q83D5PEAf/o96ML6jhSbDwCmpPKhPwwBbsyM3mQ==", + "requires": { + "@react-native-community/cli-tools": "^9.2.1", + "chalk": "^4.1.2", + "execa": "^1.0.0", + "prompts": "^2.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@react-native-community/cli-config": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-9.2.1.tgz", + "integrity": "sha512-gHJlBBXUgDN9vrr3aWkRqnYrPXZLztBDQoY97Mm5Yo6MidsEpYo2JIP6FH4N/N2p1TdjxJL4EFtdd/mBpiR2MQ==", + "requires": { + "@react-native-community/cli-tools": "^9.2.1", + "cosmiconfig": "^5.1.0", + "deepmerge": "^3.2.0", + "glob": "^7.1.3", + "joi": "^17.2.1" } }, "@react-native-community/cli-debugger-ui": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-7.0.3.tgz", - "integrity": "sha512-G4SA6jFI0j22o+j+kYP8/7sxzbCDqSp2QiHA/X5E0lsGEd2o9qN2zbIjiFr8b8k+VVAYSUONhoC0+uKuINvmkA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-9.0.0.tgz", + "integrity": "sha512-7hH05ZwU9Tp0yS6xJW0bqcZPVt0YCK7gwj7gnRu1jDNN2kughf6Lg0Ys29rAvtZ7VO1PK5c1O+zs7yFnylQDUA==", "requires": { "serve-static": "^1.13.1" } }, + "@react-native-community/cli-doctor": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-9.3.0.tgz", + "integrity": "sha512-/fiuG2eDGC2/OrXMOWI5ifq4X1gdYTQhvW2m0TT5Lk1LuFiZsbTCp1lR+XILKekuTvmYNjEGdVpeDpdIWlXdEA==", + "requires": { + "@react-native-community/cli-config": "^9.2.1", + "@react-native-community/cli-platform-ios": "^9.3.0", + "@react-native-community/cli-tools": "^9.2.1", + "chalk": "^4.1.2", + "command-exists": "^1.2.8", + "envinfo": "^7.7.2", + "execa": "^1.0.0", + "hermes-profile-transformer": "^0.0.6", + "ip": "^1.1.5", + "node-stream-zip": "^1.9.1", + "ora": "^5.4.1", + "prompts": "^2.4.0", + "semver": "^6.3.0", + "strip-ansi": "^5.2.0", + "sudo-prompt": "^9.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "@react-native-community/cli-hermes": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-6.3.0.tgz", - "integrity": "sha512-Uhbm9bubyZLZ12vFCIfWbE/Qi3SBTbYIN/TC08EudTLhv/KbPomCQnmFsnJ7AXQFuOZJs73mBxoEAYSbRbwyVA==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-9.3.1.tgz", + "integrity": "sha512-Mq4PK8m5YqIdaVq5IdRfp4qK09aVO+aiCtd6vjzjNUgk1+1X5cgUqV6L65h4N+TFJYJHcp2AnB+ik1FAYXvYPQ==", "requires": { - "@react-native-community/cli-platform-android": "^6.3.0", - "@react-native-community/cli-tools": "^6.2.0", + "@react-native-community/cli-platform-android": "^9.3.1", + "@react-native-community/cli-tools": "^9.2.1", "chalk": "^4.1.2", "hermes-profile-transformer": "^0.0.6", "ip": "^1.1.5" }, "dependencies": { - "@react-native-community/cli-platform-android": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-6.3.0.tgz", - "integrity": "sha512-d5ufyYcvrZoHznYm5bjBXaiHIJv552t5gYtQpnUsxBhHSQ8QlaNmlLUyeSPRDfOw4ND9b0tPHqs4ufwx6vp/fQ==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "@react-native-community/cli-tools": "^6.2.0", - "chalk": "^4.1.2", - "execa": "^1.0.0", - "fs-extra": "^8.1.0", - "glob": "^7.1.3", - "jetifier": "^1.6.2", - "lodash": "^4.17.15", - "logkitty": "^0.7.1", - "slash": "^3.0.0", - "xmldoc": "^1.1.2" + "has-flag": "^4.0.0" } } } }, "@react-native-community/cli-platform-android": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-7.0.1.tgz", - "integrity": "sha512-nOr0aMkxAymCnbtsQwXBlyoRN2Y+IzC7Qz5T+/zyWwEbTY8SKQI8uV+8+qttUvzSvuXa2PeXsTWluuliOS8KCw==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-9.3.1.tgz", + "integrity": "sha512-m0bQ6Twewl7OEZoVf79I2GZmsDqh+Gh0bxfxWgwxobsKDxLx8/RNItAo1lVtTCgzuCR75cX4EEO8idIF9jYhew==", "requires": { - "@react-native-community/cli-tools": "^7.0.1", + "@react-native-community/cli-tools": "^9.2.1", "chalk": "^4.1.2", "execa": "^1.0.0", "fs-extra": "^8.1.0", "glob": "^7.1.3", - "jetifier": "^1.6.2", - "lodash": "^4.17.15", "logkitty": "^0.7.1", - "slash": "^3.0.0", - "xmldoc": "^1.1.2" + "slash": "^3.0.0" }, "dependencies": { - "@react-native-community/cli-tools": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-7.0.1.tgz", - "integrity": "sha512-0xra4hKNA5PR2zYVXsDMNiXMGaDNoNRYMY6eTP2aVIxQbqIcVMDWSyCA8wMWX5iOpMWg0cZGaQ6a77f3Rlb34g==", - "requires": { - "appdirsjs": "^1.2.4", - "chalk": "^4.1.2", - "lodash": "^4.17.15", - "mime": "^2.4.1", - "node-fetch": "^2.6.0", - "open": "^6.2.0", - "ora": "^5.4.1", - "semver": "^6.3.0", - "shell-quote": "^1.7.3" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "color-convert": "^2.0.1" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { - "mimic-fn": "^2.1.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "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" + "color-name": "~1.1.4" } }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "ansi-regex": "^5.0.1" + "has-flag": "^4.0.0" } } } }, "@react-native-community/cli-platform-ios": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-7.0.1.tgz", - "integrity": "sha512-PLRIbzrCzSedmpjuFtQqcqUD45G8q7sEciI1lf5zUbVMXqjIBwJWS7iz8235PyWwj8J4MNHohLC+oyRueFtbGg==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-9.3.0.tgz", + "integrity": "sha512-nihTX53BhF2Q8p4B67oG3RGe1XwggoGBrMb6vXdcu2aN0WeXJOXdBLgR900DAA1O8g7oy1Sudu6we+JsVTKnjw==", "requires": { - "@react-native-community/cli-tools": "^7.0.1", + "@react-native-community/cli-tools": "^9.2.1", "chalk": "^4.1.2", "execa": "^1.0.0", "glob": "^7.1.3", - "js-yaml": "^3.13.1", - "lodash": "^4.17.15", - "ora": "^5.4.1", - "plist": "^3.0.2", - "xcode": "^3.0.0" + "ora": "^5.4.1" }, "dependencies": { - "@react-native-community/cli-tools": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-7.0.1.tgz", - "integrity": "sha512-0xra4hKNA5PR2zYVXsDMNiXMGaDNoNRYMY6eTP2aVIxQbqIcVMDWSyCA8wMWX5iOpMWg0cZGaQ6a77f3Rlb34g==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "appdirsjs": "^1.2.4", - "chalk": "^4.1.2", - "lodash": "^4.17.15", - "mime": "^2.4.1", - "node-fetch": "^2.6.0", - "open": "^6.2.0", - "ora": "^5.4.1", - "semver": "^6.3.0", - "shell-quote": "^1.7.3" + "color-convert": "^2.0.1" } }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { - "restore-cursor": "^3.1.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "color-name": "~1.1.4" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "mimic-fn": "^2.1.0" + "has-flag": "^4.0.0" + } + } + } + }, + "@react-native-community/cli-plugin-metro": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-9.2.1.tgz", + "integrity": "sha512-byBGBH6jDfUvcHGFA45W/sDwMlliv7flJ8Ns9foCh3VsIeYYPoDjjK7SawE9cPqRdMAD4SY7EVwqJnOtRbwLiQ==", + "requires": { + "@react-native-community/cli-server-api": "^9.2.1", + "@react-native-community/cli-tools": "^9.2.1", + "chalk": "^4.1.2", + "metro": "0.72.3", + "metro-config": "0.72.3", + "metro-core": "0.72.3", + "metro-react-native-babel-transformer": "0.72.3", + "metro-resolver": "0.72.3", + "metro-runtime": "0.72.3", + "readline": "^1.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" } }, - "ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { - "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" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "color-name": "~1.1.4" } }, - "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "ansi-regex": "^5.0.1" + "has-flag": "^4.0.0" } } } }, - "@react-native-community/cli-plugin-metro": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-7.0.3.tgz", - "integrity": "sha512-HJrEkFbxv9DNixsGwO+Q0zCcZMghDltyzeB9yQ//D5ZR4ZUEuAIPrRDdEp9xVw0WkBxAIZs6KXLux2/yPMwLhA==", - "requires": { - "@react-native-community/cli-server-api": "^7.0.3", - "@react-native-community/cli-tools": "^6.2.0", - "chalk": "^4.1.2", - "metro": "^0.67.0", - "metro-config": "^0.67.0", - "metro-core": "^0.67.0", - "metro-react-native-babel-transformer": "^0.67.0", - "metro-resolver": "^0.67.0", - "metro-runtime": "^0.67.0", - "readline": "^1.3.0" - } - }, "@react-native-community/cli-server-api": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-7.0.3.tgz", - "integrity": "sha512-JDrLsrkBgNxbG2u3fouoVGL9tKrXUrTsaNwr+oCV+3XyMwbVe42r/OaQ681/iW/7mHXjuVkDnMcp7BMg7e2yJg==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-9.2.1.tgz", + "integrity": "sha512-EI+9MUxEbWBQhWw2PkhejXfkcRqPl+58+whlXJvKHiiUd7oVbewFs0uLW0yZffUutt4FGx6Uh88JWEgwOzAdkw==", "requires": { - "@react-native-community/cli-debugger-ui": "^7.0.3", - "@react-native-community/cli-tools": "^6.2.0", + "@react-native-community/cli-debugger-ui": "^9.0.0", + "@react-native-community/cli-tools": "^9.2.1", "compression": "^1.7.1", "connect": "^3.6.5", "errorhandler": "^1.5.0", - "nocache": "^2.1.0", + "nocache": "^3.0.1", "pretty-format": "^26.6.2", "serve-static": "^1.13.1", "ws": "^7.5.1" }, "dependencies": { "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "requires": {} } } }, "@react-native-community/cli-tools": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-6.2.0.tgz", - "integrity": "sha512-08ssz4GMEnRxC/1FgTTN/Ud7mExQi5xMphItPjfHiTxpZPhrFn+IMx6mya0ncFEhhxQ207wYlJMRLPRRdBZ8oA==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-9.2.1.tgz", + "integrity": "sha512-bHmL/wrKmBphz25eMtoJQgwwmeCylbPxqFJnFSbkqJPXQz3ManQ6q/gVVMqFyz7D3v+riaus/VXz3sEDa97uiQ==", "requires": { "appdirsjs": "^1.2.4", "chalk": "^4.1.2", - "lodash": "^4.17.15", + "find-up": "^5.0.0", "mime": "^2.4.1", "node-fetch": "^2.6.0", "open": "^6.2.0", + "ora": "^5.4.1", "semver": "^6.3.0", - "shell-quote": "1.6.1" + "shell-quote": "^1.7.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@react-native-community/cli-types": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-6.0.0.tgz", - "integrity": "sha512-K493Fk2DMJC0ZM8s8gnfseKxGasIhuDaCUDeLZcoCSFlrjKEuEs1BKKEJiev0CARhKEXKOyyp/uqYM9nWhisNw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-9.1.0.tgz", + "integrity": "sha512-KDybF9XHvafLEILsbiKwz5Iobd+gxRaPyn4zSaAerBxedug4er5VUWa8Szy+2GeYKZzMh/gsb1o9lCToUwdT/g==", "requires": { - "ora": "^3.4.0" + "joi": "^17.2.1" } }, "@react-native-community/slider": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-4.3.3.tgz", - "integrity": "sha512-eVhMaVR08wWlseVWlDS7zgdhbVY0n2i7BF1qRxK+2N1VIKd7NsTIRzL57sFLgHVjbUmu/+hHfxCzLHmEaGxIQg==" + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-4.4.2.tgz", + "integrity": "sha512-D9bv+3Vd2gairAhnRPAghwccgEmoM7g562pm8i4qB3Esrms5mggF81G3UvCyc0w3jjtFHh8dpQkfEoKiP0NW/Q==" }, "@react-native/assets": { "version": "1.0.0", @@ -16713,119 +13961,30 @@ } }, "@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" }, "@sideway/pinpoint": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, "@socket.io/component-emitter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "@tsconfig/react-native": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/react-native/-/react-native-2.0.3.tgz", + "integrity": "sha512-jE58snEKBd9DXfyR4+ssZmYJ/W2mOSnNrvljR0aLyQJL9JKX6vlWELHkRjb3HBbcM9Uy0hZGijXbqEAjOERW2A==", "dev": true }, - "@types/babel__core": { - "version": "7.1.14", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", - "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", - "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" - }, - "@types/cors": { - "version": "2.8.13", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", - "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", - "requires": { - "@types/node": "*" - } - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "requires": { - "@types/node": "*" - } - }, - "@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", - "requires": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" }, "@types/istanbul-lib-report": { "version": "3.0.0", @@ -16836,91 +13995,236 @@ } }, "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "requires": { "@types/istanbul-lib-report": "*" } }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true, + "peer": true + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "peer": true }, "@types/node": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", - "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", - "dev": true + "version": "18.11.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz", + "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==" }, "@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "dev": true }, "@types/react": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.5.tgz", - "integrity": "sha512-UPxNGInDCIKlfqBrm8LDXYWNfLHwIdisWcsH5GpMyGjhEDLFgTtlRBaoWuCua9HcyuE0rMkmAeZ3FXV1pYLIYQ==", + "version": "18.0.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", + "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "dev": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, + "@types/react-native": { + "version": "0.70.11", + "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.70.11.tgz", + "integrity": "sha512-FobPtzoNPNHugBKMfzs4Li0Q9ei4tgU8SI1M5Ayg7+t5/+noCm2sknI8uwij22wMkcHcefv8RFx4q28nNVJtCQ==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-native-background-timer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/react-native-background-timer/-/react-native-background-timer-2.0.0.tgz", + "integrity": "sha512-y5VW82dL/ESOLg+5QQHyBdsFVA4ZklENxmOyxv8o06T+3HBG2JOSuz/CIPz1vKdB7dmWDGPZNuPosdtnp+xv2A==", + "dev": true + }, + "@types/react-native-vector-icons": { + "version": "6.4.13", + "resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.13.tgz", + "integrity": "sha512-1PqFoKuXTSzMHwGMAr+REdYJBQAbe9xrww3ecZR0FsHcD1K+vGS/rxuAriL4rsI6+p69sZQjDzpEVAbDQcjSwA==", + "dev": true, + "requires": { + "@types/react": "*", + "@types/react-native": "^0.70" + } + }, "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true, + "peer": true + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz", + "integrity": "sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==", + "dev": true, + "peer": true, + "requires": { + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/type-utils": "5.51.0", + "@typescript-eslint/utils": "5.51.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz", + "integrity": "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/typescript-estree": "5.51.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz", + "integrity": "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz", + "integrity": "sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==", + "dev": true, + "peer": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.51.0", + "@typescript-eslint/utils": "5.51.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz", + "integrity": "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==", "dev": true }, - "@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + "@typescript-eslint/typescript-estree": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz", + "integrity": "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } }, - "@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "@typescript-eslint/utils": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.51.0.tgz", + "integrity": "sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==", + "dev": true, + "peer": true, "requires": { - "@types/yargs-parser": "*" + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/typescript-estree": "5.51.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "dependencies": { + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, - "@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" - }, - "@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true + "@typescript-eslint/visitor-keys": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz", + "integrity": "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.51.0", + "eslint-visitor-keys": "^3.3.0" + } }, "abort-controller": { "version": "3.0.0", @@ -16933,71 +14237,38 @@ "absolute-path": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz", - "integrity": "sha1-p4di+9rftSl76ZsV01p4Wy8JW/c=" + "integrity": "sha512-HQiug4c+/s3WOvEnDRxXVmNtSG5s2gJM9r19BTcqjp7BWcE48PB+Y2G6jE65kqI0LpsQeMZygt/b60Gi4KxGyA==" }, "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } + "peer": true }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "peer": true, "requires": {} }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - } - } - }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "peer": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -17010,23 +14281,6 @@ "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==" }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, "ansi-fragments": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/ansi-fragments/-/ansi-fragments-0.2.1.tgz", @@ -17035,47 +14289,61 @@ "colorette": "^1.0.7", "slice-ansi": "^2.0.0", "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" } }, "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "appdirsjs": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.6.tgz", - "integrity": "sha512-D8wJNkqMCeQs3kLasatELsddox/Xqkhp+J07iXGyL54fVN7oc+nmNfYzGuCs1IEP6uBw+TfpuO3JKwc+lECy4w==" + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.7.tgz", + "integrity": "sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==" }, "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true }, "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==" }, "arr-flatten": { "version": "1.1.0", @@ -17085,12 +14353,7 @@ "arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" - }, - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=" + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==" }, "array-includes": { "version": "3.1.6", @@ -17105,30 +14368,28 @@ "is-string": "^1.0.7" } }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=" - }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=" + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==" }, "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dev": true, + "peer": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" } }, "array.prototype.flatmap": { @@ -17182,7 +14443,7 @@ "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==" }, "ast-types": { "version": "0.14.2", @@ -17198,24 +14459,15 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" }, "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "requires": { - "lodash": "^4.17.14" - } + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -17227,85 +14479,77 @@ "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", "requires": {} }, - "babel-jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", - "dev": true, - "requires": { - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - } - }, "babel-plugin-module-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz", - "integrity": "sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz", + "integrity": "sha512-g0u+/ChLSJ5+PzYwLwP8Rp8Rcfowz58TJNCe+L/ui4rpzE/mg//JVX0EWBUYoxaextqnwuGHzfGp2hh0PPV25Q==", "dev": true, "requires": { - "find-babel-config": "^1.2.0", - "glob": "^7.1.6", + "find-babel-config": "^2.0.0", + "glob": "^8.0.3", "pkg-up": "^3.1.0", - "reselect": "^4.0.0", - "resolve": "^1.13.1" + "reselect": "^4.1.7", + "resolve": "^1.22.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "babel-plugin-polyfill-corejs2": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", - "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.2.2", + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", "semver": "^6.1.1" } }, "babel-plugin-polyfill-corejs3": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.4.tgz", - "integrity": "sha512-z3HnJE5TY/j4EFEa/qpQMSbcUJZ5JQi+3UFjXzn6pQCmIKc5Ug5j98SuYyH+m4xQnvKlMDIW4plLfgyVnd0IcQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.14.0" + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz", - "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.2" + "@babel/helper-define-polyfill-provider": "^0.3.3" } }, "babel-plugin-syntax-trailing-function-commas": { @@ -17313,26 +14557,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz", "integrity": "sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==" }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, "babel-preset-fbjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz", @@ -17367,16 +14591,6 @@ "babel-plugin-syntax-trailing-function-commas": "^7.0.0-beta.0" } }, - "babel-preset-jest": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^26.6.2", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -17399,59 +14613,23 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "requires": { "is-descriptor": "^1.0.0" } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } } } }, "base-64": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", - "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, - "base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" - }, - "big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==" - }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -17460,49 +14638,12 @@ "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" - }, - "dependencies": { - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } } }, "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "bplist-creator": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", - "integrity": "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==", - "requires": { - "stream-buffers": "2.2.x" - } - }, - "bplist-parser": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", - "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", - "requires": { - "big-integer": "1.6.x" - } + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, "brace-expansion": { "version": "1.1.11", @@ -17524,13 +14665,7 @@ "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" }, "browserify-aes": { "version": "1.2.0", @@ -17591,16 +14726,6 @@ "safe-buffer": "^5.2.0" }, "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -17628,28 +14753,28 @@ } }, "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "requires": { "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "ieee754": "^1.1.13" } }, "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" }, "builtins": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-4.1.0.tgz", - "integrity": "sha512-1bPRZQtmKaO6h7qV1YHXNtr6nCK28k0Zo95KM4dXfILcZZwoHJBN1m3lfLv9LPkcOZlrSr+J1bzMaZFO98Yq0w==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", "dev": true, "peer": true, "requires": { @@ -17657,9 +14782,9 @@ }, "dependencies": { "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "peer": true, "requires": { @@ -17671,7 +14796,7 @@ "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" }, "cache-base": { "version": "1.0.1", @@ -17702,68 +14827,53 @@ "caller-callsite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", "requires": { "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==" + } } }, "caller-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", "requires": { "caller-callsite": "^2.0.0" } }, "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "peer": true }, "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "caniuse-lite": { - "version": "1.0.30001412", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001412.tgz", - "integrity": "sha512-+TeEIee1gS5bYOiuf+PS/kp2mrXic37Hl66VY6EAfxasIk5fELTktK2oOezYed12H8w7jt3s512PpulQidPjwA==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } + "caniuse-lite": { + "version": "1.0.30001431", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", + "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==" }, "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "changelog-parser": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/changelog-parser/-/changelog-parser-2.8.1.tgz", - "integrity": "sha512-tNUYFRCEeWTXmwLqoNtOEzx9wcytg72MmGQqsEs14ClYwIDln7sbQw7FJj/dulXgSlsxkemc9gpPQhZYZx1TPw==", - "dev": true, + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "line-reader": "^0.2.4", - "remove-markdown": "^0.2.2" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -17778,12 +14888,6 @@ "safe-buffer": "^5.0.1" } }, - "cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", - "dev": true - }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -17798,25 +14902,76 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "requires": { - "restore-cursor": "^2.0.0" + "restore-cursor": "^3.1.0" } }, "cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==" }, "cliui": { "version": "6.0.0", @@ -17826,27 +14981,12 @@ "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } - } } }, "clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" }, "clone-deep": { "version": "4.0.1", @@ -17858,53 +14998,32 @@ "shallow-clone": "^3.0.0" } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "requires": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" } }, "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "requires": { - "color-name": "~1.1.4" + "color-name": "1.1.3" } }, "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==" }, "command-exists": { "version": "1.2.9", @@ -17912,9 +15031,9 @@ "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" }, "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==" }, "commondir": { "version": "1.0.1", @@ -17946,12 +15065,27 @@ "on-headers": "~1.0.2", "safe-buffer": "5.1.2", "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } } }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "connect": { "version": "3.7.0", @@ -17962,30 +15096,32 @@ "finalhandler": "1.1.2", "parseurl": "~1.3.3", "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } } }, - "console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" - }, "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==" }, "core-js-compat": { "version": "3.26.0", @@ -17996,18 +15132,9 @@ } }, "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { - "object-assign": "^4", - "vary": "^1" - } + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "cosmiconfig": { "version": "5.2.1", @@ -18018,6 +15145,39 @@ "is-directory": "^0.3.1", "js-yaml": "^3.13.1", "parse-json": "^4.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==" + } } }, "create-ecdh": { @@ -18061,177 +15221,71 @@ "sha.js": "^2.4.8" } }, - "cross-env": { + "cross-spawn": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "peer": true, "requires": { - "cross-spawn": "^7.0.1" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" } }, "csstype": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", - "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" - }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "dev": true }, "dayjs": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.0.tgz", - "integrity": "sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", + "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==" }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } + "ms": "2.1.2" } }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" }, "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "deep-diff": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz", - "integrity": "sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ=", - "dev": true - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==" }, "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "peer": true }, "deepmerge": { "version": "3.3.0", @@ -18239,9 +15293,9 @@ "integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==" }, "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "requires": { "clone": "^1.0.2" } @@ -18263,62 +15317,18 @@ "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, "denodeify": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", - "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=" + "integrity": "sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==" }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, - "deprecated-react-native-prop-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz", - "integrity": "sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==", - "requires": { - "@react-native/normalize-color": "*", - "invariant": "*", - "prop-types": "*" - } - }, "des.js": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", @@ -18333,18 +15343,6 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true - }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -18362,78 +15360,34 @@ } } }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "peer": true, "requires": { "esutils": "^2.0.2" } }, - "dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true - }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0" - } - }, - "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", - "dev": true, - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.265", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.265.tgz", - "integrity": "sha512-38KaYBNs0oCzWCpr6j7fY/W9vF0vSp4tKFIshQTgdZMhUpkxgotkQgjJP6iGMdmlsgMs3i0/Hkko4UXLTrkYVQ==" + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" }, "elliptic": { "version": "6.5.4", @@ -18456,12 +15410,6 @@ } } }, - "emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", - "dev": true - }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -18470,7 +15418,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "end-of-stream": { "version": "1.4.4", @@ -18480,49 +15428,30 @@ "once": "^1.4.0" } }, - "engine.io": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz", - "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==", + "engine.io-client": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.4.0.tgz", + "integrity": "sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==", "requires": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", "engine.io-parser": "~5.0.3", - "ws": "~8.2.3" + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" }, "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, "ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "requires": {} } } }, "engine.io-parser": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", - "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==" - }, - "entities": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz", - "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==", - "dev": true + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz", + "integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==" }, "envinfo": { "version": "7.8.1", @@ -18538,11 +15467,11 @@ } }, "error-stack-parser": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.7.tgz", - "integrity": "sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", "requires": { - "stackframe": "^1.1.1" + "stackframe": "^1.3.4" } }, "errorhandler": { @@ -18614,85 +15543,19 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } - } + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz", + "integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==", "dev": true, + "peer": true, "requires": { "@eslint/eslintrc": "^1.3.3", "@humanwhocodes/config-array": "^0.11.6", @@ -18735,204 +15598,95 @@ "text-table": "^0.2.0" }, "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "peer": true, "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "peer": true, "requires": { - "ms": "2.1.2" + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true + "dev": true, + "peer": true }, "eslint-scope": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, + "peer": true, "requires": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, "globals": { - "version": "13.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", - "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, + "peer": true, "requires": { "type-fest": "^0.20.2" } }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "resolve-from": { + "has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true + "peer": true }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "peer": true, "requires": { - "ansi-regex": "^5.0.1" + "has-flag": "^4.0.0" } }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "requires": { - "isexe": "^2.0.0" - } + "peer": true } } }, @@ -18943,35 +15697,26 @@ "dev": true, "requires": {} }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "eslint-config-standard-with-typescript": { + "version": "34.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-34.0.0.tgz", + "integrity": "sha512-zhCsI4/A0rJ1ma8sf3RLXYc0gc7yPmdTWRVXMh9dtqeUx3yBQyALH0wosHhk1uQ9QyItynLdNOtcHKNw8G7lQw==", "dev": true, "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "@typescript-eslint/parser": "^5.0.0", + "eslint-config-standard": "17.0.0" } }, - "eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, + "peer": true, "requires": { "debug": "^3.2.7", - "find-up": "^2.1.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" }, "dependencies": { "debug": { @@ -18979,106 +15724,105 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "peer": true, "requires": { "ms": "^2.1.1" } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + } + } + }, + "eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "peer": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "peer": true, "requires": { - "p-limit": "^1.1.0" + "ms": "^2.1.1" } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true } } }, "eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", + "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", "dev": true, + "peer": true, "requires": { "eslint-utils": "^2.0.0", "regexpp": "^3.0.0" - } - }, - "eslint-plugin-html": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-7.1.0.tgz", - "integrity": "sha512-fNLRraV/e6j8e3XYOC9xgND4j+U7b1Rq+OygMlLcMg+wI/IpVbF+ubQa3R78EjKB9njT6TQOlcK5rFKBVVtdfg==", - "dev": true, - "requires": { - "htmlparser2": "^8.0.1" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "peer": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "peer": true + } } }, "eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", "dev": true, + "peer": true, "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "peer": true, + "requires": { + "ms": "^2.1.1" + } + }, "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "peer": true, "requires": { "esutils": "^2.0.2" } @@ -19086,91 +15830,46 @@ } }, "eslint-plugin-n": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.2.0.tgz", - "integrity": "sha512-lWLg++jGwC88GDGGBX3CMkk0GIWq0y41aH51lavWApOKcMQcYoL3Ayd0lEdtD3SnQtR+3qBvWQS3qGbR2BxRWg==", + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.6.1.tgz", + "integrity": "sha512-R9xw9OtCRxxaxaszTQmQAlPgM+RdGjaL1akWuY/Fv9fRAi8Wj4CUKc6iYVG8QNRjRuo8/BqVYIpfqberJUEacA==", "dev": true, "peer": true, "requires": { - "builtins": "^4.0.0", + "builtins": "^5.0.1", "eslint-plugin-es": "^4.1.0", "eslint-utils": "^3.0.0", "ignore": "^5.1.1", - "is-core-module": "^2.3.0", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.3.0" + "is-core-module": "^2.11.0", + "minimatch": "^3.1.2", + "resolve": "^1.22.1", + "semver": "^7.3.8" }, "dependencies": { - "eslint-plugin-es": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", - "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", - "dev": true, - "peer": true, - "requires": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "peer": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - } - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "peer": true, "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "peer": true - } + "lru-cache": "^6.0.0" } } } }, - "eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, - "requires": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - } - }, "eslint-plugin-promise": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", "dev": true, + "peer": true, "requires": {} }, "eslint-plugin-react": { - "version": "7.31.11", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz", - "integrity": "sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw==", + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", "dev": true, "requires": { "array-includes": "^3.1.6", @@ -19185,7 +15884,7 @@ "object.hasown": "^1.1.2", "object.values": "^1.1.6", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", + "resolve": "^2.0.0-next.4", "semver": "^6.3.0", "string.prototype.matchall": "^4.0.8" }, @@ -19199,20 +15898,15 @@ "esutils": "^2.0.2" } }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, "resolve": { - "version": "2.0.0-next.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", - "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } } } @@ -19229,49 +15923,56 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "peer": true, "requires": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "peer": true + } } }, "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, + "peer": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "peer": true + } } }, "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, "espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, + "peer": true, "requires": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" - }, - "dependencies": { - "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - } } }, "esprima": { @@ -19284,16 +15985,9 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, + "peer": true, "requires": { "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "esrecurse": { @@ -19301,22 +15995,15 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "peer": true, "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "esutils": { @@ -19327,7 +16014,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "event-target-shim": { "version": "5.0.1", @@ -19348,12 +16035,6 @@ "safe-buffer": "^5.1.1" } }, - "exec-sh": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", - "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", - "dev": true - }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -19366,18 +16047,57 @@ "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + } } }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "requires": { "debug": "^2.3.3", "define-property": "^0.2.5", @@ -19388,10 +16108,18 @@ "to-regex": "^3.0.1" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } @@ -19399,44 +16127,81 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { "is-extendable": "^0.1.0" } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, - "expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - } - }, "extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } } }, "extglob": { @@ -19457,7 +16222,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "requires": { "is-descriptor": "^1.0.0" } @@ -19465,36 +16230,15 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { - "kind-of": "^6.0.0" + "is-extendable": "^0.1.0" } }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" } } }, @@ -19502,19 +16246,46 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "peer": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "peer": true }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "peer": true }, "fastq": { "version": "1.13.0", @@ -19526,9 +16297,9 @@ } }, "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "requires": { "bser": "2.1.1" } @@ -19538,6 +16309,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "peer": true, "requires": { "flat-cache": "^3.0.4" } @@ -19562,28 +16334,37 @@ "parseurl": "~1.3.3", "statuses": "~1.5.0", "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } } }, "find-babel-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", - "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.0.0.tgz", + "integrity": "sha512-dOKT7jvF3hGzlW60Gc3ONox/0rRZ/tz7WCil0bqA1In/3I8f1BctpXahRnEKDySZqci7u+dqq93sZST9fOJpFw==", "dev": true, "requires": { - "json5": "^0.5.1", - "path-exists": "^3.0.0" + "json5": "^2.1.1", + "path-exists": "^4.0.0" }, "dependencies": { - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true } } @@ -19599,46 +16380,38 @@ } }, "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "requires": { - "locate-path": "^5.0.0", + "locate-path": "^6.0.0", "path-exists": "^4.0.0" + }, + "dependencies": { + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + } } }, - "findit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", - "integrity": "sha1-ZQnwEmr0wXhVHPqZOU4DLhOk1W4=", - "dev": true - }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, + "peer": true, "requires": { "flatted": "^3.1.0", "rimraf": "^3.0.2" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } } }, "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true, + "peer": true }, "flow-parser": { "version": "0.121.0", @@ -19648,23 +16421,12 @@ "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==" }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "requires": { "map-cache": "^0.2.2" } @@ -19672,7 +16434,7 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, "fs-extra": { "version": "8.1.0", @@ -19687,7 +16449,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { "version": "2.3.2", @@ -19739,12 +16501,6 @@ "has-symbols": "^1.0.3" } }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -19766,17 +16522,17 @@ "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==" }, "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } @@ -19786,6 +16542,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "peer": true, "requires": { "is-glob": "^4.0.3" } @@ -19795,6 +16552,20 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -19804,14 +16575,8 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "dev": true, - "optional": true + "peer": true }, "has": { "version": "1.0.3", @@ -19828,9 +16593,9 @@ "dev": true }, "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "has-property-descriptors": { "version": "1.0.0", @@ -19859,7 +16624,7 @@ "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "requires": { "get-value": "^2.0.6", "has-values": "^1.0.0", @@ -19869,7 +16634,7 @@ "has-values": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "requires": { "is-number": "^3.0.0", "kind-of": "^4.0.0" @@ -19878,7 +16643,7 @@ "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "requires": { "kind-of": "^3.0.2" }, @@ -19886,7 +16651,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -19896,7 +16661,7 @@ "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "requires": { "is-buffer": "^1.1.5" } @@ -19913,16 +16678,6 @@ "safe-buffer": "^5.2.0" }, "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -19939,22 +16694,17 @@ "minimalistic-assert": "^1.0.1" } }, - "hermes-engine": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/hermes-engine/-/hermes-engine-0.11.0.tgz", - "integrity": "sha512-7aMUlZja2IyLYAcZ69NBnwJAR5ZOYlSllj0oMpx08a8HzxHOys0eKCzfphrf6D0vX1JGO1QQvVsQKe6TkYherw==" - }, "hermes-estree": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.5.0.tgz", - "integrity": "sha512-1h8rvG23HhIR5K6Kt0e5C7BC72J1Ath/8MmSta49vxXp/j6wl7IMHvIRFYBQr35tWnQY97dSGR2uoAJ5pHUQkg==" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.8.0.tgz", + "integrity": "sha512-W6JDAOLZ5pMPMjEiQGLCXSSV7pIBEgRR5zGkxgmzGSXHOxqV5dC/M1Zevqpbm9TZDE5tu358qZf8Vkzmsc+u7Q==" }, "hermes-parser": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.5.0.tgz", - "integrity": "sha512-ARnJBScKAkkq8j3BHrNGBUv/4cSpZNbKDsVizEtzmsFeqC67Dopa5s4XRe+e3wN52Dh5Mj2kDB5wJvhcxwDkPg==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.8.0.tgz", + "integrity": "sha512-yZKalg1fTYG5eOiToLUaw69rQfZq/fi+/NtEXRU7N87K/XobNRhRWorh80oSge2lWUiZfTgUvRJH+XgZWrhoqA==", "requires": { - "hermes-estree": "0.5.0" + "hermes-estree": "0.8.0" } }, "hermes-profile-transformer": { @@ -19968,7 +16718,7 @@ "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -19983,47 +16733,6 @@ "react-is": "^16.7.0" } }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "html-parse-stringify": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", - "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", - "requires": { - "void-elements": "3.1.0" - } - }, - "htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "entities": "^4.3.0" - } - }, "http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -20043,70 +16752,12 @@ } } }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - } - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - } - } - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true - }, - "i18next": { - "version": "22.1.5", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.1.5.tgz", - "integrity": "sha512-Mjj45PbpZByE+c6ddLEkkj0LUyzJP1cRGeC/+O6mvp1+GAwW7rIx6aOPW9+Zxe+JO3EcJCAkibwbZrgBRF/qRA==", - "requires": { - "@babel/runtime": "^7.20.6" - } - }, "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "ieee754": { @@ -20126,44 +16777,25 @@ "integrity": "sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA==" }, "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "peer": true, "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "dependencies": { - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - } + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" } }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -20194,41 +16826,22 @@ } }, "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" }, "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arguments": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", - "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", - "dev": true, + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "call-bind": "^1.0.0" + "kind-of": "^6.0.0" } }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "is-bigint": { "version": "1.0.4", @@ -20260,97 +16873,64 @@ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "requires": { "has": "^1.0.3" } }, "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } + "kind-of": "^6.0.0" } }, "is-date-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", - "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", - "dev": true + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "optional": true + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==" }, "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" }, "is-glob": { "version": "4.0.3", @@ -20390,7 +16970,8 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true + "dev": true, + "peer": true }, "is-plain-obj": { "version": "2.1.0", @@ -20405,12 +16986,6 @@ "isobject": "^3.0.1" } }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -20433,713 +17008,147 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==" }, "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", - "dev": true, - "requires": { - "@jest/core": "^26.6.3", - "import-local": "^3.0.2", - "jest-cli": "^26.6.3" - }, - "dependencies": { - "jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", - "dev": true, - "requires": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "prompts": "^2.0.1", - "yargs": "^15.4.1" - } - } - } - }, - "jest-changed-files": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" - }, - "dependencies": { - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - } - } - }, - "jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" - } - }, - "jest-environment-jsdom": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", - "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", - "dev": true, - "requires": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2", - "jsdom": "^16.4.0" - } - }, - "jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", - "dev": true, - "requires": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - } - }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==" - }, - "jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", - "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^26.6.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2", - "throat": "^5.0.0" - } - }, - "jest-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", - "dev": true, - "requires": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, "requires": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "has-tostringtag": "^1.0.0" } }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" + "has-symbols": "^1.0.2" } }, - "jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*" + "call-bind": "^1.0.2" } }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + }, + "jest-get-type": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==" }, "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==" }, - "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, + "jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", "requires": { - "@jest/types": "^26.6.2", + "@types/node": "*", + "graceful-fs": "^4.2.9" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "dependencies": { - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "color-convert": "^2.0.1" } }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, + "ci-info": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.6.1.tgz", + "integrity": "sha512-up5ggbaDqOqJ4UqLKZ2naVkyqSJQgJi5lwD6b6mM748ysrghDBX0bx/qJTUHzw7zu6Mq4gycviSF5hJnwceD8w==" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" + "color-name": "~1.1.4" } }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, - "jest-resolve-dependencies": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.6.2" - } - }, - "jest-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.7.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "source-map-support": "^0.5.6", - "throat": "^5.0.0" - } - }, - "jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.4.1" - }, - "dependencies": { - "strip-bom": { + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - } - } - }, - "jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", - "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - } - }, - "jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "lru-cache": "^6.0.0" + "has-flag": "^4.0.0" } } } }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, "jest-validate": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", @@ -21153,47 +17162,100 @@ "pretty-format": "^26.6.2" }, "dependencies": { - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==" + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } } } }, - "jest-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", - "dev": true, - "requires": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^26.6.2", - "string-length": "^4.0.1" - } - }, "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "requires": { "@types/node": "*", "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "jetifier": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/jetifier/-/jetifier-1.6.8.tgz", - "integrity": "sha512-3Zi16h6L5tXDRQJTb221cnRoVG9/9OvreLdLU2/ZjRv/GILL+2Cemt0IKvkowwkDpvouAU1DQPOJ7qaiHeIdrw==" - }, "joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz", + "integrity": "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==", "requires": { "@hapi/hoek": "^9.0.0", "@hapi/topo": "^5.0.0", @@ -21202,16 +17264,12 @@ "@sideway/pinpoint": "^2.0.0" } }, - "js-htmlencode": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/js-htmlencode/-/js-htmlencode-0.3.0.tgz", - "integrity": "sha1-sc4pPflOlviooIsfM2j5d70lVzE=" - }, "js-sdsl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", - "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==", - "dev": true + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "dev": true, + "peer": true }, "js-tokens": { "version": "4.0.0", @@ -21219,12 +17277,13 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "jsc-android": { @@ -21258,6 +17317,14 @@ "write-file-atomic": "^2.3.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", @@ -21285,6 +17352,28 @@ } } }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -21306,6 +17395,16 @@ } } }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -21352,6 +17451,14 @@ "glob": "^7.1.3" } }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, "temp": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", @@ -21371,56 +17478,6 @@ } } }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true - }, - "ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", - "dev": true, - "requires": {} - } - } - }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -21431,50 +17488,41 @@ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "peer": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "peer": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "requires": { "graceful-fs": "^4.1.6" } }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" - }, "jsx-ast-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", - "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", "dev": true, "requires": { - "array-includes": "^3.1.3", - "object.assign": "^4.1.2" + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" } }, "kind-of": { @@ -21485,7 +17533,7 @@ "klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", "requires": { "graceful-fs": "^4.1.9" } @@ -21505,29 +17553,18 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "peer": true, "requires": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, - "line-reader": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/line-reader/-/line-reader-0.2.4.tgz", - "integrity": "sha1-xDkrWH3qOFgMlnhXDm6OSfzlJiI=", - "dev": true - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "requires": { - "p-locate": "^4.1.0" + "p-locate": "^5.0.0" } }, "lodash": { @@ -21538,69 +17575,70 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "peer": true }, "lodash.throttle": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "requires": { - "chalk": "^2.0.1" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "dependencies": { "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } } } @@ -21624,9 +17662,9 @@ } }, "lrc-file-parser": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/lrc-file-parser/-/lrc-file-parser-2.2.8.tgz", - "integrity": "sha512-Uq2boQVg4Ll4Csthq0ZJ+4Nn8sBfOJwceFsJGGfOxcpKSYpEMmDRsinuVnhNVJe4x/jD1HJr9xWzDqgo+8WMTw==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lrc-file-parser/-/lrc-file-parser-2.3.0.tgz", + "integrity": "sha512-EX+Dnvwqgb8q3mf7WYIR4flOzwrOp9vE2MU+eyRZO0rFUF5BIZgN52SSGXFhfnHd5tUmo7VnLrpCFdURe3O2KQ==" }, "lru-cache": { "version": "6.0.0", @@ -21654,22 +17692,22 @@ } }, "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "requires": { - "tmpl": "1.0.x" + "tmpl": "1.0.5" } }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==" }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "requires": { "object-visit": "^1.0.0" } @@ -21684,6 +17722,11 @@ "safe-buffer": "^5.1.2" } }, + "memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "merge-options": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", @@ -21697,10 +17740,16 @@ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "metro": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.67.0.tgz", - "integrity": "sha512-DwuBGAFcAivoac/swz8Lp7Y5Bcge1tzT7T6K0nf1ubqJP8YzBUtyR4pkjEYVUzVu/NZf7O54kHSPVu1ibYzOBQ==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.72.3.tgz", + "integrity": "sha512-Hb3xTvPqex8kJ1hutQNZhQadUKUwmns/Du9GikmWKBFrkiG3k3xstGAyO5t5rN9JSUEzQT6y9SWzSSOGogUKIg==", "requires": { "@babel/code-frame": "^7.0.0", "@babel/core": "^7.14.0", @@ -21711,7 +17760,7 @@ "@babel/types": "^7.0.0", "absolute-path": "^0.0.0", "accepts": "^1.3.7", - "async": "^2.4.0", + "async": "^3.2.2", "chalk": "^4.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", @@ -21719,30 +17768,29 @@ "denodeify": "^1.2.1", "error-stack-parser": "^2.0.6", "fs-extra": "^1.0.0", - "graceful-fs": "^4.1.3", - "hermes-parser": "0.5.0", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.8.0", "image-size": "^0.6.0", "invariant": "^2.2.4", - "jest-haste-map": "^27.3.1", - "jest-worker": "^26.0.0", + "jest-worker": "^27.2.0", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.67.0", - "metro-cache": "0.67.0", - "metro-cache-key": "0.67.0", - "metro-config": "0.67.0", - "metro-core": "0.67.0", - "metro-hermes-compiler": "0.67.0", - "metro-inspector-proxy": "0.67.0", - "metro-minify-uglify": "0.67.0", - "metro-react-native-babel-preset": "0.67.0", - "metro-resolver": "0.67.0", - "metro-runtime": "0.67.0", - "metro-source-map": "0.67.0", - "metro-symbolicate": "0.67.0", - "metro-transform-plugins": "0.67.0", - "metro-transform-worker": "0.67.0", + "metro-babel-transformer": "0.72.3", + "metro-cache": "0.72.3", + "metro-cache-key": "0.72.3", + "metro-config": "0.72.3", + "metro-core": "0.72.3", + "metro-file-map": "0.72.3", + "metro-hermes-compiler": "0.72.3", + "metro-inspector-proxy": "0.72.3", + "metro-minify-uglify": "0.72.3", + "metro-react-native-babel-preset": "0.72.3", + "metro-resolver": "0.72.3", + "metro-runtime": "0.72.3", + "metro-source-map": "0.72.3", + "metro-symbolicate": "0.72.3", + "metro-transform-plugins": "0.72.3", + "metro-transform-worker": "0.72.3", "mime-types": "^2.1.27", - "mkdirp": "^0.5.1", "node-fetch": "^2.2.0", "nullthrows": "^1.1.1", "rimraf": "^2.5.4", @@ -21755,294 +17803,202 @@ "yargs": "^15.3.1" }, "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "color-convert": "^2.0.1" } }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { - "@types/yargs-parser": "*" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } }, "fs-extra": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "integrity": "sha512-VerQV6vEKuhDWD2HGOybV6v5I73syoc/cXAbKlgTC7M/oFVEtklWlp9QH2Ijw3IaWDOQcMkldSPa7zXy79Z/UQ==", "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0", "klaw": "^1.0.0" } }, - "jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", - "requires": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - }, - "dependencies": { - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - } - } - }, - "jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==" - }, - "jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - } - }, - "jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "dependencies": { - "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==" - } - } + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", "requires": { "graceful-fs": "^4.1.6" } }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { - "ansi-regex": "^5.0.1" + "glob": "^7.1.3" } }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + }, "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { "has-flag": "^4.0.0" } }, "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "requires": {} } } }, "metro-babel-transformer": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.67.0.tgz", - "integrity": "sha512-SBqc4nq/dgsPNFm+mpWcQQzJaXnh0nrfz2pSnZC4i6zMtIakrTWb8SQ78jOU1FZVEZ3nu9xCYVHS9Tbr/LoEuw==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.72.3.tgz", + "integrity": "sha512-PTOR2zww0vJbWeeM3qN90WKENxCLzv9xrwWaNtwVlhcV8/diNdNe82sE1xIxLFI6OQuAVwNMv1Y7VsO2I7Ejrw==", "requires": { "@babel/core": "^7.14.0", - "hermes-parser": "0.5.0", - "metro-source-map": "0.67.0", + "hermes-parser": "0.8.0", + "metro-source-map": "0.72.3", "nullthrows": "^1.1.1" } }, "metro-cache": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.67.0.tgz", - "integrity": "sha512-IY5dXiR76L75b2ue/mv+9vW8g5hdQJU6YEe81lj6gTSoUrhcONT0rzY+Gh5QOS2Kk6z9utZQMvd9PRKL9/635A==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.72.3.tgz", + "integrity": "sha512-++eyZzwkXvijWRV3CkDbueaXXGlVzH9GA52QWqTgAOgSHYp5jWaDwLQ8qpsMkQzpwSyIF4LLK9aI3eA7Xa132A==", "requires": { - "metro-core": "0.67.0", - "mkdirp": "^0.5.1", + "metro-core": "0.72.3", "rimraf": "^2.5.4" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } } }, "metro-cache-key": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.67.0.tgz", - "integrity": "sha512-FNJe5Rcb2uzY6G6tsqCf0RV4t2rCeX6vSHBxmP7k+4aI4NqX4evtPI0K82r221nBzm5DqNWCURZ0RYUT6jZMGA==" + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.72.3.tgz", + "integrity": "sha512-kQzmF5s3qMlzqkQcDwDxrOaVxJ2Bh6WRXWdzPnnhsq9LcD3B3cYqQbRBS+3tSuXmathb4gsOdhWslOuIsYS8Rg==" }, "metro-config": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.67.0.tgz", - "integrity": "sha512-ThAwUmzZwTbKyyrIn2bKIcJDPDBS0LKAbqJZQioflvBGfcgA21h3fdL3IxRmvCEl6OnkEWI0Tn1Z9w2GLAjf2g==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.72.3.tgz", + "integrity": "sha512-VEsAIVDkrIhgCByq8HKTWMBjJG6RlYwWSu1Gnv3PpHa0IyTjKJtB7wC02rbTjSaemcr82scldf2R+h6ygMEvsw==", "requires": { "cosmiconfig": "^5.0.5", "jest-validate": "^26.5.2", - "metro": "0.67.0", - "metro-cache": "0.67.0", - "metro-core": "0.67.0", - "metro-runtime": "0.67.0" + "metro": "0.72.3", + "metro-cache": "0.72.3", + "metro-core": "0.72.3", + "metro-runtime": "0.72.3" } }, "metro-core": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.67.0.tgz", - "integrity": "sha512-TOa/ShE1bUq83fGNfV6rFwyfZ288M8ydmWN3g9C2OW8emOHLhJslYD/SIU4DhDkP/99yaJluIALdZ2g0+pCrvQ==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.72.3.tgz", + "integrity": "sha512-KuYWBMmLB4+LxSMcZ1dmWabVExNCjZe3KysgoECAIV+wyIc2r4xANq15GhS94xYvX1+RqZrxU1pa0jQ5OK+/6A==", "requires": { - "jest-haste-map": "^27.3.1", "lodash.throttle": "^4.1.1", - "metro-resolver": "0.67.0" + "metro-resolver": "0.72.3" + } + }, + "metro-file-map": { + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.72.3.tgz", + "integrity": "sha512-LhuRnuZ2i2uxkpFsz1XCDIQSixxBkBG7oICAFyLyEMDGbcfeY6/NexphfLdJLTghkaoJR5ARFMiIxUg9fIY/pA==", + "requires": { + "abort-controller": "^3.0.0", + "anymatch": "^3.0.3", + "debug": "^2.2.0", + "fb-watchman": "^2.0.0", + "fsevents": "^2.1.2", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-regex-util": "^27.0.6", + "jest-serializer": "^27.0.6", + "jest-util": "^27.2.0", + "jest-worker": "^27.2.0", + "micromatch": "^4.0.4", + "walker": "^1.0.7" }, "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "requires": { - "@types/yargs-parser": "*" - } - }, - "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==" - }, - "jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", - "requires": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - } - }, - "jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==" - }, - "jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - } - }, - "jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "ms": "2.0.0" } }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "requires": { - "has-flag": "^4.0.0" - } + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, "metro-hermes-compiler": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-hermes-compiler/-/metro-hermes-compiler-0.67.0.tgz", - "integrity": "sha512-X5Pr1jC8/kO6d1EBDJ6yhtuc5euHX89UDNv8qdPJHAET03xfFnlojRPwOw6il2udAH20WLBv+F5M9VY+58zspQ==" + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-hermes-compiler/-/metro-hermes-compiler-0.72.3.tgz", + "integrity": "sha512-QWDQASMiXNW3j8uIQbzIzCdGYv5PpAX/ZiF4/lTWqKRWuhlkP4auhVY4eqdAKj5syPx45ggpjkVE0p8hAPDZYg==" }, "metro-inspector-proxy": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.67.0.tgz", - "integrity": "sha512-5Ubjk94qpNaU3OT2IZa4/dec09bauic1hzWms4czorBzDenkp4kYXG9/aWTmgQLtCk92H3Q8jKl1PQRxUSkrOQ==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.72.3.tgz", + "integrity": "sha512-UPFkaq2k93RaOi+eqqt7UUmqy2ywCkuxJLasQ55+xavTUS+TQSyeTnTczaYn+YKw+izLTLllGcvqnQcZiWYhGw==", "requires": { "connect": "^3.6.5", "debug": "^2.2.0", @@ -22050,28 +18006,42 @@ "yargs": "^15.3.1" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "requires": {} } } }, "metro-minify-uglify": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.67.0.tgz", - "integrity": "sha512-4CmM5b3MTAmQ/yFEfsHOhD2SuBObB2YF6PKzXZc4agUsQVVtkrrNElaiWa8w26vrTzA9emwcyurxMf4Nl3lYPQ==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.72.3.tgz", + "integrity": "sha512-dPXqtMI8TQcj0g7ZrdhC8X3mx3m3rtjtMuHKGIiEXH9CMBvrET8IwrgujQw2rkPcXiSiX8vFDbGMIlfxefDsKA==", "requires": { "uglify-es": "^3.1.9" } }, "metro-react-native-babel-preset": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.67.0.tgz", - "integrity": "sha512-tgTG4j0SKwLHbLRELMmgkgkjV1biYkWlGGKOmM484/fJC6bpDikdaFhfjsyE+W+qt7I5szbCPCickMTNQ+zwig==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.72.3.tgz", + "integrity": "sha512-uJx9y/1NIqoYTp6ZW1osJ7U5ZrXGAJbOQ/Qzl05BdGYvN1S7Qmbzid6xOirgK0EIT0pJKEEh1s8qbassYZe4cw==", "requires": { "@babel/core": "^7.14.0", + "@babel/plugin-proposal-async-generator-functions": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-export-default-from": "^7.0.0", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", @@ -22091,17 +18061,15 @@ "@babel/plugin-transform-destructuring": "^7.0.0", "@babel/plugin-transform-exponentiation-operator": "^7.0.0", "@babel/plugin-transform-flow-strip-types": "^7.0.0", - "@babel/plugin-transform-for-of": "^7.0.0", "@babel/plugin-transform-function-name": "^7.0.0", "@babel/plugin-transform-literals": "^7.0.0", "@babel/plugin-transform-modules-commonjs": "^7.0.0", - "@babel/plugin-transform-object-assign": "^7.0.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", "@babel/plugin-transform-parameters": "^7.0.0", "@babel/plugin-transform-react-display-name": "^7.0.0", "@babel/plugin-transform-react-jsx": "^7.0.0", "@babel/plugin-transform-react-jsx-self": "^7.0.0", "@babel/plugin-transform-react-jsx-source": "^7.0.0", - "@babel/plugin-transform-regenerator": "^7.0.0", "@babel/plugin-transform-runtime": "^7.0.0", "@babel/plugin-transform-shorthand-properties": "^7.0.0", "@babel/plugin-transform-spread": "^7.0.0", @@ -22114,43 +18082,47 @@ } }, "metro-react-native-babel-transformer": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.67.0.tgz", - "integrity": "sha512-P0JT09n7T01epUtgL9mH6BPat3xn4JjBakl4lWHdL61cvEGcrxuIom1eoFFKkgU/K5AVLU4aCAttHS7nSFCcEQ==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.72.3.tgz", + "integrity": "sha512-Ogst/M6ujYrl/+9mpEWqE3zF7l2mTuftDTy3L8wZYwX1pWUQWQpfU1aJBeWiLxt1XlIq+uriRjKzKoRoIK57EA==", "requires": { "@babel/core": "^7.14.0", "babel-preset-fbjs": "^3.4.0", - "hermes-parser": "0.5.0", - "metro-babel-transformer": "0.67.0", - "metro-react-native-babel-preset": "0.67.0", - "metro-source-map": "0.67.0", + "hermes-parser": "0.8.0", + "metro-babel-transformer": "0.72.3", + "metro-react-native-babel-preset": "0.72.3", + "metro-source-map": "0.72.3", "nullthrows": "^1.1.1" } }, "metro-resolver": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.67.0.tgz", - "integrity": "sha512-d2KS/zAyOA/z/q4/ff41rAp+1txF4H6qItwpsls/RHStV2j6PqgRHUzq/3ga+VIeoUJntYJ8nGW3+3qSrhFlig==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.72.3.tgz", + "integrity": "sha512-wu9zSMGdxpKmfECE7FtCdpfC+vrWGTdVr57lDA0piKhZV6VN6acZIvqQ1yZKtS2WfKsngncv5VbB8Y5eHRQP3w==", "requires": { "absolute-path": "^0.0.0" } }, "metro-runtime": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.67.0.tgz", - "integrity": "sha512-IFtSL0JUt1xK3t9IoLflTDft82bjieSzdIJWLzrRzBMlesz8ox5bVmnpQbVQEwfYUpEOxbM3VOZauVbdCmXA7g==" + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.72.3.tgz", + "integrity": "sha512-3MhvDKfxMg2u7dmTdpFOfdR71NgNNo4tzAyJumDVQKwnHYHN44f2QFZQqpPBEmqhWlojNeOxsqFsjYgeyMx6VA==", + "requires": { + "@babel/runtime": "^7.0.0", + "react-refresh": "^0.4.0" + } }, "metro-source-map": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.67.0.tgz", - "integrity": "sha512-yxypInsRo3SfS00IgTuL6a2W2tfwLY//vA2E+GeqGBF5zTbJZAhwNGIEl8S87XXZhwzJcxf5/8LjJC1YDzabww==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.72.3.tgz", + "integrity": "sha512-eNtpjbjxSheXu/jYCIDrbNEKzMGOvYW6/ePYpRM7gDdEagUOqKOCsi3St8NJIQJzZCsxD2JZ2pYOiomUSkT1yQ==", "requires": { "@babel/traverse": "^7.14.0", "@babel/types": "^7.0.0", "invariant": "^2.2.4", - "metro-symbolicate": "0.67.0", + "metro-symbolicate": "0.72.3", "nullthrows": "^1.1.1", - "ob1": "0.67.0", + "ob1": "0.72.3", "source-map": "^0.5.6", "vlq": "^1.0.0" }, @@ -22158,17 +18130,17 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" } } }, "metro-symbolicate": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.67.0.tgz", - "integrity": "sha512-ZqVVcfa0xSz40eFzA5P8pCF3V6Tna9RU1prFzAJTa3j9dCGqwh0HTXC8AIkMtgX7hNdZrCJI1YipzUBlwkT0/A==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.72.3.tgz", + "integrity": "sha512-eXG0NX2PJzJ/jTG4q5yyYeN2dr1cUqUaY7worBB0SP5bRWRc3besfb+rXwfh49wTFiL5qR0oOawkU4ZiD4eHXw==", "requires": { "invariant": "^2.2.4", - "metro-source-map": "0.67.0", + "metro-source-map": "0.72.3", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "through2": "^2.0.1", @@ -22178,14 +18150,14 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" } } }, "metro-transform-plugins": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.67.0.tgz", - "integrity": "sha512-DQFoSDIJdTMPDTUlKaCNJjEXiHGwFNneAF9wDSJ3luO5gigM7t7MuSaPzF4hpjmfmcfPnRhP6AEn9jcza2Sh8Q==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.72.3.tgz", + "integrity": "sha512-D+TcUvCKZbRua1+qujE0wV1onZvslW6cVTs7dLCyC2pv20lNHjFr1GtW01jN2fyKR2PcRyMjDCppFd9VwDKnSg==", "requires": { "@babel/core": "^7.14.0", "@babel/generator": "^7.14.0", @@ -22195,32 +18167,32 @@ } }, "metro-transform-worker": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.67.0.tgz", - "integrity": "sha512-29n+JdTb80ROiv/wDiBVlY/xRAF/nrjhp/Udv/XJl1DZb+x7JEiPxpbpthPhwwl+AYxVrostGB0W06WJ61hfiw==", + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.72.3.tgz", + "integrity": "sha512-WsuWj9H7i6cHuJuy+BgbWht9DK5FOgJxHLGAyULD5FJdTG9rSMFaHDO5WfC0OwQU5h4w6cPT40iDuEGksM7+YQ==", "requires": { "@babel/core": "^7.14.0", "@babel/generator": "^7.14.0", "@babel/parser": "^7.14.0", "@babel/types": "^7.0.0", "babel-preset-fbjs": "^3.4.0", - "metro": "0.67.0", - "metro-babel-transformer": "0.67.0", - "metro-cache": "0.67.0", - "metro-cache-key": "0.67.0", - "metro-hermes-compiler": "0.67.0", - "metro-source-map": "0.67.0", - "metro-transform-plugins": "0.67.0", + "metro": "0.72.3", + "metro-babel-transformer": "0.72.3", + "metro-cache": "0.72.3", + "metro-cache-key": "0.72.3", + "metro-hermes-compiler": "0.72.3", + "metro-source-map": "0.72.3", + "metro-transform-plugins": "0.72.3", "nullthrows": "^1.1.1" } }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "miller-rabin": { @@ -22245,22 +18217,22 @@ "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" }, "mime-db": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", - "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==" + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", - "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "requires": { - "mime-db": "1.47.0" + "mime-db": "1.52.0" } }, "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, "minimalistic-assert": { "version": "1.0.1", @@ -22270,7 +18242,7 @@ "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" }, "minimatch": { "version": "3.1.2", @@ -22281,9 +18253,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" }, "mixin-deep": { "version": "1.3.2", @@ -22292,16 +18264,6 @@ "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } } }, "mkdirp": { @@ -22338,13 +18300,21 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "peer": true + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true, + "peer": true }, "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "neo-async": { "version": "2.6.2", @@ -22357,9 +18327,9 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, "nocache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz", - "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==" + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/nocache/-/nocache-3.0.4.tgz", + "integrity": "sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==" }, "node-dir": { "version": "0.1.17", @@ -22372,91 +18342,16 @@ "node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - }, - "dependencies": { - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" - }, - "node-notifier": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", - "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", - "dev": true, - "optional": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" - }, - "dependencies": { - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "optional": true, - "requires": { - "is-docker": "^2.0.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "optional": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "optional": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "optional": true, - "requires": { - "isexe": "^2.0.0" - } - } + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" } }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + }, "node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", @@ -22467,26 +18362,6 @@ "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==" }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -22495,9 +18370,16 @@ "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", "requires": { "path-key": "^2.0.0" + }, + "dependencies": { + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" + } } }, "nullthrows": { @@ -22505,26 +18387,20 @@ "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, "ob1": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.67.0.tgz", - "integrity": "sha512-YvZtX8HKYackQ5PwdFIuuNFVsMChRPHvnARRRT0Vk59xsBvL5t9U1Ock3M1sYrKj+Gp73+0q9xcHLAxI+xLi5g==" + "version": "0.72.3", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.72.3.tgz", + "integrity": "sha512-OnVto25Sj7Ghp0vVm2THsngdze3tVq0LOg9LUHsAVXMecpqOP0Y8zaATW8M9gEgs2lNEAcCqV0P/hlmOPhVRvg==" }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "requires": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", @@ -22534,15 +18410,48 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -22555,31 +18464,16 @@ "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "dev": true }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, - "object-path": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", - "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==" - }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "requires": { "isobject": "^3.0.0" } @@ -22631,7 +18525,7 @@ "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "requires": { "isobject": "^3.0.1" } @@ -22650,7 +18544,7 @@ "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "requires": { "ee-first": "1.1.1" } @@ -22663,17 +18557,17 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "requires": { "wrappy": "1" } }, "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "^2.1.0" } }, "open": { @@ -22689,6 +18583,7 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, + "peer": true, "requires": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -22699,60 +18594,62 @@ } }, "ora": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", - "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "requires": { - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-spinners": "^2.0.0", - "log-symbols": "^2.2.0", - "strip-ansi": "^5.2.0", + "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" }, "dependencies": { "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } } } @@ -22760,33 +18657,27 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", - "dev": true + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==" }, "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "requires": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" } }, "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "requires": { - "p-limit": "^2.2.0" + "p-limit": "^3.0.2" } }, "p-try": { @@ -22804,16 +18695,9 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "peer": true, "requires": { "callsites": "^3.0.0" - }, - "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - } } }, "parse-asn1": { @@ -22831,18 +18715,12 @@ "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" } }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -22851,34 +18729,46 @@ "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==" }, "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "peer": true }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "pbkdf2": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.8.tgz", - "integrity": "sha1-L4q/FuvsyCJ3lF10irodeHYfYeI=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "requires": { - "create-hmac": "^1.1.2" + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "picocolors": { @@ -22887,9 +18777,9 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pify": { "version": "4.0.1", @@ -22926,6 +18816,14 @@ "path-exists": "^3.0.0" } }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -22933,11 +18831,6 @@ "requires": { "p-limit": "^2.0.0" } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" } } }, @@ -22969,6 +18862,15 @@ "path-exists": "^3.0.0" } }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -22977,34 +18879,20 @@ "requires": { "p-limit": "^2.0.0" } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true } } }, - "plist": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz", - "integrity": "sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==", - "requires": { - "base64-js": "^1.5.1", - "xmlbuilder": "^9.0.7" - } - }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==" }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true + "dev": true, + "peer": true }, "pretty-format": { "version": "26.6.2", @@ -23017,23 +18905,76 @@ "react-is": "^17.0.1" }, "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } } } }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -23048,9 +18989,9 @@ } }, "prompts": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", - "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "requires": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -23066,12 +19007,6 @@ "react-is": "^16.13.1" } }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, "public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -23102,14 +19037,11 @@ } }, "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "peer": true }, "queue-microtask": { "version": "1.2.3", @@ -23140,40 +19072,30 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.1.0.tgz", + "integrity": "sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "react-devtools-core": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.24.4.tgz", - "integrity": "sha512-jbX8Yqyq4YvFEobHyXVlGaH0Cs/+EOdb3PL911bxaR5BnzbB5TE4RFHC1iOgT4vRH3VxIIrVQ7lR9vsiFFCYCA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.24.0.tgz", + "integrity": "sha512-Rw7FzYOOzcfyUPaAm9P3g0tFdGqGq2LLiAI+wjYcp6CsF3DeeMrRS3HZAho4s273C29G/DJhx0e8BpRE/QZNGg==", "requires": { "shell-quote": "^1.6.1", "ws": "^7" }, "dependencies": { "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "requires": {} } } }, - "react-i18next": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz", - "integrity": "sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==", - "requires": { - "@babel/runtime": "^7.14.5", - "html-parse-stringify": "^3.0.1" - } - }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -23185,40 +19107,40 @@ "integrity": "sha512-txfpPCQYiazVdcbMRhatqWKcAxJweUu2wDXvts5/7Wyp6+Y9cHojqXHsLPEckzutfHlxZhG8Oiundbmp8Fd6eQ==" }, "react-native": { - "version": "0.68.5", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.68.5.tgz", - "integrity": "sha512-t3kiQ/gumFV+0r/NRSIGtYxanjY4da0utFqHgkMcRPJVwXFWC0Fr8YiOeRGYO1dp8EfrSsOjtfWic/inqVYlbQ==", + "version": "0.70.7", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.70.7.tgz", + "integrity": "sha512-MvnJJXiEPuOBbf1VPY5WXIUR/n6QB/DAk5XtBz3bzinpy9YBXiiQkhGIrTpVdVt37JeHOzafhfxAMf+Rs8jpvA==", "requires": { "@jest/create-cache-key-function": "^27.0.1", - "@react-native-community/cli": "^7.0.3", - "@react-native-community/cli-platform-android": "^7.0.1", - "@react-native-community/cli-platform-ios": "^7.0.1", + "@react-native-community/cli": "9.3.2", + "@react-native-community/cli-platform-android": "9.3.1", + "@react-native-community/cli-platform-ios": "9.3.0", "@react-native/assets": "1.0.0", "@react-native/normalize-color": "2.0.0", "@react-native/polyfills": "2.0.0", "abort-controller": "^3.0.0", "anser": "^1.4.9", "base64-js": "^1.1.2", - "deprecated-react-native-prop-types": "^2.3.0", "event-target-shim": "^5.0.1", - "hermes-engine": "~0.11.0", "invariant": "^2.2.4", "jsc-android": "^250230.2.1", - "metro-react-native-babel-transformer": "0.67.0", - "metro-runtime": "0.67.0", - "metro-source-map": "0.67.0", + "memoize-one": "^5.0.0", + "metro-react-native-babel-transformer": "0.72.3", + "metro-runtime": "0.72.3", + "metro-source-map": "0.72.3", + "mkdirp": "^0.5.1", "nullthrows": "^1.1.1", "pretty-format": "^26.5.2", - "promise": "^8.2.0", - "react-devtools-core": "^4.23.0", - "react-native-codegen": "^0.0.18", - "react-native-gradle-plugin": "^0.0.6", + "promise": "^8.3.0", + "react-devtools-core": "4.24.0", + "react-native-codegen": "^0.70.6", + "react-native-gradle-plugin": "^0.70.3", "react-refresh": "^0.4.0", - "react-shallow-renderer": "16.14.1", + "react-shallow-renderer": "^16.15.0", "regenerator-runtime": "^0.13.2", - "scheduler": "^0.20.2", + "scheduler": "^0.22.0", "stacktrace-parser": "^0.1.3", - "use-subscription": ">=1.0.0 <1.6.0", + "use-sync-external-store": "^1.0.0", "whatwg-fetch": "^3.0.0", "ws": "^6.1.4" } @@ -23229,16 +19151,10 @@ "integrity": "sha512-TE4Kiy7jUyv+hugxDxitzu38sW1NqjCk4uE5IgU2WevLv7sZacaBc6PZKOShNRPGirLl1NWkaG3LDEkdb9Um5g==", "requires": {} }, - "react-native-clean-project": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/react-native-clean-project/-/react-native-clean-project-4.0.1.tgz", - "integrity": "sha512-B7rXdFC4bfA+Vv7lZ9bKS6cUDgqg04OR5D69sNnhheFBJQ1V04cIfJ1Fu0sbqRsIehqlOcySQRpp8tm7r7PvLQ==", - "dev": true - }, "react-native-codegen": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.0.18.tgz", - "integrity": "sha512-XPI9aVsFy3dvgDZvyGWrFnknNiyb22kg5nHgxa0vjWTH9ENLBgVRZt9A64xHZ8BYihH+gl0p/1JNOCIEUzRPBg==", + "version": "0.70.6", + "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.70.6.tgz", + "integrity": "sha512-kdwIhH2hi+cFnG5Nb8Ji2JwmcCxnaOOo9440ov7XDzSvGfmUStnCzl+MCW8jLjqHcE4icT7N9y+xx4f50vfBTw==", "requires": { "@babel/parser": "^7.14.0", "flow-parser": "^0.121.0", @@ -23246,23 +19162,6 @@ "nullthrows": "^1.1.1" } }, - "react-native-crypto": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/react-native-crypto/-/react-native-crypto-2.2.0.tgz", - "integrity": "sha512-eZu9Y8pa8BN9FU2pIex7MLRAi+Cd1Y6bsxfiufKh7sfraAACJvjQTeW7/zcQAT93WMfM+D0OVk+bubvkrbrUkw==", - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.4", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "3.0.8", - "public-encrypt": "^4.0.0", - "randomfill": "^1.0.3" - } - }, "react-native-exception-handler": { "version": "2.10.10", "resolved": "https://registry.npmjs.org/react-native-exception-handler/-/react-native-exception-handler-2.10.10.tgz", @@ -23279,14 +19178,14 @@ } }, "react-native-gradle-plugin": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.0.6.tgz", - "integrity": "sha512-eIlgtsmDp1jLC24dRn43hB3kEcZVqx6DUQbR0N1ABXGnMEafm9I3V3dUUeD1vh+Dy5WqijSoEwLNUPLgu5zDMg==" + "version": "0.70.3", + "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz", + "integrity": "sha512-oOanj84fJEXUg9FoEAQomA8ISG+DVIrTZ3qF7m69VQUJyOGYyDZmPqKcjvRku4KXlEH6hWO9i4ACLzNBh8gC0A==" }, "react-native-navigation": { - "version": "7.30.3", - "resolved": "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-7.30.3.tgz", - "integrity": "sha512-4XTeq60YxAsp8zeUeIMedUduQ9blUjPlhAgxKCj5ekam5GoHwqq7iKtQr43+rYbOp0+eATGAqdZ8H/+ZXP9EFw==", + "version": "7.32.1", + "resolved": "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-7.32.1.tgz", + "integrity": "sha512-qqpccWh6MqTG0hn/XeggKonSYg+h64kOsYBot/+g2EUC/Usp8TZsKi1B2gzsUrDQy8EmsF9iTBoZMIgjxFG/WQ==", "requires": { "hoist-non-react-statics": "3.x.x", "lodash": "4.17.x", @@ -23303,42 +19202,44 @@ } }, "react-native-pager-view": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.1.2.tgz", - "integrity": "sha512-qs2KSFc+7N7B+UZ6SG2sTvCkppagm5fVyRclv1KFKc7lDtrhXLzN59tXJw575LDP/dRJoXsNwqUAhZJdws6ABQ==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.1.4.tgz", + "integrity": "sha512-fmTwgGwPxGCBusKAq7gHzm+s1Yp0qh5rKPoQszaCuxrb+76KgK4Qe82jJNPUp2xTZOKSw+FbJU2QahF8ncTl+w==", "requires": {} }, - "react-native-randombytes": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/react-native-randombytes/-/react-native-randombytes-3.6.1.tgz", - "integrity": "sha512-qxkwMbOZ0Hff1V7VqpaWrR6ItkA+oF6bnI79Qp9F3Tk8WBsdKDi6m1mi3dEdFWePoRLrhJ2L03rU0yabst1tVw==", + "react-native-quick-base64": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/react-native-quick-base64/-/react-native-quick-base64-2.0.5.tgz", + "integrity": "sha512-waRcIlchdLCSzpWYqRNIN5NyE5PxKyedMQ/sTgA/fcEkBzwp3EOwjhsfVuJuBtc1bHL2Mg34pxDVBxyLU3Mu2Q==", + "requires": { + "base64-js": "^1.5.1" + } + }, + "react-native-quick-crypto": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/react-native-quick-crypto/-/react-native-quick-crypto-0.5.0.tgz", + "integrity": "sha512-NYc8r97UaKOfkHj0iyM8OD+S5U+8mTKheb/BYpu7CNJ0qt1VkwFEaWkJtOUWSRbyd24d0AKrC9+97UkroBs9JA==", "requires": { - "buffer": "^4.9.1", - "sjcl": "^1.0.3" + "@craftzdog/react-native-buffer": "^6.0.4", + "@types/node": "^17.0.31", + "crypto-browserify": "^3.12.0", + "events": "^3.3.0", + "react-native-quick-base64": "^2.0.2", + "stream-browserify": "^3.0.0", + "string_decoder": "^1.3.0" }, "dependencies": { - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } + "@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" } } }, - "react-native-splash-screen": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/react-native-splash-screen/-/react-native-splash-screen-3.3.0.tgz", - "integrity": "sha512-rGjt6HkoSXxMqH4SQUJ1gnPQlPJV8+J47+4yhgTIan4bVvAwJhEeJH7wWt9hXSdH4+VfwTS0GTaflj1Tw83IhA==", - "requires": {} - }, "react-native-track-player": { - "version": "git+ssh://git@github.com/lyswhut/react-native-track-player.git#5fb0bec8694d3783f32a1e4ed1251c163e9842f7", - "integrity": "sha512-n48QN+6YlCXRyzkBy6h5zal9jBNoTC4ti5r2sbH+9oVcYFR1r9grjKw24B9m/1tL2gdeLj/OuoPD9l5HpUF2ZA==", - "from": "react-native-track-player@git+https://github.com/lyswhut/react-native-track-player.git#5fb0bec8694d3783f32a1e4ed1251c163e9842f7", + "version": "git+ssh://git@github.com/lyswhut/react-native-track-player.git#38027954a5ac6e3d92961745e0a9633fc647f47a", + "integrity": "sha512-WLUJIbfNPTudwEhr8D70U0kwg3sQsivdFHCGjiq9ko44PmxlINFty+0g1/DmFdWZOAKUrq8y3/e6S+Uj7Uv7Bw==", + "from": "react-native-track-player@github:lyswhut/react-native-track-player#38027954a5ac6e3d92961745e0a9633fc647f47a", "requires": {} }, "react-native-vector-icons": { @@ -23350,10 +19251,13 @@ "yargs": "^16.1.1" }, "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } }, "cliui": { "version": "7.0.4", @@ -23365,14 +19269,19 @@ "wrap-ansi": "^7.0.0" } }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "ansi-regex": "^5.0.1" + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -23409,87 +19318,34 @@ } } }, - "react-redux": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", - "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", - "requires": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", - "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", - "use-sync-external-store": "^1.0.0" - }, - "dependencies": { - "react-is": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.0.0.tgz", - "integrity": "sha512-yUcBYdBBbo3QiPsgYDcfQcIkGZHfxOaoE6HLSnr1sPzMhdyxusbfKOSUbSd/ocGi32dxcj366PsTj+5oggeKKw==" - } - } - }, "react-refresh": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz", "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==" }, "react-shallow-renderer": { - "version": "16.14.1", - "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz", - "integrity": "sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==", - "requires": { - "object-assign": "^4.1.1", - "react-is": "^16.12.0 || ^17.0.0" - } - }, - "react-test-renderer": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz", - "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "react-is": "^17.0.2", - "react-shallow-renderer": "^16.13.1", - "scheduler": "^0.20.2" - }, - "dependencies": { - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - } + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", + "requires": { + "object-assign": "^4.1.1", + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" } }, "readable-stream": { - "version": "1.0.33", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", - "integrity": "sha1-OjYN1mwbHX/UcFOJhg7aHQ9hEmw=", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "readline": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", - "integrity": "sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw=" + "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==" }, "recast": { "version": "0.20.5", @@ -23509,37 +19365,6 @@ } } }, - "redux": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", - "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", - "requires": { - "@babel/runtime": "^7.9.2" - } - }, - "redux-logger": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz", - "integrity": "sha1-91VZZvMJjzyIYExEnPC69XeCdL8=", - "dev": true, - "requires": { - "deep-diff": "^0.3.5" - } - }, - "redux-subscriber": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/redux-subscriber/-/redux-subscriber-1.1.0.tgz", - "integrity": "sha1-PKwopnTOwHtungFcp6q7vawVVUM=", - "requires": { - "object-path": "^0.11.3" - } - }, - "redux-thunk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", - "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", - "requires": {} - }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -23562,6 +19387,7 @@ "version": "0.15.0", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "peer": true, "requires": { "@babel/runtime": "^7.8.4" } @@ -23587,10 +19413,11 @@ } }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "peer": true }, "regexpu-core": { "version": "5.2.1", @@ -23625,18 +19452,6 @@ } } }, - "remove-markdown": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/remove-markdown/-/remove-markdown-0.2.2.tgz", - "integrity": "sha1-ZrDO66n7d8qWNrsbAwfOIaMqEqY=", - "dev": true - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, "repeat-element": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", @@ -23645,12 +19460,12 @@ "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" }, "require-main-filename": { "version": "2.0.0", @@ -23660,51 +19475,37 @@ "reselect": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", - "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==" + "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==", + "dev": true }, "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "requires": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.9.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "peer": true }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==" }, "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "requires": { - "onetime": "^2.0.0", + "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, @@ -23720,273 +19521,68 @@ "dev": true }, "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "peer": true, "requires": { "glob": "^7.1.3" } }, "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rn-nodeify": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/rn-nodeify/-/rn-nodeify-10.3.0.tgz", - "integrity": "sha512-EZB3M4M5i8yySCWF7AAZ31xU7cpdLuIKMlVxXji9t0aY8Ojy3BAyRt1sTp0OwBgy1ejShmlIu2L4f8mToJ+uvg==", - "dev": true, - "requires": { - "@yarnpkg/lockfile": "^1.0.0", - "deep-equal": "^1.0.0", - "findit": "^2.0.0", - "fs-extra": "^0.22.1", - "minimist": "^1.1.2", - "object.pick": "^1.1.1", - "run-parallel": "^1.1.2", - "semver": "^5.0.1", - "xtend": "^4.0.0" - }, - "dependencies": { - "fs-extra": { - "version": "0.22.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.22.1.tgz", - "integrity": "sha1-X9b4BJ3JdsoZ6yNV1lgXPKvM4FY=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "rimraf": "^2.2.8" - } - }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "requires": { - "ret": "~0.1.10" - } - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "requires": { + "ret": "~0.1.10" + } + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", "dev": true, "requires": { - "xmlchars": "^2.2.0" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" } }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.22.0.tgz", + "integrity": "sha512-6QAm1BgQI88NPYymgGQLCZgvep4FyePDWFpXVK+zNSUgHwlqpJy8VEh8Et0KxTACS4VWwMousBElAZOH9nkkoQ==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "semver": { @@ -24014,6 +19610,21 @@ "statuses": "2.0.1" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -24042,7 +19653,7 @@ "serialize-error": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", - "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==" }, "serve-static": { "version": "1.15.0", @@ -24058,7 +19669,7 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "set-value": { "version": "2.0.1", @@ -24074,10 +19685,15 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { "is-extendable": "^0.1.0" } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" } } }, @@ -24104,35 +19720,26 @@ } }, "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "peer": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "peer": true }, "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "requires": { - "array-filter": "~0.0.0", - "array-map": "~0.0.0", - "array-reduce": "~0.0.0", - "jsonify": "~0.0.0" - } - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz", + "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==" }, "side-channel": { "version": "1.0.4", @@ -24146,30 +19753,15 @@ } }, "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" - }, - "simple-plist": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz", - "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==", - "requires": { - "bplist-creator": "0.1.0", - "bplist-parser": "0.3.1", - "plist": "^3.0.5" - } + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, - "sjcl": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.8.tgz", - "integrity": "sha512-LzIjEQ0S0DpIgnxMEayM1rq9aGwGRG4OnZhCdjx7glTaJtf4zRfpg87ImfjSJjoW9vKpagd82McDOwbRT5kQKQ==" - }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -24183,29 +19775,6 @@ "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - } } }, "snapdragon": { @@ -24223,10 +19792,18 @@ "use": "^3.1.0" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } @@ -24234,15 +19811,76 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { "is-extendable": "^0.1.0" } }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" } } }, @@ -24259,36 +19897,10 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "requires": { "is-descriptor": "^1.0.0" } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } } } }, @@ -24303,41 +19915,24 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } } } }, - "socket.io": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.4.tgz", - "integrity": "sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ==", + "socket.io-client": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.6.0.tgz", + "integrity": "sha512-2XOp18xnGghUICSd5ziUIS4rB0dhr6S8OvAps8y+HhOjFQlqGcf+FIh6fCIsKKZyWFxJeFPrZRNPGsHDTsz1Ug==", "requires": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", - "engine.io": "~6.2.1", - "socket.io-adapter": "~2.4.0", + "engine.io-client": "~6.4.0", "socket.io-parser": "~4.2.1" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - } } }, - "socket.io-adapter": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", - "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==" - }, "socket.io-parser": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", @@ -24345,22 +19940,12 @@ "requires": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - } } }, "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" }, "source-map-resolve": { "version": "0.5.3", @@ -24375,9 +19960,9 @@ } }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -24395,38 +19980,6 @@ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -24438,29 +19991,12 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "stackframe": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.1.tgz", - "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==" + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" }, "stacktrace-parser": { "version": "0.1.10", @@ -24473,7 +20009,7 @@ "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "requires": { "define-property": "^0.2.5", "object-copy": "^0.1.0" @@ -24482,94 +20018,107 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stream-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-1.0.0.tgz", - "integrity": "sha1-v5tKv7QrJ011FHnkTg/yZWtvEZM=", - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^1.0.27-1" - } - }, - "stream-buffers": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", - "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + }, + "stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", "requires": { - "safe-buffer": "~5.1.0" + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" } }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, + "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==", "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" + "safe-buffer": "~5.2.0" }, "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" } } }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } } } }, @@ -24590,57 +20139,53 @@ } }, "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" } }, "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" } }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "peer": true }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==" }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true + "dev": true, + "peer": true }, "sudo-prompt": { "version": "9.2.1", @@ -24648,21 +20193,11 @@ "integrity": "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==" }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" + "has-flag": "^3.0.0" } }, "supports-preserve-symlinks-flag": { @@ -24670,16 +20205,10 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, "temp": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", - "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", + "integrity": "sha512-jtnWJs6B1cZlHs9wPG7BrowKxZw/rf6+UpGAkr8AaYmiTyTO7zQlLoST8zx/8TcUPnZmeBoB+H8ARuHZaSijVw==", "requires": { "os-tmpdir": "^1.0.0", "rimraf": "~2.2.6" @@ -24688,36 +20217,16 @@ "rimraf": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" + "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==" } } }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "peer": true }, "throat": { "version": "5.0.0", @@ -24746,6 +20255,14 @@ "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } } } }, @@ -24757,12 +20274,12 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "requires": { "kind-of": "^3.0.2" }, @@ -24770,7 +20287,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -24801,47 +20318,17 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } - } - }, "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } - } + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, + "peer": true, "requires": { "@types/json5": "^0.0.29", "json5": "^1.0.1", @@ -24850,10 +20337,11 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, + "peer": true, "requires": { "minimist": "^1.2.0" } @@ -24865,34 +20353,43 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "peer": true, "requires": { "prelude-ls": "^1.2.1" } }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, "type-fest": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==" }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true }, "uglify-es": { "version": "3.3.9", @@ -24960,6 +20457,13 @@ "get-value": "^2.0.6", "is-extendable": "^0.1.1", "set-value": "^2.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + } } }, "universalify": { @@ -24970,12 +20474,12 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "requires": { "has-value": "^0.3.1", "isobject": "^3.0.0" @@ -24984,7 +20488,7 @@ "has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", "requires": { "get-value": "^2.0.3", "has-values": "^0.1.4", @@ -24994,7 +20498,7 @@ "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "requires": { "isarray": "1.0.0" } @@ -25004,14 +20508,14 @@ "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==" } } }, "update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -25022,49 +20526,25 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "peer": true, "requires": { "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } } }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" - }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==" }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, - "use-subscription": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz", - "integrity": "sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA==", - "requires": { - "object-assign": "^4.1.1" - } - }, "use-sync-external-store": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.0.0.tgz", - "integrity": "sha512-AFVsxg5GkFg8GDcxnl+Z0lMAz9rE8DGJCc28qnBuQF7lac57B5smLcT37aXpXIIPz75rW4g3eXHPjhHwdGskOw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", "requires": {} }, "utf8": { @@ -25072,147 +20552,67 @@ "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" }, - "util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "requires": { - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", - "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==" - }, - "v8-to-istanbul": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", - "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - } - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "vlq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==" }, - "void-elements": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=" - }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" - } - }, "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "requires": { - "makeerror": "1.0.x" + "makeerror": "1.0.12" } }, "wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "requires": { "defaults": "^1.0.3" } }, "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "whatwg-fetch": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "peer": true, "requires": { "isexe": "^2.0.0" } @@ -25233,13 +20633,14 @@ "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true + "dev": true, + "peer": true }, "wrap-ansi": { "version": "6.2.0", @@ -25251,25 +20652,33 @@ "strip-ansi": "^6.0.0" }, "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "ansi-regex": "^5.0.0" + "color-name": "~1.1.4" } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" } } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "write-file-atomic": { "version": "2.4.3", @@ -25289,39 +20698,10 @@ "async-limiter": "~1.0.0" } }, - "xcode": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", - "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", - "requires": { - "simple-plist": "^1.1.0", - "uuid": "^7.0.3" - } - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "xmldoc": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-1.1.2.tgz", - "integrity": "sha512-ruPC/fyPNck2BD1dpz0AZZyrEwMOrWTO5lDdIXS91rs3wtm4j+T8Rp2o+zoOYkkAxJTZRPOSnOGei1egoRmKMQ==", - "requires": { - "sax": "^1.2.1" - } + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" }, "xtend": { "version": "4.0.2", @@ -25355,6 +20735,46 @@ "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + } } }, "yargs-parser": { @@ -25364,13 +20784,19 @@ "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + } } }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" } } } diff --git a/package.json b/package.json index 1a71bd1c5..a7478a7f6 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,24 @@ { "name": "lx-music-mobile", - "version": "0.15.5", - "versionCode": 52, + "version": "1.0.0-beta.1", + "versionCode": 53, + "private": true, "scripts": { "ar": "react-native run-android", "ios": "react-native run-ios", "start": "react-native start", "sc": "react-native start --reset-cache", "test": "jest", - "lint": "eslint .", + "lint": "eslint . --ext .js,.jsx,.ts,.tsx", "rd": "react-devtools", "menu": "adb shell input keyevent 82", "bundle-android": "react-native bundle --platform android --dev true --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res", "pack:android:debug": "./gradlew assembleDebug", "pack": "npm run pack:android", - "pack:android": "./gradlew assembleRelease", + "pack:android": "cd android && gradlew.bat assembleRelease", "clear": "react-native clean-project", - "publish": "node publish", - "nodeify": "rn-nodeify --hack --install process,crypto,events,constant,console,stream,url,util", - "postinstall": "npm run nodeify" + "build:theme": "node src/theme/themes/createThemes.js", + "publish": "node publish" }, "engines": { "node": ">= 16", @@ -42,88 +42,41 @@ }, "homepage": "https://github.com/lyswhut/lx-music-mobile#readme", "dependencies": { + "@craftzdog/react-native-buffer": "^6.0.5", "@react-native-async-storage/async-storage": "^1.17.11", "@react-native-clipboard/clipboard": "^1.11.1", "@react-native-community/checkbox": "^0.5.14", - "@react-native-community/slider": "^4.3.3", - "buffer": "^6.0.3", - "console-browserify": "^1.2.0", - "events": "^3.3.0", - "i18next": "^22.1.5", - "js-htmlencode": "^0.3.0", - "lrc-file-parser": "^2.2.8", + "@react-native-community/slider": "^4.4.2", + "iconv-lite": "^0.6.3", + "lrc-file-parser": "^2.3.0", "pako": "^2.1.0", - "process": "^0.11.10", - "prop-types": "^15.8.1", - "react": "17.0.2", - "react-i18next": "^12.1.1", - "react-native": "0.68.5", + "react": "18.1.0", + "react-native": "0.70.7", "react-native-background-timer": "^2.4.1", - "react-native-crypto": "^2.2.0", "react-native-exception-handler": "^2.10.10", "react-native-fs": "^2.20.0", - "react-native-navigation": "^7.30.3", - "react-native-pager-view": "^6.1.2", - "react-native-randombytes": "^3.6.1", - "react-native-splash-screen": "^3.3.0", - "react-native-track-player": "git+https://github.com/lyswhut/react-native-track-player.git#5fb0bec8694d3783f32a1e4ed1251c163e9842f7", + "react-native-navigation": "^7.32.1", + "react-native-pager-view": "^6.1.4", + "react-native-quick-base64": "^2.0.5", + "react-native-quick-crypto": "^0.5.0", + "react-native-track-player": "github:lyswhut/react-native-track-player#38027954a5ac6e3d92961745e0a9633fc647f47a", "react-native-vector-icons": "^9.2.0", - "react-redux": "^8.0.5", - "readable-stream": "1.0.33", - "redux": "^4.2.0", - "redux-subscriber": "^1.1.0", - "redux-thunk": "^2.4.2", - "reselect": "^4.1.7", - "socket.io": "^4.5.4", - "stream-browserify": "^1.0.0", - "url": "~0.10.1", - "util": "~0.10.3" + "socket.io-client": "^4.6.0" }, "devDependencies": { - "@babel/core": "^7.20.5", - "@babel/eslint-parser": "^7.19.1", + "@babel/core": "^7.20.12", "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/runtime": "^7.20.6", - "babel-jest": "^26.6.3", - "babel-plugin-module-resolver": "^4.1.0", - "changelog-parser": "^2.8.1", - "cross-env": "^7.0.3", - "eslint": "^8.29.0", - "eslint-config-standard": "^17.0.0", - "eslint-plugin-html": "^7.1.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-react": "^7.31.11", + "@babel/runtime": "^7.20.13", + "@tsconfig/react-native": "^2.0.3", + "@types/react": "^18.0.28", + "@types/react-native": "^0.70.11", + "@types/react-native-background-timer": "^2.0.0", + "@types/react-native-vector-icons": "^6.4.13", + "babel-plugin-module-resolver": "^5.0.0", + "eslint-config-standard-with-typescript": "^34.0.0", + "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", - "jest": "^26.6.3", - "metro-react-native-babel-preset": "^0.67.0", - "react-native-clean-project": "^4.0.1", - "react-test-renderer": "17.0.2", - "redux-logger": "^3.0.6", - "rn-nodeify": "^10.3.0" - }, - "jest": { - "preset": "react-native" - }, - "react-native": { - "console": "console-browserify", - "crypto": "react-native-crypto", - "_stream_transform": "readable-stream/transform", - "_stream_readable": "readable-stream/readable", - "_stream_writable": "readable-stream/writable", - "_stream_duplex": "readable-stream/duplex", - "_stream_passthrough": "readable-stream/passthrough", - "stream": "stream-browserify" - }, - "browser": { - "console": "console-browserify", - "crypto": "react-native-crypto", - "_stream_transform": "readable-stream/transform", - "_stream_readable": "readable-stream/readable", - "_stream_writable": "readable-stream/writable", - "_stream_duplex": "readable-stream/duplex", - "_stream_passthrough": "readable-stream/passthrough", - "stream": "stream-browserify" + "metro-react-native-babel-preset": "0.72.3", + "typescript": "^4.9.5" } } diff --git a/publish/changeLog.md b/publish/changeLog.md index abe88388b..7cad2beb3 100644 --- a/publish/changeLog.md +++ b/publish/changeLog.md @@ -1,4 +1,29 @@ -### 修复 +### 不兼容性变更说明 -- 修复导入PC端v2列表文件歌曲信息转换丢失的问题 -- 修复上面问题导致的tx源评论加载失败的问题 +- 同步功能,该功能不支持与移动端v2.0.0之前版本的使用 + +### 新增 + +- 新增聚合搜索,注:由于这个方式需要对各个源的结果进行排序,所以需要以“歌曲名 歌手”的顺序输入(例如:突然的自我 伍佰),否则排序后的结果可能不是你想要的 +- 新增歌单搜索功能 +- 新增热门搜索显示,默认关闭,需要到设置-搜索设置开启 +- 新增搜索历史记录,默认关闭,需要到设置-搜索设置开启 +- 启动软件时自动回到上次的界面,例如上次退出软件时在我的收藏,下次启动软件时会自动进入我的收藏 +- 新增PC端所拥有的内置皮肤 +- 新增界面字体大小设置 +- 添加kg源评论图片展示(感谢@helloplhm-qwq) + +### 优化(界面/交互/功能) + +- 调整了首页的界面布局 +- 优化大屏幕下的字体大小及界面布局显示 + +### 优化(程序) + +- 优化程序启动性能,优化与程序交互的流畅度 +- 重构整个程序,重新梳理了程序逻辑,使其更容易扩展及维护,将大部分代码从JavaScript迁移到TypeScript +- 重写配置管理、列表管理功能,使其与PC端同步,更容易复用PC端的代码 + +### 其他 + +- 升级React Native到v0.70.7 diff --git a/shim.js b/shim.js index 9d79f386b..78351206d 100644 --- a/shim.js +++ b/shim.js @@ -1,26 +1 @@ -if (typeof __dirname === 'undefined') global.__dirname = '/' -if (typeof __filename === 'undefined') global.__filename = '' -if (typeof process === 'undefined') { - global.process = require('process') -} else { - const bProcess = require('process') - for (let p in bProcess) { - if (!(p in process)) { - process[p] = bProcess[p] - } - } -} - -process.browser = false -if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer - -// global.location = global.location || { port: 80 } -const isDev = typeof __DEV__ === 'boolean' && __DEV__ -process.env.NODE_ENV = isDev ? 'development' : 'production' -if (typeof localStorage !== 'undefined') { - localStorage.debug = isDev ? '*' : '' -} - -// If using the crypto shim, uncomment the following line to ensure -// crypto is loaded first, so it can populate global.crypto -require('crypto') +global.Buffer = require('buffer').Buffer diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 000000000..149c3cac8 --- /dev/null +++ b/src/app.ts @@ -0,0 +1,45 @@ +import '@/utils/errorHandle' +// import { init as initLog, log } from '@/utils/log' +import '@/config/globalData' +import { init as initNavigation, navigations } from '@/navigation' +import { getFontSize } from '@/utils/data' +import { Alert } from 'react-native' +import { exitApp } from './utils/nativeModules/utils' + +console.log('starting app...') + +initNavigation(async() => { + global.lx.fontSize = await getFontSize() + const { default: init } = await import('@/core/init') + let handlePushedHomeScreen: () => void + try { + handlePushedHomeScreen = await init() + } catch (err: any) { + Alert.alert('初始化失败 (Init Failed)', err.stack ?? err.message, [ + { + text: 'Exit', + onPress() { + exitApp() + }, + }, + ], { + cancelable: false, + }) + return + } + navigations.pushHomeScreen().then(() => { + handlePushedHomeScreen() + }).catch((err: any) => { + Alert.alert('Error', err.message, [ + { + text: 'Exit', + onPress() { + exitApp() + }, + }, + ], { + cancelable: false, + }) + }) +}) + diff --git a/src/components/ListItem/index.js b/src/components/ListItem/index.js deleted file mode 100644 index 87d3dee4d..000000000 --- a/src/components/ListItem/index.js +++ /dev/null @@ -1,71 +0,0 @@ -import React from 'react' -import { View, Text, StyleSheet, TouchableOpacity } from 'react-native' -import PropTypes from 'prop-types' -import { BorderWidths } from '@/theme' -import { useGetter } from '@/store' - -const ListItem = ({ data, onPress, badge }) => { - const theme = useGetter('common', 'theme') - return ( - - - - {data.title} - {!!data.badge && {data.badge}} - - {!!data.desc && {data.desc}} - - {!!data.right && {data.right}} - - ) -} - -// class ListItem extends Component { -// state = { - -// } - -// static propTypes = { -// data: PropTypes.object.isRequired, -// onPress: PropTypes.func, -// } - -// render() { -// const { data, onPress, badge } = this.props - -// } -// } - -const styles = StyleSheet.create({ - container: { - width: '100%', - flexDirection: 'row', - flexWrap: 'nowrap', - paddingTop: 10, - paddingBottom: 10, - paddingLeft: 10, - paddingRight: 10, - }, - left: { - flex: 1, - }, - title: { - fontSize: 16, - }, - desc: { - color: '#888', - }, - badge: { - - }, - right: { - flexGrow: 0, - flexShrink: 0, - flexBasis: 'auto', - justifyContent: 'center', - }, - -}) - -export default ListItem - diff --git a/src/components/MusicAddModal.js b/src/components/MusicAddModal.js deleted file mode 100644 index 4cf8c1b04..000000000 --- a/src/components/MusicAddModal.js +++ /dev/null @@ -1,201 +0,0 @@ -import React, { useCallback, useMemo, memo, useState, useRef, useEffect } from 'react' -import { View, StyleSheet, Text, ScrollView, TouchableOpacity } from 'react-native' -import Dialog from '@/components/common/Dialog' -import Button from '@/components/common/Button' -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' -import { useDimensions } from '@/utils/hooks' -import { BorderWidths } from '@/theme' -import Input from '@/components/common/Input' -import { toast } from '@/utils/tools' - -const ListItem = ({ list, onPress, musicInfo, width }) => { - const theme = useGetter('common', 'theme') - const isExists = useMemo(() => { - return list.list.some(s => s.songmid == musicInfo.songmid) - }, [list, musicInfo]) - - return ( - - - - ) -} - -const Title = ({ musicInfo, isMove }) => { - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - return ( - musicInfo - ? {t(isMove ? 'list_add_title_first_move' : 'list_add_title_first_add')} {musicInfo.name} {t('list_add_title_last')} - : null - ) -} - -const CreateUserList = ({ isEdit, hideEdit }) => { - const [text, setText] = useState('') - const inputRef = useRef() - const { t } = useTranslation() - const theme = useGetter('common', 'theme') - const createUserList = useDispatch('list', 'createUserList') - - useEffect(() => { - if (isEdit) { - setText('') - global.requestAnimationFrame(() => { - inputRef.current.focus() - }) - } - }, [isEdit]) - - const handleSubmitEditing = () => { - hideEdit() - const name = text.trim() - if (!name.length) return - createUserList({ name }) - } - - return isEdit - ? ( - - - - ) - : null -} - -export default memo(({ visible, hideModal, musicInfo, listId, isMove = false }) => { - const allList = useGetter('list', 'allList') - const addMusicToList = useDispatch('list', 'listAdd') - const moveMusicToList = useDispatch('list', 'listMove') - const { window } = useDimensions() - const theme = useGetter('common', 'theme') - const [isEdit, setIsEdit] = useState(false) - const { t } = useTranslation() - - const itemWidth = useMemo(() => { - let w = window.width * 0.9 - 20 - let n = 1 - while (true) { - if (w / n < 100 + n * 30 || n > 9) return parseInt(w / n) - n++ - } - }, [window]) - - const handleSelect = useCallback((list, isExists) => { - if (isMove) { - moveMusicToList({ - fromId: listId, - toId: list.id, - musicInfo, - }) - toast(t('list_edit_action_tip_move_success')) - hideModal() - } else { - if (isExists) { - toast(t('list_edit_action_tip_exist')) - } else { - addMusicToList({ - musicInfo, - id: list.id, - }) - toast(t('list_edit_action_tip_add_success')) - hideModal() - } - } - }, [addMusicToList, hideModal, isMove, listId, moveMusicToList, musicInfo, t]) - - const hideEdit = useCallback(() => { - setIsEdit(false) - }, []) - - useEffect(() => { - if (!visible) { - hideEdit() - } - }, [hideEdit, visible]) - - return ( - - - <View style={{ flexShrink: 1 }} onStartShouldSetResponder={() => true}> - <ScrollView style={{ flexGrow: 0 }}> - <View style={{ ...styles.list }}> - { allList.map(list => <ListItem key={list.id} list={list} musicInfo={musicInfo} onPress={handleSelect} width={itemWidth} />) } - <View style={{ ...styles.listItem, width: itemWidth }}> - <TouchableOpacity - style={{ ...styles.button, borderColor: theme.secondary20, borderStyle: 'dashed' }} - onPress={() => setIsEdit(true)}> - <Text numberOfLines={1} style={{ fontSize: 12, color: theme.secondary }}>{t('list_create')}</Text> - </TouchableOpacity> - { - isEdit - ? <CreateUserList isEdit={isEdit} hideEdit={hideEdit} /> - : null - } - </View> - </View> - </ScrollView> - </View> - </Dialog> - ) -}) - -const styles = StyleSheet.create({ - title: { - textAlign: 'center', - padding: 15, - }, - list: { - paddingLeft: 15, - paddingRight: 5, - paddingBottom: 5, - flexDirection: 'row', - flexWrap: 'wrap', - // backgroundColor: 'rgba(0,0,0,0.2)' - }, - listItem: { - // width: '50%', - paddingRight: 10, - }, - button: { - paddingTop: 8, - paddingBottom: 8, - paddingLeft: 10, - paddingRight: 10, - marginRight: 10, - marginBottom: 10, - borderRadius: 4, - width: '100%', - alignItems: 'center', - borderWidth: BorderWidths.normal2, - }, - imputContainer: { - position: 'absolute', - top: 0, - left: 0, - width: '100%', - height: '100%', - paddingBottom: 10, - // backgroundColor: 'rgba(0,0,0,0.2)', - }, - input: { - flex: 1, - fontSize: 12, - borderRadius: 4, - textAlign: 'center', - }, -}) diff --git a/src/components/MusicAddModal/CreateUserList.tsx b/src/components/MusicAddModal/CreateUserList.tsx new file mode 100644 index 000000000..d0761a11c --- /dev/null +++ b/src/components/MusicAddModal/CreateUserList.tsx @@ -0,0 +1,67 @@ +import React, { useState, useRef, useEffect } from 'react' +import { View } from 'react-native' +import Input, { InputType } from '@/components/common/Input' +import { createStyle } from '@/utils/tools' +import { useI18n } from '@/lang' +import { createUserList } from '@/core/list' +import listState from '@/store/list/state' + +export default ({ isEdit, onHide }: { + isEdit: boolean + onHide: () => void +}) => { + const [text, setText] = useState('') + const inputRef = useRef<InputType>(null) + const t = useI18n() + + useEffect(() => { + if (isEdit) { + setText('') + requestAnimationFrame(() => { + inputRef.current?.focus() + }) + } + }, [isEdit]) + + const handleSubmitEditing = () => { + onHide() + const name = text.trim() + if (!name.length) return + void createUserList(listState.userList.length, [{ id: `userlist_${Date.now()}`, name, locationUpdateTime: null }]) + } + + return isEdit + ? ( + <View style={styles.imputContainer}> + <Input + placeholder={t('list_create_input_placeholder')} + value={text} + onChangeText={setText} + ref={inputRef} + onBlur={handleSubmitEditing} + onSubmitEditing={handleSubmitEditing} + style={styles.input} + /> + </View> + ) + : null +} + +const styles = createStyle({ + imputContainer: { + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%', + paddingBottom: 10, + // backgroundColor: 'rgba(0,0,0,0.2)', + }, + input: { + flex: 1, + fontSize: 14, + borderRadius: 4, + textAlign: 'center', + height: '100%', + }, +}) diff --git a/src/components/MusicAddModal/List.tsx b/src/components/MusicAddModal/List.tsx new file mode 100644 index 000000000..cc13e602b --- /dev/null +++ b/src/components/MusicAddModal/List.tsx @@ -0,0 +1,74 @@ +import React, { useMemo, useState } from 'react' +import { ScrollView, TouchableOpacity, View } from 'react-native' + +import Text from '@/components/common/Text' +import { useMyList } from '@/store/list/hook' +import ListItem, { styles as listStyles } from './ListItem' +import CreateUserList from './CreateUserList' +import { useDimensions } from '@/utils/hooks' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import { scaleSizeW } from '@/utils/pixelRatio' + +const styles = createStyle({ + list: { + paddingLeft: 15, + paddingRight: 2, + paddingBottom: 5, + flexDirection: 'row', + flexWrap: 'wrap', + // backgroundColor: 'rgba(0,0,0,0.2)' + // justifyContent: 'center', + }, +}) +const MIN_WIDTH = scaleSizeW(150) +const PADDING = styles.list.paddingLeft + styles.list.paddingRight + + +const EditListItem = ({ itemWidth }: { + itemWidth: number +}) => { + const [isEdit, setEdit] = useState(false) + const theme = useTheme() + const t = useI18n() + + return ( + <View style={{ ...listStyles.listItem, width: itemWidth }}> + <TouchableOpacity + style={{ ...listStyles.button, borderColor: theme['c-primary-light-200-alpha-700'], borderStyle: 'dashed' }} + onPress={() => { setEdit(true) }} + > + <Text style={{ opacity: isEdit ? 0 : 1 }} numberOfLines={1} size={14} color={theme['c-button-font']}>{t('list_create')}</Text> + </TouchableOpacity> + { + isEdit + ? <CreateUserList isEdit={isEdit} onHide={() => { setEdit(false) }} /> + : null + } + </View> + ) +} + +export default ({ musicInfo, onPress }: { + musicInfo: LX.Music.MusicInfo + onPress: (listInfo: LX.List.MyListInfo) => void +}) => { + const { window } = useDimensions() + const allList = useMyList() + const itemWidth = useMemo(() => { + let w = Math.floor(window.width * 0.9 - PADDING) + let n = Math.floor(w / MIN_WIDTH) + if (n > 10) n = 10 + return Math.floor((w - 1) / n) + }, [window]) + + return ( + <ScrollView style={{ flexGrow: 0 }}> + <View style={styles.list}> + { allList.map(info => <ListItem key={info.id} listInfo={info} musicInfo={musicInfo} onPress={onPress} width={itemWidth} />) } + <EditListItem itemWidth={itemWidth} /> + </View> + </ScrollView> + ) +} diff --git a/src/components/MusicAddModal/ListItem.tsx b/src/components/MusicAddModal/ListItem.tsx new file mode 100644 index 000000000..98f717746 --- /dev/null +++ b/src/components/MusicAddModal/ListItem.tsx @@ -0,0 +1,57 @@ +import React from 'react' +import { View } from 'react-native' +import Button from '@/components/common/Button' +import Text from '@/components/common/Text' +import { BorderWidths } from '@/theme' +import { createStyle, toast } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { useMusicExistsList } from '@/store/list/hook' + +export default ({ listInfo, onPress, musicInfo, width }: { + listInfo: LX.List.MyListInfo + onPress: (listInfo: LX.List.MyListInfo) => void + musicInfo: LX.Music.MusicInfo + width: number +}) => { + const theme = useTheme() + const isExists = useMusicExistsList(listInfo, musicInfo) + + const handlePress = () => { + if (isExists) { + toast(global.i18n.t('list_add_tip_exists')) + return + } + onPress(listInfo) + } + + return ( + <View style={{ ...styles.listItem, width }}> + <Button + style={{ ...styles.button, backgroundColor: theme['c-button-background'], borderColor: theme['c-primary-light-400-alpha-300'], opacity: isExists ? 0.4 : 1 }} + onPress={handlePress} + > + <Text numberOfLines={1} size={14} color={theme['c-button-font']}>{listInfo.name}</Text> + </Button> + </View> + ) +} + +export const styles = createStyle({ + listItem: { + // width: '50%', + paddingRight: 13, + // backgroundColor: 'rgba(0,0,0,0.2)', + }, + button: { + height: 34, + paddingLeft: 10, + paddingRight: 10, + marginRight: 10, + marginBottom: 10, + borderRadius: 4, + width: '100%', + alignItems: 'center', + justifyContent: 'center', + borderWidth: BorderWidths.normal2, + }, +}) diff --git a/src/components/MusicAddModal/MusicAddModal.tsx b/src/components/MusicAddModal/MusicAddModal.tsx new file mode 100644 index 000000000..a2b8e78a3 --- /dev/null +++ b/src/components/MusicAddModal/MusicAddModal.tsx @@ -0,0 +1,86 @@ +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' +import Dialog, { type DialogType } from '@/components/common/Dialog' +import { toast } from '@/utils/tools' +import Title from './Title' +import List from './List' +import { useI18n } from '@/lang' +import { addListMusics, moveListMusics } from '@/core/list' +import settingState from '@/store/setting/state' + +export interface SelectInfo { + musicInfo: LX.Music.MusicInfo | null + listId: string + isMove: boolean + // single: boolean +} +const initSelectInfo = {} + +// export interface MusicAddModalProps { +// onRename: (listInfo: LX.List.UserListInfo) => void +// onImport: (listInfo: LX.List.MyListInfo, index: number) => void +// onExport: (listInfo: LX.List.MyListInfo, index: number) => void +// onSync: (listInfo: LX.List.UserListInfo) => void +// onRemove: (listInfo: LX.List.UserListInfo) => void +// } +export interface MusicAddModalType { + show: (info: SelectInfo) => void +} + +export default forwardRef<MusicAddModalType, {}>((props, ref) => { + const t = useI18n() + const dialogRef = useRef<DialogType>(null) + const [selectInfo, setSelectInfo] = useState<SelectInfo>(initSelectInfo as SelectInfo) + + useImperativeHandle(ref, () => ({ + show(selectInfo) { + setSelectInfo(selectInfo) + + requestAnimationFrame(() => { + dialogRef.current?.setVisible(true) + }) + }, + })) + + const handleHide = () => { + requestAnimationFrame(() => { + setSelectInfo({ ...selectInfo, musicInfo: null }) + }) + } + + const handleSelect = (listInfo: LX.List.MyListInfo) => { + dialogRef.current?.setVisible(false) + if (selectInfo.isMove) { + void moveListMusics(selectInfo.listId, listInfo.id, + [selectInfo.musicInfo as LX.Music.MusicInfo], + settingState.setting['list.addMusicLocationType'], + ).then(() => { + toast(t('list_edit_action_tip_move_success')) + }).catch(() => { + toast(t('list_edit_action_tip_move_failed')) + }) + } else { + void addListMusics(listInfo.id, + [selectInfo.musicInfo as LX.Music.MusicInfo], + settingState.setting['list.addMusicLocationType'], + ).then(() => { + toast(t('list_edit_action_tip_add_success')) + }).catch(() => { + toast(t('list_edit_action_tip_add_failed')) + }) + } + } + + return ( + <Dialog ref={dialogRef} onHide={handleHide}> + { + selectInfo.musicInfo + ? (<> + <Title musicInfo={selectInfo.musicInfo} isMove={selectInfo.isMove} /> + <List musicInfo={selectInfo.musicInfo} onPress={handleSelect} /> + </>) + : null + } + </Dialog> + ) +}) + diff --git a/src/components/MusicAddModal/Title.tsx b/src/components/MusicAddModal/Title.tsx new file mode 100644 index 000000000..eeefd7235 --- /dev/null +++ b/src/components/MusicAddModal/Title.tsx @@ -0,0 +1,26 @@ +import React from 'react' +import Text from '@/components/common/Text' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' + +export default ({ musicInfo, isMove }: { + musicInfo: LX.Music.MusicInfo + isMove: boolean +}) => { + const theme = useTheme() + const t = useI18n() + return ( + <Text style={styles.title}> + {t(isMove ? 'list_add_title_first_move' : 'list_add_title_first_add')} <Text color={theme['c-primary-font']}>{musicInfo.name}</Text> {t('list_add_title_last')} + </Text> + ) +} + +const styles = createStyle({ + title: { + textAlign: 'center', + paddingTop: 15, + paddingBottom: 15, + }, +}) diff --git a/src/components/MusicAddModal/index.tsx b/src/components/MusicAddModal/index.tsx new file mode 100644 index 000000000..73bf0457d --- /dev/null +++ b/src/components/MusicAddModal/index.tsx @@ -0,0 +1,29 @@ +import React, { useRef, useImperativeHandle, forwardRef, useState } from 'react' +import Modal, { type MusicAddModalType as ModalType, type SelectInfo } from './MusicAddModal' + +export interface MusicAddModalType { + show: (info: SelectInfo) => void +} + +export default forwardRef<MusicAddModalType, {}>((props, ref) => { + const musicAddModalRef = useRef<ModalType>(null) + const [visible, setVisible] = useState(false) + + useImperativeHandle(ref, () => ({ + show(listInfo) { + if (visible) musicAddModalRef.current?.show(listInfo) + else { + setVisible(true) + requestAnimationFrame(() => { + musicAddModalRef.current?.show(listInfo) + }) + } + }, + })) + + return ( + visible + ? <Modal ref={musicAddModalRef} /> + : null + ) +}) diff --git a/src/components/MusicMultiAddModal.js b/src/components/MusicMultiAddModal.js deleted file mode 100644 index 7fafdbc4e..000000000 --- a/src/components/MusicMultiAddModal.js +++ /dev/null @@ -1,199 +0,0 @@ -import React, { useCallback, useMemo, memo, useState, useRef, useEffect } from 'react' -import { View, StyleSheet, Text, ScrollView, TouchableOpacity } from 'react-native' -import Dialog from '@/components/common/Dialog' -import Button from '@/components/common/Button' -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' -import { useDimensions } from '@/utils/hooks' -import { BorderWidths } from '@/theme' -import Input from '@/components/common/Input' -import { toast } from '@/utils/tools' - - -const ListItem = ({ list, onPress, width }) => { - const theme = useGetter('common', 'theme') - - return ( - <View style={{ ...styles.listItem, width: width }}> - <Button - style={{ ...styles.button, backgroundColor: theme.secondary45, borderColor: theme.secondary45 }} - onPress={() => { onPress(list) }} - > - <Text numberOfLines={1} style={{ fontSize: 12, color: theme.secondary }}>{list.name}</Text> - </Button> - </View> - ) -} - -const Title = ({ list, isMove }) => { - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - return ( - list.length - ? <Text style={{ ...styles.title, color: theme.normal }}>{t(isMove ? 'list_multi_add_title_first_move' : 'list_multi_add_title_first_add')} <Text style={{ color: theme.secondary }} >{list.length}</Text> {t('list_multi_add_title_last')}</Text> - : null - ) -} - -const CreateUserList = ({ isEdit, hideEdit }) => { - const [text, setText] = useState('') - const inputRef = useRef() - const { t } = useTranslation() - const theme = useGetter('common', 'theme') - const createUserList = useDispatch('list', 'createUserList') - - useEffect(() => { - if (isEdit) { - setText('') - global.requestAnimationFrame(() => { - inputRef.current.focus() - }) - } - }, [isEdit]) - - const handleSubmitEditing = () => { - hideEdit() - const name = text.trim() - if (!name.length) return - createUserList({ name }) - } - - return isEdit - ? ( - <View style={styles.imputContainer}> - <Input - placeholder={t('list_create_input_placeholder')} - value={text} - onChangeText={setText} - ref={inputRef} - onBlur={handleSubmitEditing} - onSubmitEditing={handleSubmitEditing} - style={{ ...styles.input, backgroundColor: theme.secondary45 }} - /> - </View> - ) - : null -} - -export default memo(({ visible, hideModal, list, onAdd, excludeList = [], listId, isMove = false }) => { - const allList = useGetter('list', 'allList') - const addMultiMusicToList = useDispatch('list', 'listAddMultiple') - const moveMultiMusicToList = useDispatch('list', 'listMoveMultiple') - const { window } = useDimensions() - const theme = useGetter('common', 'theme') - const [isEdit, setIsEdit] = useState(false) - const { t } = useTranslation() - - const itemWidth = useMemo(() => { - let w = window.width * 0.9 - 20 - let n = 1 - while (true) { - if (w / n < 100 + n * 30 || n > 9) return parseInt(w / n) - n++ - } - }, [window]) - - const handleSelect = useCallback(({ id }) => { - if (isMove) { - moveMultiMusicToList({ - fromId: listId, - toId: id, - list, - }) - toast(t('list_edit_action_tip_move_success')) - } else { - addMultiMusicToList({ - list, - id, - }) - toast(t('list_edit_action_tip_add_success')) - } - hideModal() - onAdd() - }, [isMove, hideModal, onAdd, moveMultiMusicToList, listId, list, t, addMultiMusicToList]) - - const filteredList = useMemo(() => { - return allList.filter(({ id }) => !excludeList.includes(id)) - }, [allList, excludeList]) - - const hideEdit = useCallback(() => { - setIsEdit(false) - }, []) - - useEffect(() => { - if (!visible) { - hideEdit() - } - }, [hideEdit, visible]) - - return ( - <Dialog visible={visible} hideDialog={hideModal}> - <Title list={list} isMove={isMove} /> - <View style={{ flexShrink: 1 }} onStartShouldSetResponder={() => true}> - <ScrollView style={{ flexGrow: 0 }}> - <View style={{ ...styles.list }}> - { filteredList.map(list => <ListItem key={list.id} list={list} onPress={handleSelect} width={itemWidth} />) } - <View style={{ ...styles.listItem, width: itemWidth }}> - <TouchableOpacity - style={{ ...styles.button, borderColor: theme.secondary20, borderStyle: 'dashed' }} - onPress={() => setIsEdit(true)}> - <Text numberOfLines={1} style={{ fontSize: 12, color: theme.secondary }}>{t('list_create')}</Text> - </TouchableOpacity> - { - isEdit - ? <CreateUserList isEdit={isEdit} hideEdit={hideEdit} /> - : null - } - </View> - </View> - </ScrollView> - </View> - </Dialog> - ) -}) - -const styles = StyleSheet.create({ - title: { - textAlign: 'center', - padding: 15, - }, - list: { - paddingLeft: 15, - paddingRight: 5, - paddingBottom: 5, - flexDirection: 'row', - flexWrap: 'wrap', - // backgroundColor: 'rgba(0,0,0,0.2)' - }, - listItem: { - // width: '50%', - paddingRight: 10, - }, - button: { - paddingTop: 8, - paddingBottom: 8, - paddingLeft: 10, - paddingRight: 10, - marginRight: 10, - marginBottom: 10, - borderRadius: 4, - width: '100%', - alignItems: 'center', - borderWidth: BorderWidths.normal2, - }, - imputContainer: { - position: 'absolute', - top: 0, - left: 0, - width: '100%', - height: '100%', - paddingBottom: 10, - // backgroundColor: 'rgba(0,0,0,0.2)', - }, - input: { - flex: 1, - fontSize: 12, - borderRadius: 4, - textAlign: 'center', - }, -}) diff --git a/src/components/MusicMultiAddModal/List.tsx b/src/components/MusicMultiAddModal/List.tsx new file mode 100644 index 000000000..559b39d08 --- /dev/null +++ b/src/components/MusicMultiAddModal/List.tsx @@ -0,0 +1,72 @@ +import React, { useMemo, useState } from 'react' +import { ScrollView, TouchableOpacity, View } from 'react-native' + +import Text from '@/components/common/Text' +import { useMyList } from '@/store/list/hook' +import ListItem, { styles as listStyles } from './ListItem' +import CreateUserList from '../MusicAddModal/CreateUserList' +import { useDimensions } from '@/utils/hooks' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import { scaleSizeW } from '@/utils/pixelRatio' + +const styles = createStyle({ + list: { + paddingLeft: 15, + paddingRight: 2, + paddingBottom: 5, + flexDirection: 'row', + flexWrap: 'wrap', + // backgroundColor: 'rgba(0,0,0,0.2)' + }, +}) +const MIN_WIDTH = scaleSizeW(140) +const PADDING = styles.list.paddingLeft + styles.list.paddingRight + +const EditListItem = ({ itemWidth }: { + itemWidth: number +}) => { + const [isEdit, setEdit] = useState(false) + const theme = useTheme() + const t = useI18n() + + return ( + <View style={{ ...listStyles.listItem, width: itemWidth }}> + <TouchableOpacity + style={{ ...listStyles.button, borderColor: theme['c-primary-light-200-alpha-700'], borderStyle: 'dashed' }} + onPress={() => { setEdit(true) }} + > + <Text style={{ opacity: isEdit ? 0 : 1 }} numberOfLines={1} size={14} color={theme['c-button-font']}>{t('list_create')}</Text> + </TouchableOpacity> + { + isEdit + ? <CreateUserList isEdit={isEdit} onHide={() => { setEdit(false) }} /> + : null + } + </View> + ) +} + +export default ({ listId, onPress }: { + listId: string + onPress: (listInfo: LX.List.MyListInfo) => void +}) => { + const { window } = useDimensions() + const allList = useMyList().filter(l => l.id != listId) + const itemWidth = useMemo(() => { + let w = Math.floor(window.width * 0.9 - PADDING) + let n = Math.floor(w / MIN_WIDTH) + if (n > 10) n = 10 + return Math.floor((w - 1) / n) + }, [window]) + + return ( + <ScrollView style={{ flexGrow: 0 }}> + <View style={{ ...styles.list }}> + { allList.map(info => <ListItem key={info.id} listInfo={info} onPress={onPress} width={itemWidth} />) } + <EditListItem itemWidth={itemWidth} /> + </View> + </ScrollView> + ) +} diff --git a/src/components/MusicMultiAddModal/ListItem.tsx b/src/components/MusicMultiAddModal/ListItem.tsx new file mode 100644 index 000000000..f85f5255c --- /dev/null +++ b/src/components/MusicMultiAddModal/ListItem.tsx @@ -0,0 +1,49 @@ +import React from 'react' +import { View } from 'react-native' +import Button from '@/components/common/Button' +import Text from '@/components/common/Text' +import { BorderWidths } from '@/theme' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' + +export default ({ listInfo, onPress, width }: { + listInfo: LX.List.MyListInfo + onPress: (listInfo: LX.List.MyListInfo) => void + width: number +}) => { + const theme = useTheme() + + const handlePress = () => { + onPress(listInfo) + } + + return ( + <View style={{ ...styles.listItem, width }}> + <Button + style={{ ...styles.button, backgroundColor: theme['c-button-background'], borderColor: theme['c-primary-light-200-alpha-700'] }} + onPress={handlePress} + > + <Text numberOfLines={1} size={14} color={theme['c-button-font']}>{listInfo.name}</Text> + </Button> + </View> + ) +} + +export const styles = createStyle({ + listItem: { + // width: '50%', + paddingRight: 13, + }, + button: { + height: 34, + paddingLeft: 10, + paddingRight: 10, + marginRight: 10, + marginBottom: 10, + borderRadius: 4, + width: '100%', + alignItems: 'center', + justifyContent: 'center', + borderWidth: BorderWidths.normal2, + }, +}) diff --git a/src/components/MusicMultiAddModal/MusicMultiAddModal.tsx b/src/components/MusicMultiAddModal/MusicMultiAddModal.tsx new file mode 100644 index 000000000..75cbaa593 --- /dev/null +++ b/src/components/MusicMultiAddModal/MusicMultiAddModal.tsx @@ -0,0 +1,86 @@ +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' +import Dialog, { DialogType } from '@/components/common/Dialog' +import { toast } from '@/utils/tools' +import Title from './Title' +import List from './List' +import { useI18n } from '@/lang' +import { addListMusics, moveListMusics } from '@/core/list' +import settingState from '@/store/setting/state' + +export interface SelectInfo { + selectedList: LX.Music.MusicInfo[] + listId: string + isMove: boolean + // single: boolean +} +const initSelectInfo = { selectedList: [], listId: '', isMove: false } + +// export interface MusicMultiAddModalProps { +// onRename: (listInfo: LX.List.UserListInfo) => void +// onImport: (listInfo: LX.List.MyListInfo, index: number) => void +// onExport: (listInfo: LX.List.MyListInfo, index: number) => void +// onSync: (listInfo: LX.List.UserListInfo) => void +// onRemove: (listInfo: LX.List.UserListInfo) => void +// } +export interface MusicMultiAddModalType { + show: (info: SelectInfo) => void +} + +export default forwardRef<MusicMultiAddModalType, {}>((props, ref) => { + const t = useI18n() + const dialogRef = useRef<DialogType>(null) + const [selectInfo, setSelectInfo] = useState<SelectInfo>(initSelectInfo) + + useImperativeHandle(ref, () => ({ + show(selectInfo) { + setSelectInfo(selectInfo) + + requestAnimationFrame(() => { + dialogRef.current?.setVisible(true) + }) + }, + })) + + const handleHide = () => { + requestAnimationFrame(() => { + setSelectInfo({ ...selectInfo, selectedList: [] }) + }) + } + + const handleSelect = (listInfo: LX.List.MyListInfo) => { + dialogRef.current?.setVisible(false) + if (selectInfo.isMove) { + void moveListMusics(selectInfo.listId, listInfo.id, + [...selectInfo.selectedList], + settingState.setting['list.addMusicLocationType'], + ).then(() => { + toast(t('list_edit_action_tip_move_success')) + }).catch(() => { + toast(t('list_edit_action_tip_move_failed')) + }) + } else { + void addListMusics(listInfo.id, + [...selectInfo.selectedList], + settingState.setting['list.addMusicLocationType'], + ).then(() => { + toast(t('list_edit_action_tip_add_success')) + }).catch(() => { + toast(t('list_edit_action_tip_add_failed')) + }) + } + } + + return ( + <Dialog ref={dialogRef} onHide={handleHide}> + { + selectInfo.selectedList.length + ? (<> + <Title selectedList={selectInfo.selectedList} isMove={selectInfo.isMove} /> + <List listId={selectInfo.listId} onPress={handleSelect} /> + </>) + : null + } + </Dialog> + ) +}) + diff --git a/src/components/MusicMultiAddModal/Title.tsx b/src/components/MusicMultiAddModal/Title.tsx new file mode 100644 index 000000000..0ae7a7422 --- /dev/null +++ b/src/components/MusicMultiAddModal/Title.tsx @@ -0,0 +1,26 @@ +import React from 'react' +import Text from '@/components/common/Text' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' + +export default ({ selectedList, isMove }: { + selectedList: LX.Music.MusicInfo[] + isMove: boolean +}) => { + const theme = useTheme() + const t = useI18n() + return ( + <Text style={styles.title} size={16}> + {t(isMove ? 'list_multi_add_title_first_move' : 'list_multi_add_title_first_add')} <Text color={theme['c-primary-font']} size={16}>{selectedList.length}</Text> {t('list_multi_add_title_last')} + </Text> + ) +} + +const styles = createStyle({ + title: { + textAlign: 'center', + paddingTop: 15, + paddingBottom: 15, + }, +}) diff --git a/src/components/MusicMultiAddModal/index.tsx b/src/components/MusicMultiAddModal/index.tsx new file mode 100644 index 000000000..625d3adc5 --- /dev/null +++ b/src/components/MusicMultiAddModal/index.tsx @@ -0,0 +1,29 @@ +import React, { useRef, useImperativeHandle, forwardRef, useState } from 'react' +import Modal, { MusicMultiAddModalType as ModalType, SelectInfo } from './MusicMultiAddModal' + +export interface MusicMultiAddModalType { + show: (info: SelectInfo) => void +} + +export default forwardRef<MusicMultiAddModalType, {}>((props, ref) => { + const musicMultiAddModalRef = useRef<ModalType>(null) + const [visible, setVisible] = useState(false) + + useImperativeHandle(ref, () => ({ + show(listInfo) { + if (visible) musicMultiAddModalRef.current?.show(listInfo) + else { + setVisible(true) + requestAnimationFrame(() => { + musicMultiAddModalRef.current?.show(listInfo) + }) + } + }, + })) + + return ( + visible + ? <Modal ref={musicMultiAddModalRef} /> + : null + ) +}) diff --git a/src/components/OnlineList/ExitMultipleModeBar.js b/src/components/OnlineList/ExitMultipleModeBar.js deleted file mode 100644 index 57bc10438..000000000 --- a/src/components/OnlineList/ExitMultipleModeBar.js +++ /dev/null @@ -1,142 +0,0 @@ -import React, { useState, useRef, useEffect, useCallback, useMemo, memo } from 'react' -import { Text, StyleSheet, Animated, View, TouchableOpacity } from 'react-native' -import { useTranslation } from '@/plugins/i18n' - -import Button from '@/components/common/Button' -import { useGetter } from '@/store' - - -export default memo(({ multipleMode, onCancel, onSelectAll, selectMode, onSwitchMode, isSelectAll }) => { - const { t } = useTranslation() - // const isGetDetailFailedRef = useRef(false) - const [visible, setVisible] = useState(false) - const [animatePlayed, setAnimatPlayed] = useState(true) - const animFade = useRef(new Animated.Value(0)).current - const animTranslateY = useRef(new Animated.Value(0)).current - - const theme = useGetter('common', 'theme') - - useEffect(() => { - setAnimatPlayed(true) - if (multipleMode) { - animFade.setValue(0.92) - animTranslateY.setValue(0) - setVisible(true) - } else { - animFade.setValue(0) - animTranslateY.setValue(20) - setVisible(false) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - const showList = useCallback(() => { - // console.log('show List') - setVisible(true) - setAnimatPlayed(false) - animTranslateY.setValue(20) - - Animated.parallel([ - Animated.timing(animFade, { - toValue: 0.92, - duration: 200, - useNativeDriver: true, - }), - Animated.timing(animTranslateY, { - toValue: 0, - duration: 200, - useNativeDriver: true, - }), - ]).start(() => { - setAnimatPlayed(true) - }) - }, [animFade, animTranslateY]) - - const hideList = useCallback(() => { - setAnimatPlayed(false) - Animated.parallel([ - Animated.timing(animFade, { - toValue: 0, - duration: 200, - useNativeDriver: true, - }), - Animated.timing(animTranslateY, { - toValue: 20, - duration: 200, - useNativeDriver: true, - }), - ]).start(finished => { - if (!finished) return - setVisible(false) - setAnimatPlayed(true) - }) - }, [animFade, animTranslateY]) - - useEffect(() => { - if (multipleMode) { - showList() - } else { - hideList() - } - }, [hideList, multipleMode, showList]) - - - const animaStyle = useMemo(() => StyleSheet.compose(styles.container, { - backgroundColor: theme.secondary45, - opacity: animFade, // Bind opacity to animated value - transform: [ - { translateY: animTranslateY }, - ], - }), [animFade, animTranslateY, theme]) - - const switchModeSingle = useCallback(() => { - onSwitchMode('single') - }, [onSwitchMode]) - const switchModeRange = useCallback(() => { - onSwitchMode('range') - }, [onSwitchMode]) - - const component = useMemo(() => ( - <Animated.View style={animaStyle}> - <View style={styles.switchBtn}> - <Button onPress={switchModeSingle} style={{ ...styles.btn, backgroundColor: selectMode == 'single' ? theme.secondary40 : 'rgba(0,0,0,0)' }}> - <Text style={{ color: theme.secondary }}>{t('list_select_single')}</Text> - </Button> - <Button onPress={switchModeRange} style={{ ...styles.btn, backgroundColor: selectMode == 'range' ? theme.secondary40 : 'rgba(0,0,0,0)' }}> - <Text style={{ color: theme.secondary }}>{t('list_select_range')}</Text> - </Button> - </View> - <TouchableOpacity onPress={onSelectAll} style={styles.btn}> - <Text style={{ color: theme.secondary }}>{t(isSelectAll ? 'list_select_unall' : 'list_select_all')}</Text> - </TouchableOpacity> - <TouchableOpacity onPress={onCancel} style={styles.btn}> - <Text style={{ color: theme.secondary }}>{t('list_select_cancel')}</Text> - </TouchableOpacity> - </Animated.View> - ), [animaStyle, isSelectAll, selectMode, onCancel, onSelectAll, switchModeRange, switchModeSingle, t, theme]) - - return !visible && animatePlayed ? null : component -}) - -const styles = StyleSheet.create({ - container: { - flex: 1, - position: 'absolute', - left: 0, - bottom: 0, - width: '100%', - height: 40, - flexDirection: 'row', - }, - switchBtn: { - flexDirection: 'row', - flex: 1, - }, - btn: { - // flex: 1, - paddingLeft: 15, - paddingRight: 15, - alignItems: 'center', - justifyContent: 'center', - }, -}) diff --git a/src/components/OnlineList/Footer.js b/src/components/OnlineList/Footer.js deleted file mode 100644 index fd58c0f6c..000000000 --- a/src/components/OnlineList/Footer.js +++ /dev/null @@ -1,26 +0,0 @@ -import React, { memo } from 'react' -import { View, Text } from 'react-native' -import { useGetter } from '@/store' -import { useTranslation } from '@/plugins/i18n' - -export const Loading = memo(() => { - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - return ( - <View style={{ alignItems: 'center', padding: 10 }}> - <Text style={{ color: theme.normal30 }}>{t('list_loading')}</Text> - </View> - ) -}) - - -export const End = memo(() => { - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - return ( - <View style={{ alignItems: 'center', padding: 10 }}> - <Text style={{ color: theme.normal30 }}>{t('list_end')}</Text> - </View> - ) -}) - diff --git a/src/components/OnlineList/List.tsx b/src/components/OnlineList/List.tsx new file mode 100644 index 000000000..9d11b293e --- /dev/null +++ b/src/components/OnlineList/List.tsx @@ -0,0 +1,278 @@ +import React, { useMemo, useRef, useState, forwardRef, useImperativeHandle } from 'react' +import { FlatList, type FlatListProps, RefreshControl, View } from 'react-native' + +// import { useMusicList } from '@/store/list/hook' +import ListItem, { ITEM_HEIGHT } from './ListItem' +import { createStyle } from '@/utils/tools' +import type { Position } from './ListMenu' +import type { SelectMode } from './MultipleModeBar' +import { useTheme } from '@/store/theme/hook' +import settingState from '@/store/setting/state' +import { MULTI_SELECT_BAR_HEIGHT } from './MultipleModeBar' +import { useI18n } from '@/lang' +import Text from '@/components/common/Text' +import { handlePlay } from './listAction' + +type FlatListType = FlatListProps<LX.Music.MusicInfoOnline> + +export interface ListProps { + onShowMenu: (musicInfo: LX.Music.MusicInfoOnline, index: number, position: Position) => void + onMuiltSelectMode: () => void + onSelectAll: (isAll: boolean) => void + onRefresh: () => void + onLoadMore: () => void + onPlayList?: (index: number) => void + progressViewOffset?: number + ListHeaderComponent?: FlatListType['ListEmptyComponent'] +} +export interface ListType { + setList: (list: LX.Music.MusicInfoOnline[], showSource?: boolean) => void + setIsMultiSelectMode: (isMultiSelectMode: boolean) => void + setSelectMode: (mode: SelectMode) => void + selectAll: (isAll: boolean) => void + getSelectedList: () => LX.Music.MusicInfoOnline[] + getList: () => LX.Music.MusicInfoOnline[] + setStatus: (val: Status) => void +} +export type Status = 'loading' | 'refreshing' | 'end' | 'error' | 'idle' + + +const List = forwardRef<ListType, ListProps>(({ + onShowMenu, + onMuiltSelectMode, + onSelectAll, + onRefresh, + onLoadMore, + onPlayList, + progressViewOffset, + ListHeaderComponent, +}, ref) => { + // const t = useI18n() + const theme = useTheme() + const flatListRef = useRef<FlatList>(null) + const [currentList, setList] = useState<LX.Music.MusicInfoOnline[]>([]) + const [showSource, setShowSource] = useState(false) + const isMultiSelectModeRef = useRef(false) + const selectModeRef = useRef<SelectMode>('single') + const prevSelectIndexRef = useRef(-1) + const [selectedList, setSelectedList] = useState<LX.Music.MusicInfoOnline[]>([]) + const selectedListRef = useRef<LX.Music.MusicInfoOnline[]>([]) + const [visibleMultiSelect, setVisibleMultiSelect] = useState(false) + const [status, setStatus] = useState<Status>('idle') + // const currentListIdRef = useRef('') + // console.log('render music list') + + useImperativeHandle(ref, () => ({ + setList(list, showSource = false) { + setList(list) + setShowSource(showSource) + }, + setIsMultiSelectMode(isMultiSelectMode) { + isMultiSelectModeRef.current = isMultiSelectMode + if (!isMultiSelectMode) { + prevSelectIndexRef.current = -1 + handleUpdateSelectedList([]) + } + setVisibleMultiSelect(isMultiSelectMode) + }, + setSelectMode(mode) { + selectModeRef.current = mode + }, + selectAll(isAll) { + let list: LX.Music.MusicInfoOnline[] + if (isAll) { + list = [...currentList] + } else { + list = [] + } + selectedListRef.current = list + setSelectedList(list) + }, + getSelectedList() { + return selectedListRef.current + }, + getList() { + return currentList + }, + setStatus(val) { + setStatus(val) + }, + })) + + + const handleUpdateSelectedList = (newList: LX.Music.MusicInfoOnline[]) => { + if (selectedListRef.current.length && newList.length == currentList.length) onSelectAll(true) + else if (selectedListRef.current.length == currentList.length) onSelectAll(false) + selectedListRef.current = newList + setSelectedList(newList) + } + const handleSelect = (item: LX.Music.MusicInfoOnline, pressIndex: number) => { + let newList: LX.Music.MusicInfoOnline[] + if (selectModeRef.current == 'single') { + prevSelectIndexRef.current = pressIndex + const index = selectedListRef.current.indexOf(item) + if (index < 0) { + newList = [...selectedListRef.current, item] + } else { + newList = [...selectedListRef.current] + newList.splice(index, 1) + } + } else { + if (selectedListRef.current.length) { + const prevIndex = prevSelectIndexRef.current + const currentIndex = pressIndex + if (prevIndex == currentIndex) { + newList = [] + } else if (currentIndex > prevIndex) { + newList = currentList.slice(prevIndex, currentIndex + 1) + } else { + newList = currentList.slice(currentIndex, prevIndex + 1) + newList.reverse() + } + } else { + newList = [item] + prevSelectIndexRef.current = pressIndex + } + } + + handleUpdateSelectedList(newList) + } + + const handlePress = (item: LX.Music.MusicInfoOnline, index: number) => { + if (isMultiSelectModeRef.current) { + handleSelect(item, index) + } else { + if (settingState.setting['list.isClickPlayList'] && onPlayList != null) { + onPlayList(index) + } else { + // console.log(currentList[index]) + handlePlay(currentList[index]) + } + } + } + + const handleLongPress = (item: LX.Music.MusicInfoOnline, index: number) => { + if (isMultiSelectModeRef.current) return + prevSelectIndexRef.current = index + handleUpdateSelectedList([item]) + onMuiltSelectMode() + } + + const handleLoadMore = () => { + switch (status) { + case 'end': + case 'loading': + case 'refreshing': return + } + onLoadMore() + } + + + const renderItem: FlatListType['renderItem'] = ({ item, index }) => ( + <ListItem + item={item} + index={index} + showSource={showSource} + onPress={handlePress} + onLongPress={handleLongPress} + onShowMenu={onShowMenu} + selectedList={selectedList} + /> + ) + const getkey: FlatListType['keyExtractor'] = item => item.id + const getItemLayout: FlatListType['getItemLayout'] = (data, index) => { + return { length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index } + } + const refreshControl = useMemo(() => ( + <RefreshControl + colors={[theme['c-primary']]} + // progressBackgroundColor={theme.primary} + refreshing={status == 'refreshing'} + onRefresh={onRefresh} /> + ), [status, onRefresh, theme]) + const footerComponent = useMemo(() => { + let label: FooterLabel + switch (status) { + case 'refreshing': return null + case 'loading': + label = 'list_loading' + break + case 'end': + label = 'list_end' + break + case 'error': + label = 'list_error' + break + case 'idle': + label = null + break + } + return ( + <View style={{ width: '100%', paddingBottom: visibleMultiSelect ? MULTI_SELECT_BAR_HEIGHT : 0 }} > + <Footer label={label} onLoadMore={onLoadMore} /> + </View> + ) + }, [onLoadMore, status, visibleMultiSelect]) + + return ( + <FlatList + ref={flatListRef} + style={styles.list} + data={currentList} + maxToRenderPerBatch={4} + // updateCellsBatchingPeriod={80} + windowSize={8} + removeClippedSubviews={true} + initialNumToRender={12} + renderItem={renderItem} + keyExtractor={getkey} + getItemLayout={getItemLayout} + // onRefresh={onRefresh} + // refreshing={refreshing} + onEndReachedThreshold={0.5} + onEndReached={handleLoadMore} + progressViewOffset={progressViewOffset} + ListHeaderComponent={ListHeaderComponent} + refreshControl={refreshControl} + ListFooterComponent={footerComponent} + /> + ) +}) + +type FooterLabel = 'list_loading' | 'list_end' | 'list_error' | null +const Footer = ({ label, onLoadMore }: { + label: FooterLabel + onLoadMore: () => void +}) => { + const theme = useTheme() + const t = useI18n() + const handlePress = () => { + if (label != 'list_error') return + onLoadMore() + } + return ( + label + ? ( + <View> + <Text onPress={handlePress} style={styles.footer} color={theme['c-font-label']}>{t(label)}</Text> + </View> + ) + : null + ) +} + +const styles = createStyle({ + container: { + flex: 1, + }, + list: { + flexGrow: 1, + flexShrink: 1, + }, + footer: { + textAlign: 'center', + padding: 10, + }, +}) + +export default List diff --git a/src/components/OnlineList/ListItem.js b/src/components/OnlineList/ListItem.js deleted file mode 100644 index beab3c48b..000000000 --- a/src/components/OnlineList/ListItem.js +++ /dev/null @@ -1,133 +0,0 @@ -import React, { useCallback, memo, useRef, useMemo } from 'react' -import { StyleSheet, View, Text, TouchableOpacity } from 'react-native' -import { useGetter } from '@/store' -// import Button from '@/components/common/Button' -import Badge from '@/components/common/Badge' -import { BorderWidths } from '@/theme' -import { useTranslation } from '@/plugins/i18n' -import { Icon } from '@/components/common/Icon' - -const useQualityTag = musicInfo => { - const { t } = useTranslation() - let info = {} - if (musicInfo._types.flac32bit) { - info.type = 'secondary' - info.text = t('quality_lossless_24bit') - } else if (musicInfo._types.ape || musicInfo._types.flac) { - info.type = 'secondary' - info.text = t('quality_lossless') - } else if (musicInfo._types['320k']) { - info.type = 'tertiary' - info.text = t('quality_high_quality') - } else info = null - - return info -} - -export default memo(({ item, index, onPress, showMenu, handleLongPress, selectedList }) => { - const theme = useGetter('common', 'theme') - - const isSelected = selectedList.indexOf(item) != -1 - - const moreButtonRef = useRef() - const handleShowMenu = useCallback(() => { - if (moreButtonRef.current && moreButtonRef.current.measure) { - moreButtonRef.current.measure((fx, fy, width, height, px, py) => { - // console.log(fx, fy, width, height, px, py) - showMenu(item, index, { x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }) - }) - } - }, [item, index, showMenu]) - const tagInfo = useQualityTag(item) - - return ( - <View style={{ ...styles.listItem, backgroundColor: isSelected ? theme.secondary45 : theme.primary, borderBottomColor: theme.secondary45 }}> - <TouchableOpacity style={styles.listItemLeft} onPress={ () => { onPress(item, index) }} onLongPress={() => { handleLongPress(item, index) }}> - <Text style={{ ...styles.sn, color: theme.normal50 }}>{index + 1}</Text> - <View style={styles.itemInfo}> - <View style={styles.listItemTitle}> - <Text style={{ ...styles.listItemTitleText, color: theme.normal }}>{item.name}</Text> - { tagInfo ? <Badge type={tagInfo.type}>{tagInfo.text}</Badge> : null } - </View> - <View style={styles.row2}><Text style={{ ...styles.listItemSingle, color: theme.normal40 }}>{item.singer}</Text></View> - </View> - </TouchableOpacity> - <View style={styles.listItemRight}> - <TouchableOpacity onPress={handleShowMenu} ref={moreButtonRef} style={styles.moreButton}> - <Icon name="dots-vertical" style={{ color: theme.normal35 }} size={16} /> - </TouchableOpacity> - </View> - </View> - ) -}, (prevProps, nextProps) => { - return !!(prevProps.item === nextProps.item && - prevProps.index === nextProps.index && - nextProps.selectedList.includes(nextProps.item) == prevProps.selectedList.includes(nextProps.item) - ) -}) - -const styles = StyleSheet.create({ - listItem: { - width: '100%', - flexDirection: 'row', - flexWrap: 'nowrap', - borderBottomWidth: BorderWidths.normal, - // paddingLeft: 10, - paddingRight: 10, - }, - listItemLeft: { - flex: 1, - flexGrow: 1, - flexShrink: 1, - flexDirection: 'row', - alignItems: 'center', - // backgroundColor: 'rgba(0,0,0,0.1)', - }, - sn: { - width: 32, - fontSize: 11, - textAlign: 'center', - // backgroundColor: 'rgba(0,0,0,0.2)', - paddingLeft: 3, - paddingRight: 3, - }, - itemInfo: { - flexGrow: 0, - flexShrink: 1, - paddingTop: 10, - paddingBottom: 10, - }, - listItemTitle: { - flexDirection: 'row', - alignItems: 'flex-end', - }, - listItemTitleText: { - // backgroundColor: 'rgba(0,0,0,0.2)', - flexGrow: 0, - flexShrink: 1, - fontSize: 14, - }, - listItemSingle: { - fontSize: 12, - paddingTop: 2, - }, - listItemBadge: { - fontSize: 10, - paddingLeft: 5, - paddingBottom: 2, - }, - listItemRight: { - flexGrow: 0, - flexShrink: 0, - flexBasis: 'auto', - justifyContent: 'center', - // backgroundColor: 'rgba(0,0,0,0.2)', - }, - moreButton: { - paddingLeft: 10, - paddingRight: 10, - paddingTop: 10, - paddingBottom: 10, - }, -}) - diff --git a/src/components/OnlineList/ListItem.tsx b/src/components/OnlineList/ListItem.tsx new file mode 100644 index 000000000..836fdc07c --- /dev/null +++ b/src/components/OnlineList/ListItem.tsx @@ -0,0 +1,151 @@ +import React, { memo, useRef } from 'react' +import { StyleSheet, View, TouchableOpacity } from 'react-native' +// import Button from '@/components/common/Button' +import Text from '@/components/common/Text' +import Badge, { type BadgeType } from '@/components/common/Badge' +import { Icon } from '@/components/common/Icon' +import { useI18n } from '@/lang' +import { useTheme } from '@/store/theme/hook' +import { scaleSizeH } from '@/utils/pixelRatio' +import { LIST_ITEM_HEIGHT } from '@/config/constant' + +export const ITEM_HEIGHT = scaleSizeH(LIST_ITEM_HEIGHT) + +const useQualityTag = (musicInfo: LX.Music.MusicInfoOnline) => { + const t = useI18n() + let info: { type: BadgeType | null, text: string } = { type: null, text: '' } + if (musicInfo.meta._qualitys.flac24bit) { + info.type = 'secondary' + info.text = t('quality_lossless_24bit') + } else if (musicInfo.meta._qualitys.flac ?? musicInfo.meta._qualitys.ape) { + info.type = 'secondary' + info.text = t('quality_lossless') + } else if (musicInfo.meta._qualitys['320k']) { + info.type = 'tertiary' + info.text = t('quality_high_quality') + } + + return info +} + +export default memo(({ item, index, showSource, onPress, onLongPress, onShowMenu, selectedList }: { + item: LX.Music.MusicInfoOnline + index: number + showSource?: boolean + onPress: (item: LX.Music.MusicInfoOnline, index: number) => void + onLongPress: (item: LX.Music.MusicInfoOnline, index: number) => void + onShowMenu: (item: LX.Music.MusicInfoOnline, index: number, position: { x: number, y: number, w: number, h: number }) => void + selectedList: LX.Music.MusicInfoOnline[] +}) => { + const theme = useTheme() + + const isSelected = selectedList.includes(item) + + const moreButtonRef = useRef<TouchableOpacity>(null) + const handleShowMenu = () => { + if (moreButtonRef.current?.measure) { + moreButtonRef.current.measure((fx, fy, width, height, px, py) => { + // console.log(fx, fy, width, height, px, py) + onShowMenu(item, index, { x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }) + }) + } + } + const tagInfo = useQualityTag(item) + + return ( + <View style={{ ...styles.listItem, height: ITEM_HEIGHT, backgroundColor: isSelected ? theme['c-primary-background-hover'] : 'rgba(0,0,0,0)' }}> + <TouchableOpacity style={styles.listItemLeft} onPress={() => { onPress(item, index) }} onLongPress={() => { onLongPress(item, index) }}> + <Text style={styles.sn} size={14} color={theme['c-300']}>{index + 1}</Text> + <View style={styles.itemInfo}> + <Text numberOfLines={1}>{item.name}</Text> + <View style={styles.listItemSingle}> + <Text style={styles.listItemSingleText} size={13} color={theme['c-500']} numberOfLines={1}>{item.singer}</Text> + { tagInfo.type ? <Badge type={tagInfo.type}>{tagInfo.text}</Badge> : null } + { showSource ? <Badge type="tertiary">{item.source}</Badge> : null } + </View> + </View> + </TouchableOpacity> + <TouchableOpacity onPress={handleShowMenu} ref={moreButtonRef} style={styles.moreButton}> + <Icon name="dots-vertical" style={{ color: theme['c-350'] }} size={12} /> + </TouchableOpacity> + </View> + ) +}, (prevProps, nextProps) => { + return !!(prevProps.item === nextProps.item && + prevProps.index === nextProps.index && + nextProps.selectedList.includes(nextProps.item) == prevProps.selectedList.includes(nextProps.item) + ) +}) + +const styles = StyleSheet.create({ + listItem: { + width: '100%', + flexDirection: 'row', + flexWrap: 'nowrap', + // paddingLeft: 10, + paddingRight: 2, + alignItems: 'center', + // borderBottomWidth: BorderWidths.normal, + }, + listItemLeft: { + flex: 1, + flexGrow: 1, + flexShrink: 1, + flexDirection: 'row', + alignItems: 'center', + }, + sn: { + width: 38, + // fontSize: 12, + textAlign: 'center', + // backgroundColor: 'rgba(0,0,0,0.2)', + paddingLeft: 3, + paddingRight: 3, + }, + itemInfo: { + flexGrow: 0, + flexShrink: 1, + // paddingTop: 10, + // paddingBottom: 10, + }, + // listItemTitle: { + // // backgroundColor: 'rgba(0,0,0,0.2)', + // flexGrow: 0, + // flexShrink: 1, + // // fontSize: 15, + // }, + listItemSingle: { + paddingTop: 2, + flexDirection: 'row', + // alignItems: 'flex-end', + // backgroundColor: 'rgba(0,0,0,0.2)', + }, + listItemSingleText: { + // fontSize: 13, + // paddingTop: 2, + flexGrow: 0, + flexShrink: 1, + }, + listItemBadge: { + // fontSize: 10, + paddingLeft: 5, + paddingTop: 2, + alignSelf: 'flex-start', + }, + listItemRight: { + flexGrow: 0, + flexShrink: 0, + flexBasis: 'auto', + justifyContent: 'center', + }, + moreButton: { + height: '80%', + paddingLeft: 16, + paddingRight: 16, + // paddingTop: 10, + // paddingBottom: 10, + // backgroundColor: 'rgba(0,0,0,0.2)', + justifyContent: 'center', + }, +}) + diff --git a/src/components/OnlineList/ListMenu.tsx b/src/components/OnlineList/ListMenu.tsx new file mode 100644 index 000000000..51ce55825 --- /dev/null +++ b/src/components/OnlineList/ListMenu.tsx @@ -0,0 +1,81 @@ +import React, { useMemo, useRef, useImperativeHandle, forwardRef, useState } from 'react' +import { useI18n } from '@/lang' +import Menu, { type MenuType, type Position } from '@/components/common/Menu' + +export interface SelectInfo { + musicInfo: LX.Music.MusicInfoOnline + selectedList: LX.Music.MusicInfoOnline[] + index: number + single: boolean +} +const initSelectInfo = {} + +export interface ListMenuProps { + onPlay: (selectInfo: SelectInfo) => void + onPlayLater: (selectInfo: SelectInfo) => void + onAdd: (selectInfo: SelectInfo) => void + onCopyName: (selectInfo: SelectInfo) => void +} +export interface ListMenuType { + show: (selectInfo: SelectInfo, position: Position) => void +} + +export type { + Position, +} + +export default forwardRef<ListMenuType, ListMenuProps>((props: ListMenuProps, ref) => { + const t = useI18n() + const [visible, setVisible] = useState(false) + const menuRef = useRef<MenuType>(null) + const selectInfoRef = useRef<SelectInfo>(initSelectInfo as SelectInfo) + + useImperativeHandle(ref, () => ({ + show(selectInfo, position) { + selectInfoRef.current = selectInfo + if (visible) menuRef.current?.show(position) + else { + setVisible(true) + requestAnimationFrame(() => { + menuRef.current?.show(position) + }) + } + }, + })) + + const menus = useMemo(() => { + return [ + { action: 'play', label: t('play') }, + { action: 'playLater', label: t('play_later') }, + // { action: 'download', label: '下载' }, + { action: 'add', label: t('add_to') }, + { action: 'copyName', label: t('copy_name') }, + ] as const + }, [t]) + + const handleMenuPress = ({ action }: typeof menus[number]) => { + const selectInfo = selectInfoRef.current + switch (action) { + case 'play': + props.onPlay(selectInfo) + break + case 'playLater': + props.onPlayLater(selectInfo) + break + case 'add': + props.onAdd(selectInfo) + break + case 'copyName': + props.onCopyName(selectInfo) + break + default: + break + } + } + + return ( + visible + ? <Menu ref={menuRef} menus={menus} onPress={handleMenuPress} /> + : null + ) +}) diff --git a/src/components/OnlineList/MultipleModeBar.tsx b/src/components/OnlineList/MultipleModeBar.tsx new file mode 100644 index 000000000..7cc72c78f --- /dev/null +++ b/src/components/OnlineList/MultipleModeBar.tsx @@ -0,0 +1,158 @@ +import React, { useState, useRef, useCallback, useMemo, forwardRef, useImperativeHandle } from 'react' +import { Animated, View, TouchableOpacity } from 'react-native' + +import Text from '@/components/common/Text' +import Button from '@/components/common/Button' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import { BorderWidths } from '@/theme' +import { scaleSizeH } from '@/utils/pixelRatio' + +export type SelectMode = 'single' | 'range' + +export const MULTI_SELECT_BAR_HEIGHT = scaleSizeH(40) + +export interface MultipleModeBarProps { + onSwitchMode: (mode: SelectMode) => void + onSelectAll: (isAll: boolean) => void + onExitSelectMode: () => void +} +export interface MultipleModeBarType { + show: () => void + setIsSelectAll: (isAll: boolean) => void + setSwitchMode: (mode: SelectMode) => void + exitSelectMode: () => void +} + +export default forwardRef<MultipleModeBarType, MultipleModeBarProps>(({ onSelectAll, onSwitchMode, onExitSelectMode }, ref) => { + // const isGetDetailFailedRef = useRef(false) + const [visible, setVisible] = useState(false) + const [animatePlayed, setAnimatPlayed] = useState(true) + const animFade = useRef(new Animated.Value(0)).current + const animTranslateY = useRef(new Animated.Value(0)).current + const [selectMode, setSelectMode] = useState<SelectMode>('single') + const [isSelectAll, setIsSelectAll] = useState(false) + const theme = useTheme() + + useImperativeHandle(ref, () => ({ + show() { + handleShow() + }, + setIsSelectAll(isAll) { + setIsSelectAll(isAll) + }, + setSwitchMode(mode: SelectMode) { + setSelectMode(mode) + }, + exitSelectMode() { + handleHide() + }, + })) + + const handleShow = useCallback(() => { + // console.log('show List') + setVisible(true) + setAnimatPlayed(false) + animTranslateY.setValue(20) + + Animated.parallel([ + Animated.timing(animFade, { + toValue: 0.92, + duration: 200, + useNativeDriver: true, + }), + Animated.timing(animTranslateY, { + toValue: 0, + duration: 200, + useNativeDriver: true, + }), + ]).start(() => { + setAnimatPlayed(true) + }) + }, [animFade, animTranslateY]) + + const handleHide = useCallback(() => { + setAnimatPlayed(false) + Animated.parallel([ + Animated.timing(animFade, { + toValue: 0, + duration: 200, + useNativeDriver: true, + }), + Animated.timing(animTranslateY, { + toValue: 20, + duration: 200, + useNativeDriver: true, + }), + ]).start(finished => { + if (!finished) return + setVisible(false) + setAnimatPlayed(true) + }) + }, [animFade, animTranslateY]) + + + const animaStyle = useMemo(() => ({ + ...styles.container, + height: MULTI_SELECT_BAR_HEIGHT, + // backgroundColor: theme['c-content-background'], + borderBottomColor: theme['c-border-background'], + opacity: animFade, // Bind opacity to animated value + transform: [ + { translateY: animTranslateY }, + ], + }), [animFade, animTranslateY, theme]) + + const handleSelectAll = useCallback(() => { + const selectAll = !isSelectAll + setIsSelectAll(selectAll) + onSelectAll(selectAll) + }, [isSelectAll, onSelectAll]) + + const component = useMemo(() => { + return ( + <Animated.View style={animaStyle}> + <View style={styles.switchBtn}> + <Button onPress={() => onSwitchMode('single')} style={{ ...styles.btn, backgroundColor: selectMode == 'single' ? theme['c-button-background'] : 'rgba(0,0,0,0)' }}> + <Text color={theme['c-button-font']}>{global.i18n.t('list_select_single')}</Text> + </Button> + <Button onPress={() => onSwitchMode('range')} style={{ ...styles.btn, backgroundColor: selectMode == 'range' ? theme['c-button-background'] : 'rgba(0,0,0,0)' }}> + <Text color={theme['c-button-font']}>{global.i18n.t('list_select_range')}</Text> + </Button> + </View> + <TouchableOpacity onPress={handleSelectAll} style={styles.btn}> + <Text color={theme['c-button-font']}>{global.i18n.t(isSelectAll ? 'list_select_unall' : 'list_select_all')}</Text> + </TouchableOpacity> + <TouchableOpacity onPress={onExitSelectMode} style={styles.btn}> + <Text color={theme['c-button-font']}>{global.i18n.t('list_select_cancel')}</Text> + </TouchableOpacity> + </Animated.View> + ) + }, [animaStyle, selectMode, theme, handleSelectAll, isSelectAll, onExitSelectMode, onSwitchMode]) + + return !visible && animatePlayed ? null : component +}) + +const styles = createStyle({ + container: { + flex: 1, + position: 'absolute', + left: 0, + bottom: 0, + width: '100%', + // height: 40, + flexDirection: 'row', + borderBottomWidth: BorderWidths.normal, + }, + switchBtn: { + flexDirection: 'row', + flex: 1, + }, + btn: { + // flex: 1, + paddingLeft: 18, + paddingRight: 18, + alignItems: 'center', + justifyContent: 'center', + }, +}) diff --git a/src/components/OnlineList/index.js b/src/components/OnlineList/index.js deleted file mode 100644 index 6a1afc905..000000000 --- a/src/components/OnlineList/index.js +++ /dev/null @@ -1,308 +0,0 @@ -import React, { useState, useCallback, memo, useMemo, useRef, useEffect } from 'react' -import { StyleSheet, FlatList, View, RefreshControl } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import Menu from '@/components/common/Menu' -import MusicAddModal from '@/components/MusicAddModal' -import MusicMultiAddModal from '@/components/MusicMultiAddModal' -import ListItem from './ListItem' -import ExitMultipleModeBar from './ExitMultipleModeBar' -import LoadingMask from '@/components/common/LoadingMask' -import { useTranslation } from '@/plugins/i18n' -import { Loading as FooterLoading, End as FooterEnd } from './Footer' -import { LIST_ID_PLAY_LATER } from '@/config/constant' -import { shareMusic } from '@/utils/tools' - -export default memo(({ - list, - isEnd, - page, - isListRefreshing, - // visibleLoadingMask, - onRefresh, - onLoadMore, - onPlayList, - isLoading, - progressViewOffset, - ListHeaderComponent, -}) => { - const defaultList = useGetter('list', 'defaultList') - const defaultListRef = useRef(defaultList) - const addMusicToList = useDispatch('list', 'listAdd') - const setPlayList = useDispatch('player', 'setList') - const setTempPlayList = useDispatch('player', 'setTempPlayList') - const isClickPlayList = useGetter('common', 'isClickPlayList') - const downloadFileName = useGetter('common', 'downloadFileName') - const shareType = useGetter('common', 'shareType') - const [buttonPosition, setButtonPosition] = useState({ w: 0, h: 0, x: 0, y: 0 }) - const selectedData = useRef({ data: null, index: -1 }) - const [visibleMenu, setVisibleMenu] = useState(false) - const [visibleLoadingMask, setVisibleLoadingMask] = useState(false) - const flatListRef = useRef() - const { t } = useTranslation() - const [visibleMusicAddModal, setVisibleMusicAddModal] = useState(false) - const [isMultiSelectMode, setIsMultiSelectMode] = useState(false) - const isMultiSelectModeRef = useRef(isMultiSelectMode) - const [selectedList, setSelectedList] = useState([]) - const selectedListRef = useRef([]) - const [visibleMusicMultiAddModal, setVisibleMusicMultiAddModal] = useState(false) - const listRef = useRef([]) - const [selectMode, setSelectMode] = useState('single') - const selectModeRef = useRef('single') - const prevSelectIndexRef = useRef(-1) - const addMultiMusicToList = useDispatch('list', 'listAddMultiple') - const theme = useGetter('common', 'theme') - - useEffect(() => { - defaultListRef.current = defaultList - }, [defaultList]) - useEffect(() => { - listRef.current = list - }, [list]) - - const handlePlay = useCallback((targetSong, index) => { - addMusicToList({ - musicInfo: targetSong, - id: defaultListRef.current.id, - }) - - const targetIndex = defaultListRef.current.list.findIndex(s => s.songmid === targetSong.songmid) - if (targetIndex > -1) { - setPlayList({ - list: defaultListRef.current, - index: targetIndex, - }) - } - }, [addMusicToList, setPlayList]) - - const handleSelect = useCallback((item, index) => { - if (selectModeRef.current == 'single') { - const index = selectedListRef.current.indexOf(item) - if (index < 0) { - selectedListRef.current.push(item) - // setSelectedItem({ item, isChecked: true }) - } else { - selectedListRef.current.splice(index, 1) - // setSelectedItem({ item, isChecked: false }) - } - } else { - if (selectedListRef.current.length) { - const prevIndex = prevSelectIndexRef.current - const currentIndex = index - if (prevIndex == currentIndex) { - selectedListRef.current = [] - } else if (currentIndex > prevIndex) { - selectedListRef.current = listRef.current.slice(prevIndex, currentIndex + 1) - } else { - selectedListRef.current = listRef.current.slice(currentIndex, prevIndex + 1) - selectedListRef.current.reverse() - } - } else { - selectedListRef.current.push(item) - prevSelectIndexRef.current = index - } - } - setSelectedList([...selectedListRef.current]) - }, []) - const handleSelectAll = useCallback(() => { - if (!listRef.current.length) return - if (selectedListRef.current.length == listRef.current.length) { - selectedListRef.current = [] - } else { - selectedListRef.current = [...listRef.current] - } - setSelectedList([...selectedListRef.current]) - }, []) - - const handleSetSelectMode = useCallback(mode => { - setSelectMode(mode) - selectModeRef.current = mode - if (mode == 'range' && selectedListRef.current.length) { - prevSelectIndexRef.current = listRef.current.indexOf(selectedListRef.current[selectedListRef.current.length - 1]) - } - }, []) - - const handleCancelMultiSelect = useCallback(() => { - setIsMultiSelectMode(false) - isMultiSelectModeRef.current = false - selectedListRef.current = [] - setSelectedList([]) - }, []) - const handlePress = useCallback((item, index) => { - if (isMultiSelectModeRef.current) { - handleSelect(item, index) - } else { - if (isClickPlayList && typeof onPlayList == 'function') { - onPlayList(index, item) - } else { - handlePlay(item, index) - } - } - }, [handlePlay, handleSelect, isClickPlayList, onPlayList]) - - const handleLongPress = useCallback((item, index) => { - setIsMultiSelectMode(true) - isMultiSelectModeRef.current = true - handleSelect(item, index) - }, [handleSelect]) - - const menus = useMemo(() => { - return [ - { action: 'play', label: t('play') }, - { action: 'playLater', label: t('play_later') }, - { action: 'copyName', label: t('copy_name') }, - // { action: 'download', label: '下载' }, - // { action: 'add', label: '添加到...' }, - // { action: 'move', label: '移动到...' }, - { action: 'add', label: t('add_to') }, - ] - }, [t]) - const showMenu = useCallback((item, index, position) => { - setButtonPosition({ ...position }) - selectedData.current.data = item - selectedData.current.index = index - setVisibleMenu(true) - }, [setButtonPosition]) - const hideMenu = useCallback(() => { - setVisibleMenu(false) - }, [setVisibleMenu]) - const handleMenuPress = useCallback(({ action }) => { - switch (action) { - case 'play': - if (selectedListRef.current.length) { - addMultiMusicToList({ id: 'default', list: [...selectedListRef.current] }) - handleCancelMultiSelect() - } - handlePlay(selectedData.current.data, selectedData.current.index) - break - case 'playLater': - if (selectedListRef.current.length) { - setTempPlayList(selectedListRef.current.map(s => ({ listId: LIST_ID_PLAY_LATER, musicInfo: s }))) - handleCancelMultiSelect() - } else { - setTempPlayList([{ listId: LIST_ID_PLAY_LATER, musicInfo: selectedData.current.data }]) - } - break - case 'copyName': - shareMusic(shareType, downloadFileName, selectedData.current.data) - break - case 'add': - // console.log(selectedListRef.current.length) - selectedListRef.current.length - ? setVisibleMusicMultiAddModal(true) - : setVisibleMusicAddModal(true) - break - default: - break - } - }, [addMultiMusicToList, downloadFileName, handleCancelMultiSelect, handlePlay, setTempPlayList, shareType]) - - useEffect(() => { - if (isLoading && page == 1) { - setVisibleLoadingMask(true) - } else { - setVisibleLoadingMask(false) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isLoading]) - - useEffect(() => { - if (!flatListRef.current) return - if (page == 1) flatListRef.current.scrollToOffset({ offset: 0, animated: true }) - }, [list, page]) - - const hideMusicAddModal = useCallback(() => { - setVisibleMusicAddModal(false) - }, []) - - const hideMusicMultiAddModal = useCallback(() => { - setVisibleMusicMultiAddModal(false) - }, []) - - const loadingMaskmomponent = useMemo(() => ( - <LoadingMask visible={visibleLoadingMask} /> - ), [visibleLoadingMask]) - const exitMultipleModeBtn = useMemo(() => ( - <ExitMultipleModeBar - multipleMode={isMultiSelectMode} - onCancel={handleCancelMultiSelect} - onSwitchMode={handleSetSelectMode} - onSelectAll={handleSelectAll} - selectMode={selectMode} - isSelectAll={selectedList.length && list.length == selectedList.length} /> - ), [handleCancelMultiSelect, handleSelectAll, handleSetSelectMode, isMultiSelectMode, list, selectMode, selectedList]) - - const renderItem = useCallback(({ item, index }) => ( - <ListItem - item={item} - index={index} - onPress={handlePress} - showMenu={showMenu} - selectedList={selectedList} - handleLongPress={handleLongPress} /> - ), [handleLongPress, handlePress, selectedList, showMenu]) - - const refreshControl = useMemo(() => ( - <RefreshControl - colors={[theme.secondary]} - progressBackgroundColor={theme.primary} - refreshing={isListRefreshing} - onRefresh={onRefresh} /> - ), [isListRefreshing, onRefresh, theme]) - - return ( - <View style={styles.container}> - <FlatList - ref={flatListRef} - style={styles.list} - keyboardShouldPersistTaps={'always'} - data={list} - renderItem={renderItem} - keyExtractor={item => item.songmid.toString()} - onRefresh={onRefresh} - refreshing={isListRefreshing} - maxToRenderPerBatch={8} - updateCellsBatchingPeriod={80} - windowSize={18} - removeClippedSubviews={true} - initialNumToRender={15} - onEndReached={onLoadMore} - progressViewOffset={progressViewOffset} - ListHeaderComponent={ListHeaderComponent} - refreshControl={refreshControl} - ListFooterComponent={<View style={{ paddingBottom: isMultiSelectMode ? 40 : 0 }}>{isLoading ? <FooterLoading /> : isEnd ? <FooterEnd /> : null}</View>} - /> - { exitMultipleModeBtn } - <Menu - menus={menus} - buttonPosition={buttonPosition} - onPress={handleMenuPress} - visible={visibleMenu} - hideMenu={hideMenu} /> - <MusicAddModal - visible={visibleMusicAddModal} - hideModal={hideMusicAddModal} - musicInfo={selectedData.current.data} /> - <MusicMultiAddModal - visible={visibleMusicMultiAddModal} - hideModal={hideMusicMultiAddModal} - list={selectedListRef.current} - onAdd={handleCancelMultiSelect} /> - { loadingMaskmomponent } - </View> - ) -}) - - -const styles = StyleSheet.create({ - container: { - flex: 1, - overflow: 'hidden', - }, - list: { - flex: 1, - }, - exitMultipleModeBtn: { - height: 40, - }, -}) - diff --git a/src/components/OnlineList/index.tsx b/src/components/OnlineList/index.tsx new file mode 100644 index 000000000..8f9df7071 --- /dev/null +++ b/src/components/OnlineList/index.tsx @@ -0,0 +1,124 @@ +import React, { useRef, forwardRef, useImperativeHandle } from 'react' +import { View } from 'react-native' +// import LoadingMask, { LoadingMaskType } from '@/components/common/LoadingMask' +import List, { type ListProps, type ListType, type Status } from './List' +import ListMenu, { type ListMenuType, type Position, type SelectInfo } from './ListMenu' +import ListMusicMultiAdd, { type MusicMultiAddModalType as ListAddMultiType } from '@/components/MusicMultiAddModal' +import ListMusicAdd, { type MusicAddModalType as ListMusicAddType } from '@/components/MusicAddModal' +import MultipleModeBar, { type MultipleModeBarType, type SelectMode } from './MultipleModeBar' +import { handlePlay, handlePlayLater, handleShare } from './listAction' +import { createStyle } from '@/utils/tools' + +export interface OnlineListProps { + onRefresh: ListProps['onRefresh'] + onLoadMore: ListProps['onLoadMore'] + onPlayList?: ListProps['onPlayList'] + progressViewOffset?: ListProps['progressViewOffset'] + ListHeaderComponent?: ListProps['ListHeaderComponent'] +} +export interface OnlineListType { + setList: (list: LX.Music.MusicInfoOnline[], showSource?: boolean) => void + setStatus: (val: Status) => void +} + +export default forwardRef<OnlineListType, OnlineListProps>(({ + onRefresh, + onLoadMore, + onPlayList, + progressViewOffset, + ListHeaderComponent, +}, ref) => { + const listRef = useRef<ListType>(null) + const multipleModeBarRef = useRef<MultipleModeBarType>(null) + const listMusicAddRef = useRef<ListMusicAddType>(null) + const listMusicMultiAddRef = useRef<ListAddMultiType>(null) + const listMenuRef = useRef<ListMenuType>(null) + // const loadingMaskRef = useRef<LoadingMaskType>(null) + + useImperativeHandle(ref, () => ({ + setList(list, showSource) { + listRef.current?.setList(list, showSource) + }, + setStatus(val) { + listRef.current?.setStatus(val) + }, + })) + + const hancelMultiSelect = () => { + multipleModeBarRef.current?.show() + listRef.current?.setIsMultiSelectMode(true) + } + const hancelSwitchSelectMode = (mode: SelectMode) => { + multipleModeBarRef.current?.setSwitchMode(mode) + listRef.current?.setSelectMode(mode) + } + const hancelExitSelect = () => { + multipleModeBarRef.current?.exitSelectMode() + listRef.current?.setIsMultiSelectMode(false) + } + + const showMenu = (musicInfo: LX.Music.MusicInfoOnline, index: number, position: Position) => { + listMenuRef.current?.show({ + musicInfo, + index, + single: false, + selectedList: listRef.current!.getSelectedList(), + }, position) + } + const handleAddMusic = (info: SelectInfo) => { + if (info.selectedList.length) { + listMusicMultiAddRef.current?.show({ selectedList: info.selectedList, listId: '', isMove: false }) + } else { + listMusicAddRef.current?.show({ musicInfo: info.musicInfo, listId: '', isMove: false }) + } + } + + return ( + <View style={styles.container}> + <View style={{ flex: 1 }}> + <List + ref={listRef} + onShowMenu={showMenu} + onMuiltSelectMode={hancelMultiSelect} + onSelectAll={isAll => multipleModeBarRef.current?.setIsSelectAll(isAll)} + onRefresh={onRefresh} + onLoadMore={onLoadMore} + onPlayList={onPlayList} + progressViewOffset={progressViewOffset} + ListHeaderComponent={ListHeaderComponent} + /> + <MultipleModeBar + ref={multipleModeBarRef} + onSwitchMode={hancelSwitchSelectMode} + onSelectAll={isAll => listRef.current?.selectAll(isAll)} + onExitSelectMode={hancelExitSelect} + /> + </View> + <ListMusicAdd ref={listMusicAddRef} /> + <ListMusicMultiAdd ref={listMusicMultiAddRef} /> + <ListMenu + ref={listMenuRef} + onPlay={info => { handlePlay(info.musicInfo) }} + onPlayLater={info => { handlePlayLater(info.musicInfo, info.selectedList, hancelExitSelect) }} + onCopyName={info => { handleShare(info.musicInfo) }} + onAdd={handleAddMusic} + /> + {/* <LoadingMask ref={loadingMaskRef} /> */} + </View> + ) +}) + + +const styles = createStyle({ + container: { + flex: 1, + overflow: 'hidden', + }, + list: { + flex: 1, + }, + exitMultipleModeBtn: { + height: 40, + }, +}) + diff --git a/src/components/OnlineList/listAction.ts b/src/components/OnlineList/listAction.ts new file mode 100644 index 000000000..8fbedd6ee --- /dev/null +++ b/src/components/OnlineList/listAction.ts @@ -0,0 +1,29 @@ +import { LIST_IDS } from '@/config/constant' +import { addListMusics } from '@/core/list' +import { playList } from '@/core/player/player' +import { addTempPlayList } from '@/core/player/tempPlayList' +import settingState from '@/store/setting/state' +import { getListMusicSync } from '@/utils/listManage' +import { shareMusic } from '@/utils/tools' + +export const handlePlay = (musicInfo: LX.Music.MusicInfoOnline) => { + void addListMusics(LIST_IDS.DEFAULT, [musicInfo], settingState.setting['list.addMusicLocationType']).then(() => { + const index = getListMusicSync(LIST_IDS.DEFAULT).findIndex(m => m.id == musicInfo.id) + if (index < 0) return + void playList(LIST_IDS.DEFAULT, index) + }) +} +export const handlePlayLater = (musicInfo: LX.Music.MusicInfoOnline, selectedList: LX.Music.MusicInfoOnline[], onCancelSelect: () => void) => { + if (selectedList.length) { + addTempPlayList(selectedList.map(s => ({ listId: '', musicInfo: s }))) + onCancelSelect() + } else { + addTempPlayList([{ listId: '', musicInfo }]) + } +} + + +export const handleShare = (musicInfo: LX.Music.MusicInfoOnline) => { + shareMusic(settingState.setting['common.shareType'], settingState.setting['download.fileName'], musicInfo) +} + diff --git a/src/components/PageContent.tsx b/src/components/PageContent.tsx new file mode 100644 index 000000000..4c563832e --- /dev/null +++ b/src/components/PageContent.tsx @@ -0,0 +1,41 @@ +import React, { useEffect, useState } from 'react' +import { Dimensions, ImageBackground, type LayoutChangeEvent, View } from 'react-native' +import { useTheme } from '@/store/theme/hook' +// import { useDimensions } from '@/utils/hooks' + +interface Props { + children: React.ReactNode +} + + +export default ({ children }: Props) => { + const theme = useTheme() + // const { window } = useDimensions() + const [wh, setWH] = useState<{ width: number | string, height: number | string }>({ width: '100%', height: '100%' }) + + // 固定宽高度 防止弹窗键盘时大小改变导致背景被缩放 + useEffect(() => { + const onChange = () => { + setWH({ width: '100%', height: '100%' }) + } + + const changeEvent = Dimensions.addEventListener('change', onChange) + return () => { changeEvent.remove() } + }, []) + const handleLayout = (e: LayoutChangeEvent) => { + setWH({ width: e.nativeEvent.layout.width, height: e.nativeEvent.layout.height }) + } + + return ( + <ImageBackground + onLayout={handleLayout} + style={{ height: wh.height, width: wh.width, backgroundColor: theme['c-content-background'] }} + source={theme['bg-image']} + resizeMode="cover" + > + <View style={{ flex: 1, flexDirection: 'column', backgroundColor: theme['c-main-background'] }}> + {children} + </View> + </ImageBackground> + ) +} diff --git a/src/components/SearchInput.js b/src/components/SearchInput.js deleted file mode 100644 index 654e7c9f1..000000000 --- a/src/components/SearchInput.js +++ /dev/null @@ -1,35 +0,0 @@ -import React, { useRef, forwardRef, useImperativeHandle } from 'react' -import { View, StyleSheet } from 'react-native' -import Input from './common/Input' - -const SearchInput = (props, ref) => { - const textInputRef = useRef() - - useImperativeHandle(ref, () => ({ - blur() { - if (!textInputRef.current) return - textInputRef.current.blur() - }, - })) - - return ( - <View style={{ ...styles.container, ...props.styles }}> - <Input {...props} ref={textInputRef} /> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - // backgroundColor: AppColors.secondary40, - paddingTop: 5, - paddingBottom: 5, - paddingLeft: 10, - paddingRight: 10, - width: '100%', - // borderBottomLeftRadius: 10, - // borderBottomRightRadius: 10, - }, -}) - -export default forwardRef(SearchInput) diff --git a/src/components/SearchTipList/List.tsx b/src/components/SearchTipList/List.tsx new file mode 100644 index 000000000..eb29955c8 --- /dev/null +++ b/src/components/SearchTipList/List.tsx @@ -0,0 +1,36 @@ +import React, { useState, forwardRef, useImperativeHandle, Ref } from 'react' +import { FlatList, FlatListProps } from 'react-native' + +// import InsetShadow from 'react-native-inset-shadow' + +export type ItemT<T> = FlatListProps<T>['data'] + +export type ListProps<T> = Pick<FlatListProps<T>, +| 'renderItem' +| 'maxToRenderPerBatch' +| 'windowSize' +| 'initialNumToRender' +| 'keyExtractor' +| 'getItemLayout' +| 'keyboardShouldPersistTaps' +> + +export interface ListType<T> { + setList: (list: T[]) => void +} + +const List = <T extends ItemT<T>>(props: ListProps<T>, ref: Ref<ListType<T>>) => { + const [list, setList] = useState<T[]>([]) + useImperativeHandle(ref, () => ({ + setList(list) { + setList(list) + }, + })) + + return <FlatList removeClippedSubviews={true} keyboardShouldPersistTaps={'always'} {...props} data={list} /> +} + +export default forwardRef(List) as + <M,>(p: ListProps<M> & { ref?: Ref<ListType<M>> }) => JSX.Element | null + + diff --git a/src/components/SearchTipList/index.tsx b/src/components/SearchTipList/index.tsx new file mode 100644 index 000000000..91c7a0a9f --- /dev/null +++ b/src/components/SearchTipList/index.tsx @@ -0,0 +1,146 @@ +import React, { useRef, useState, useCallback, useMemo, forwardRef, useImperativeHandle, type Ref } from 'react' +import { StyleSheet, View, Animated } from 'react-native' +// import PropTypes from 'prop-types' +// import { AppColors } from '@/theme' +import { useTheme } from '@/store/theme/hook' +import List, { type ItemT, type ListProps, type ListType } from './List' +// import InsetShadow from 'react-native-inset-shadow' + +export interface SearchTipListProps<T> extends ListProps<T> { + onPressBg?: () => void +} +export interface SearchTipListType<T> { + setList: (list: T[]) => void + setHeight: (height: number) => void +} + +const noop = () => {} + +const Component = <T extends ItemT<T>>({ onPressBg = noop, ...props }: SearchTipListProps<T>, ref: Ref<SearchTipListType<T>>) => { + const theme = useTheme() + const translateY = useRef(new Animated.Value(0)).current + const scaleY = useRef(new Animated.Value(0)).current + const [visible, setVisible] = useState(false) + const [animatePlayed, setAnimatPlayed] = useState(true) + const listRef = useRef<ListType<T>>(null) + const prevListRef = useRef<T[]>([]) + const heightRef = useRef(0) + + useImperativeHandle(ref, () => ({ + setList(list) { + if (prevListRef.current.length) { + if (!list.length) handleHide() + } else if (list.length) handleShow() + prevListRef.current = list + requestAnimationFrame(() => { + listRef.current?.setList(list) + }) + }, + setHeight(height) { + heightRef.current = height + }, + })) + + + const handleShow = useCallback(() => { + // console.log('handleShow', height, visible) + if (!heightRef.current) return + setVisible(true) + setAnimatPlayed(false) + + translateY.setValue(-heightRef.current / 2) + scaleY.setValue(0) + + Animated.parallel([ + // Animated.timing(fade, { + // toValue: 1, + // duration: 300, + // useNativeDriver: true, + // }), + Animated.timing(translateY, { + toValue: 0, + duration: 300, + useNativeDriver: true, + }), + Animated.timing(scaleY, { + toValue: 1, + duration: 300, + useNativeDriver: true, + }), + ]).start(() => { + setAnimatPlayed(true) + }) + }, [translateY, scaleY]) + + const handleHide = useCallback(() => { + setAnimatPlayed(false) + Animated.parallel([ + // Animated.timing(fade, { + // toValue: 0, + // duration: 200, + // useNativeDriver: true, + // }), + Animated.timing(translateY, { + toValue: -heightRef.current / 2, + duration: 300, + useNativeDriver: true, + }), + Animated.timing(scaleY, { + toValue: 0, + duration: 300, + useNativeDriver: true, + }), + ]).start((finished) => { + // console.log(finished) + if (!finished) return + setVisible(false) + setAnimatPlayed(true) + }) + }, [translateY, scaleY]) + + + const component = useMemo(() => ( + <Animated.View + style={{ + ...styles.anima, + transform: [ + { translateY }, + { scaleY }, + ], + }}> + <View style={{ ...styles.container, backgroundColor: theme['c-content-background'] }}> + <List ref={listRef} {...props} /> + </View> + <View style={styles.blank} onTouchStart={onPressBg}></View> + </Animated.View> + ), [onPressBg, props, scaleY, theme, translateY]) + + return !visible && animatePlayed ? null : component +} + +export default forwardRef(Component) as + <T,>(p: SearchTipListProps<T> & { ref?: Ref<SearchTipListType<T>> }) => JSX.Element | null + +const styles = StyleSheet.create({ + anima: { + position: 'absolute', + left: 0, + top: 0, + height: '100%', + width: '100%', + zIndex: 10, + }, + container: { + flex: 0, + // flexGrow: 0, + // borderBottomWidth: BorderWidths.normal, + elevation: 2, + maxHeight: '80%', + }, + blank: { + flex: 1, + flexGrow: 1, + // backgroundColor: 'transparent', + // backgroundColor: 'rgba(0,0,0,0.2)', + }, +}) diff --git a/src/components/SourceSelector.tsx b/src/components/SourceSelector.tsx new file mode 100644 index 000000000..7ce919cac --- /dev/null +++ b/src/components/SourceSelector.tsx @@ -0,0 +1,77 @@ +import React, { forwardRef, type Ref, useImperativeHandle, useMemo, useState } from 'react' +import { View } from 'react-native' + +import DorpDownMenu, { type DorpDownMenuProps as _DorpDownMenuProps } from '@/components/common/DorpDownMenu' +import Text from '@/components/common/Text' +import { useI18n } from '@/lang' + +import { useSettingValue } from '@/store/setting/hook' +import { createStyle } from '@/utils/tools' + +type Sources = Readonly<Array<LX.OnlineSource | 'all'>> + +export interface SourceSelectorProps<S extends Sources> { + fontSize?: number + center?: _DorpDownMenuProps<any>['center'] + onSourceChange: (source: S[number]) => void +} + +export interface SourceSelectorType<S extends Sources> { + setSourceList: (list: S, activeSource: S[number]) => void +} + +const Component = <S extends Sources>({ fontSize = 15, center, onSourceChange }: SourceSelectorProps<S>, ref: Ref<SourceSelectorType<S>>) => { + const sourceNameType = useSettingValue('common.sourceNameType') + const [list, setList] = useState([] as unknown as S) + const [source, setSource] = useState<S[number]>('kw') + const t = useI18n() + + useImperativeHandle(ref, () => ({ + setSourceList(list, activeSource) { + setList(list) + setSource(activeSource) + }, + }), []) + + const sourceList_t = useMemo(() => { + return list.map(s => ({ label: t(`source_${sourceNameType}_${s}`), action: s })) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [list, sourceNameType, t]) + + type DorpDownMenuProps = _DorpDownMenuProps<typeof sourceList_t> + + const handleChangeSource: DorpDownMenuProps['onPress'] = ({ action }) => { + onSourceChange(action) + setSource(action) + } + + return ( + <DorpDownMenu + menus={sourceList_t} + center={center} + onPress={handleChangeSource} + fontSize={fontSize} + activeId={source} + > + <View style={styles.sourceMenu}> + <Text style={{ textAlign: center ? 'center' : 'left' }} numberOfLines={1} size={fontSize}>{t(`source_${sourceNameType}_${source}`)}</Text> + </View> + </DorpDownMenu> + ) +} + +export default forwardRef(Component) as <S extends Sources>(p: SourceSelectorProps<S> & { ref?: Ref<SourceSelectorType<S>> }) => JSX.Element | null + + +const styles = createStyle({ + sourceMenu: { + height: '100%', + justifyContent: 'center', + // paddingTop: 12, + // paddingBottom: 12, + paddingLeft: 15, + paddingRight: 15, + // backgroundColor: '#ccc', + + }, +}) diff --git a/src/components/TimeoutExitEditModal.tsx b/src/components/TimeoutExitEditModal.tsx new file mode 100644 index 000000000..38e357035 --- /dev/null +++ b/src/components/TimeoutExitEditModal.tsx @@ -0,0 +1,258 @@ +import React, { useRef, useImperativeHandle, forwardRef, useState, useEffect } from 'react' +import ConfirmAlert, { ConfirmAlertType } from '@/components/common/ConfirmAlert' +import Text from '@/components/common/Text' +import { View } from 'react-native' +import Input, { InputType } from '@/components/common/Input' +import { createStyle, toast } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { cancelTimeoutExit, getTimeoutExitTime, onTimeUpdate, startTimeoutExit, stopTimeoutExit, useTimeoutExitTimeInfo } from '@/core/player/timeoutExit' +import { useI18n } from '@/lang' +import CheckBox from './common/CheckBox' +import { useSettingValue } from '@/store/setting/hook' +import { updateSetting } from '@/core/common' +import settingState from '@/store/setting/state' + +const MAX_MIN = 1440 +const rxp = /([1-9]\d*)/ +const formatTime = (time: number) => { + // let d = parseInt(time / 86400) + // d = d ? d.toString() + ':' : '' + // time = time % 86400 + let h = Math.trunc(time / 3600) + let hStr = h ? h.toString() + ':' : '' + time = time % 3600 + const m = Math.trunc(time / 60).toString().padStart(2, '0') + const s = Math.trunc(time % 60).toString().padStart(2, '0') + return `${hStr}${m}:${s}` +} +const Status = () => { + const theme = useTheme() + const t = useI18n() + const exitTimeInfo = useTimeoutExitTimeInfo() + return ( + <View style={styles.tip}> + { + exitTimeInfo.time < 0 + ? ( + <Text>{t('timeout_exit_tip_off')}</Text> + ) + : ( + <Text>{t('timeout_exit_tip_on', { time: formatTime(exitTimeInfo.time) })}</Text> + ) + } + {exitTimeInfo.isPlayedStop ? <Text color={theme['c-font-label']} size={13}>{t('timeout_exit_btn_wait_tip')}</Text> : null} + </View> + ) +} + + +interface TimeInputType { + setText: (text: string) => void + getText: () => string + focus: () => void +} +const TimeInput = forwardRef<TimeInputType, {}>((props, ref) => { + const theme = useTheme() + const [text, setText] = useState('') + const inputRef = useRef<InputType>(null) + const t = useI18n() + + useImperativeHandle(ref, () => ({ + getText() { + return text.trim() + }, + setText(text) { + setText(text) + }, + focus() { + inputRef.current?.focus() + }, + })) + + return ( + <Input + ref={inputRef} + placeholder={t('timeout_exit_input_tip')} + value={text} + onChangeText={setText} + style={{ ...styles.input, backgroundColor: theme['c-primary-input-background'] }} + /> + ) +}) + + +const Setting = () => { + const t = useI18n() + const timeoutExitPlayed = useSettingValue('player.timeoutExitPlayed') + const onCheckChange = (check: boolean) => { + updateSetting({ 'player.timeoutExitPlayed': check }) + } + + return ( + <View style={styles.checkbox}> + <CheckBox check={timeoutExitPlayed} label={t('timeout_exit_label_isPlayed')} onChange={onCheckChange} /> + </View> + ) +} + +export const useTimeInfo = () => { + const [exitTimeInfo, setExitTimeInfo] = useState({ + cancelText: '', + confirmText: '', + isPlayedStop: false, + active: false, + }) + const t = useI18n() + + useEffect(() => { + let active: boolean | null = null + const remove = onTimeUpdate((time, isPlayedStop) => { + if (time < 0) { + if (active) { + setExitTimeInfo({ + cancelText: isPlayedStop ? t('timeout_exit_btn_wait_cancel') : '', + confirmText: '', + isPlayedStop, + active: false, + }) + active = false + } + } else { + if (active !== true) { + setExitTimeInfo({ + cancelText: t('timeout_exit_btn_cancel'), + confirmText: t('timeout_exit_btn_update'), + isPlayedStop, + active: true, + }) + active = true + } + } + }) + + return () => { + remove() + } + }, [t]) + + return exitTimeInfo +} + +export interface TimeoutExitEditModalType { + show: () => void +} +interface TimeoutExitEditModalProps { + timeInfo: ReturnType<typeof useTimeInfo> +} + +export default forwardRef<TimeoutExitEditModalType, TimeoutExitEditModalProps>(({ timeInfo }, ref) => { + const alertRef = useRef<ConfirmAlertType>(null) + const timeInputRef = useRef<TimeInputType>(null) + const [visible, setVisible] = useState(false) + const t = useI18n() + + const handleShow = () => { + alertRef.current?.setVisible(true) + requestAnimationFrame(() => { + if (settingState.setting['player.timeoutExit']) timeInputRef.current?.setText(settingState.setting['player.timeoutExit']) + // setTimeout(() => { + // timeInputRef.current?.focus() + // }, 300) + }) + } + useImperativeHandle(ref, () => ({ + show() { + if (visible) handleShow() + else { + setVisible(true) + requestAnimationFrame(() => { + handleShow() + }) + } + }, + })) + + const handleCancel = () => { + if (timeInfo.isPlayedStop) { + cancelTimeoutExit() + return + } + if (!timeInfo.active) return + stopTimeoutExit() + toast(t('timeout_exit_tip_cancel')) + } + const handleConfirm = () => { + let timeStr = timeInputRef.current?.getText() ?? '' + if (rxp.test(timeStr)) { + // if (timeStr != RegExp.$1) toast(t('input_error')) + timeStr = RegExp.$1 + if (parseInt(timeStr) > MAX_MIN) { + toast(t('timeout_exit_tip_max', { num: MAX_MIN })) + // timeStr = timeStr.substring(0, timeStr.length - 1) + return + } + } else { + if (timeStr.length) toast(t('input_error')) + timeStr = '' + } + if (!timeStr) return + const time = parseInt(timeStr) + cancelTimeoutExit() + startTimeoutExit(time * 60) + toast(t('timeout_exit_tip_on', { time: formatTime(getTimeoutExitTime()) })) + updateSetting({ 'player.timeoutExit': String(time) }) + alertRef.current?.setVisible(false) + } + + return ( + visible + ? <ConfirmAlert + ref={alertRef} + cancelText={timeInfo.cancelText} + confirmText={timeInfo.confirmText} + onCancel={handleCancel} + onConfirm={handleConfirm} + > + <View style={styles.alertContent}> + <Status /> + <View style={styles.inputContent}> + <TimeInput ref={timeInputRef} /> + <Text style={styles.inputLabel}>{t('timeout_exit_min')}</Text> + </View> + <Setting /> + </View> + </ConfirmAlert> + : null + ) +}) + +const styles = createStyle({ + alertContent: { + flexShrink: 1, + flexDirection: 'column', + }, + tip: { + marginBottom: 8, + }, + checkbox: { + marginTop: 5, + }, + inputContent: { + marginTop: 8, + flex: 1, + flexDirection: 'row', + alignItems: 'center', + }, + input: { + flexGrow: 1, + flexShrink: 1, + // borderRadius: 4, + // paddingTop: 2, + // paddingBottom: 2, + }, + inputLabel: { + marginLeft: 8, + }, +}) + + diff --git a/src/components/common/Badge.js b/src/components/common/Badge.js deleted file mode 100644 index 1e02a6465..000000000 --- a/src/components/common/Badge.js +++ /dev/null @@ -1,46 +0,0 @@ -import React, { memo, useMemo } from 'react' -import { StyleSheet, Text } from 'react-native' -import { useGetter } from '@/store' -// const menuItemHeight = 42 -// const menuItemWidth = 100 - -const styles = StyleSheet.create({ - text: { - // paddingLeft: 4, - // paddingRight: 4, - fontSize: 9, - // borderRadius: 2, - // lineHeight: 12, - marginTop: 2, - marginLeft: 5, - marginBottom: 2, - alignSelf: 'flex-start', - }, -}) - - -export default memo(({ type, children }) => { - const theme = useGetter('common', 'theme') - // console.log(visible) - const colors = useMemo(() => { - const colors = {} - switch (type) { - case 'normal': - // colors.bgColor = theme.primary - colors.textColor = theme.normal10 - break - case 'secondary': - // colors.bgColor = theme.primary - colors.textColor = theme.secondary10 - break - case 'tertiary': - // colors.bgColor = theme.primary - colors.textColor = theme.tertiary10 - break - } - return colors - }, [type, theme]) - - return <Text style={{ ...styles.text, color: colors.textColor }}>{children}</Text> -}) - diff --git a/src/components/common/Badge.tsx b/src/components/common/Badge.tsx new file mode 100644 index 000000000..d80e1e233 --- /dev/null +++ b/src/components/common/Badge.tsx @@ -0,0 +1,52 @@ +import React, { memo, useMemo } from 'react' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import Text from './Text' +// const menuItemHeight = 42 +// const menuItemWidth = 100 + +const styles = createStyle({ + text: { + // paddingLeft: 4, + // paddingRight: 4, + // borderRadius: 2, + // lineHeight: 12, + // marginTop: 2, + marginLeft: 5, + // marginRight: 5, + // marginBottom: 2, + // alignSelf: 'flex-start', + alignSelf: 'center', + }, +}) + +export type BadgeType = 'normal' | 'secondary' | 'tertiary' + +export default memo(({ type = 'normal', children }: { + type?: BadgeType + children: string +}) => { + const theme = useTheme() + // console.log(visible) + const colors = useMemo(() => { + const colors = { textColor: '' } + switch (type) { + case 'normal': + // colors.bgColor = theme.primary + colors.textColor = theme['c-badge-primary'] + break + case 'secondary': + // colors.bgColor = theme.primary + colors.textColor = theme['c-badge-secondary'] + break + case 'tertiary': + // colors.bgColor = theme.primary + colors.textColor = theme['c-badge-tertiary'] + break + } + return colors + }, [type, theme]) + + return <Text style={styles.text} size={9} color={colors.textColor}>{children}</Text> +}) + diff --git a/src/components/common/Button.js b/src/components/common/Button.js deleted file mode 100644 index 94e71b28f..000000000 --- a/src/components/common/Button.js +++ /dev/null @@ -1,30 +0,0 @@ -import React, { useMemo, useRef, useImperativeHandle, forwardRef } from 'react' -import { Pressable } from 'react-native' -import { useGetter } from '@/store' -// import { AppColors } from '@/theme' - -const Btn = ({ ripple: propsRipple, children, disabled, style, ...props }, ref) => { - const theme = useGetter('common', 'theme') - const btnRef = useRef() - const ripple = useMemo(() => ({ - color: theme.secondary30, - ...(propsRipple || {}), - }), [theme, propsRipple]) - - useImperativeHandle(ref, () => ({ - measure(callback) { - if (!btnRef.current) return - btnRef.current.measure(callback) - }, - })) - - return ( - <Pressable android_ripple={ripple} disabled={disabled} style={{ opacity: disabled ? 0.3 : 1, ...style }} {...props} ref={btnRef}> - {children} - </Pressable> - ) -} - - -export default forwardRef(Btn) - diff --git a/src/components/common/Button.tsx b/src/components/common/Button.tsx new file mode 100644 index 000000000..60228bf57 --- /dev/null +++ b/src/components/common/Button.tsx @@ -0,0 +1,46 @@ +import { useTheme } from '@/store/theme/hook' +import React, { useMemo, useRef, useImperativeHandle, forwardRef } from 'react' +import { Pressable, PressableProps, StyleSheet, View, ViewProps } from 'react-native' +// import { AppColors } from '@/theme' + + +export interface BtnProps extends PressableProps { + ripple?: PressableProps['android_ripple'] + style?: ViewProps['style'] + onChangeText?: (value: string) => void + onClearText?: () => void + children: React.ReactNode +} + + +export interface BtnType { + measure: (callback: (x: number, y: number, width: number, height: number, pageX: number, pageY: number) => void) => void +} + +export default forwardRef<BtnType, BtnProps>(({ ripple: propsRipple = {}, disabled, children, style, ...props }, ref) => { + const theme = useTheme() + const btnRef = useRef<View>(null) + const ripple = useMemo(() => ({ + color: theme['c-primary-light-200-alpha-700'], + ...propsRipple, + }), [theme, propsRipple]) + + useImperativeHandle(ref, () => ({ + measure(callback) { + btnRef.current?.measure(callback) + }, + })) + + return ( + <Pressable + android_ripple={ripple} + disabled={disabled} + style={StyleSheet.compose({ opacity: disabled ? 0.3 : 1 }, style)} + {...props} + ref={btnRef} + > + {children} + </Pressable> + ) +}) + diff --git a/src/components/common/CheckBox.js b/src/components/common/CheckBox.tsx similarity index 52% rename from src/components/common/CheckBox.js rename to src/components/common/CheckBox.tsx index 08b219f2f..0f28139e9 100644 --- a/src/components/common/CheckBox.js +++ b/src/components/common/CheckBox.tsx @@ -1,24 +1,34 @@ -import React, { useCallback, useEffect, useMemo, useState } from 'react' -import { StyleSheet, View, TouchableOpacity, Text } from 'react-native' +import React, { useCallback, useEffect, useState } from 'react' +import { View, TouchableOpacity } from 'react-native' import CheckBox from '@react-native-community/checkbox' -import { useGetter } from '@/store' +import { createStyle } from '@/utils/tools' +import { scaleSizeH, scaleSizeW } from '@/utils/pixelRatio' +import { useTheme } from '@/store/theme/hook' +import Text from './Text' -export default ({ check, label, children, onChange, disabled = false, need = false, marginRight = 0, marginBottom = 0 }) => { - const theme = useGetter('common', 'theme') +export interface CheckBoxProps { + check: boolean + label: string + children?: React.ReactNode + onChange: (check: boolean) => void + disabled?: boolean + need?: boolean + marginRight?: number + marginBottom?: number +} + +export default ({ check, label, children, onChange, disabled = false, need = false, marginRight = 0, marginBottom = 0 }: CheckBoxProps) => { + const theme = useTheme() const [isDisabled, setDisabled] = useState(false) - const tintColors = useMemo(() => { - return { - true: theme.secondary, - false: theme.normal35, - } - }, [theme]) - const disabledTintColors = useMemo(() => { - return { - true: theme.secondary30, - false: theme.normal60, - } - }, [theme]) + const tintColors = { + true: theme['c-primary'], + false: theme['c-600'], + } + const disabledTintColors = { + true: theme['c-primary-alpha-600'], + false: theme['c-400'], + } useEffect(() => { if (need) { @@ -34,33 +44,33 @@ export default ({ check, label, children, onChange, disabled = false, need = fal const handleLabelPress = useCallback(() => { if (isDisabled) return - onChange && onChange(!check) + onChange?.(!check) }, [isDisabled, onChange, check]) - const contentStyle = StyleSheet.compose(styles.content, { marginBottom }) - const labelStyle = StyleSheet.compose(styles.label, { marginRight }) + const contentStyle = { ...styles.content, marginBottom: scaleSizeH(marginBottom) } + const labelStyle = { ...styles.label, marginRight: scaleSizeW(marginRight) } return ( disabled ? ( <View style={contentStyle}> <CheckBox style={styles.checkbox} value={check} disabled={true} tintColors={disabledTintColors} /> - <View style={labelStyle}>{label ? <Text style={{ ...styles.name, color: theme.normal40 }}>{label}</Text> : children}</View> + <View style={labelStyle}>{label ? <Text style={styles.name} color={theme['c-500']}>{label}</Text> : children}</View> </View> ) : ( <View style={contentStyle}> - <CheckBox value={check} disabled={isDisabled} onValueChange={onChange} tintColors={tintColors} /> + <CheckBox value={check} disabled={isDisabled} onValueChange={onChange} tintColors={tintColors} scale={1} /> <TouchableOpacity style={labelStyle} activeOpacity={0.3} onPress={handleLabelPress}> - {label ? <Text style={{ ...styles.name, color: theme.normal }}>{label}</Text> : children} + {label ? <Text style={styles.name}>{label}</Text> : children} </TouchableOpacity> </View> ) ) } -const styles = StyleSheet.create({ +const styles = createStyle({ content: { flexGrow: 0, flexShrink: 1, @@ -79,11 +89,10 @@ const styles = StyleSheet.create({ // marginRight: 15, // alignItems: 'center', // backgroundColor: 'rgba(0,0,0,0.2)', - // paddingRight: 8, + paddingRight: 3, }, name: { marginTop: 2, - fontSize: 13, }, }) diff --git a/src/components/common/ChoosePath/List.js b/src/components/common/ChoosePath/List.js deleted file mode 100644 index 6ecf756a4..000000000 --- a/src/components/common/ChoosePath/List.js +++ /dev/null @@ -1,128 +0,0 @@ -import React, { useEffect, useState, useRef, useCallback } from 'react' -import { View, StyleSheet } from 'react-native' -import { readDir, externalStorageDirectoryPath } from '@/utils/fs' -import { toast } from '@/utils/tools' -// import { useTranslation } from '@/plugins/i18n' -import { useGetter, useDispatch } from '@/store' -import Modal from '@/components/common/Modal' - -import Header from './components/Header' -import Main from './components/Main' -import Footer from './components/Footer' -import { sizeFormate } from '@/utils' -// let prevPath = externalStorageDirectoryPath - -const caches = {} - -const handleReadDir = (path, dirOnly, filter, isRefresh = false) => { - const cacheKey = `${path}_${dirOnly ? 'true' : 'false'}_${filter ? filter.toString() : 'null'}` - if (!isRefresh && caches[cacheKey]) return Promise.resolve(caches[cacheKey]) - return readDir(path).then(paths => { - // console.log('read') - // prevPath = path - const list = [] - // console.log(paths) - for (const path of paths) { - // console.log(path) - const isDirectory = path.isDirectory() - if (dirOnly) { - if (!isDirectory) continue - list.push({ - name: path.name, - path: path.path, - mtime: path.mtime, - size: path.size, - isDir: true, - }) - } else { - if (filter != null && path.isFile() && !filter.test(path.name)) continue - - list.push({ - name: path.name, - path: path.path, - mtime: path.mtime, - size: path.size, - isDir: isDirectory, - sizeText: isDirectory ? '' : sizeFormate(path.size), - }) - } - } - - list.sort((a, b) => a.name.charCodeAt(0) - b.name.charCodeAt(0)) - caches[cacheKey] = list - return list - }) -} - -export default ({ dirOnly = false, filter, onConfirm, title, granted, visible, hide }) => { - const [path, setPath] = useState(externalStorageDirectoryPath) - const [list, setList] = useState([]) - const isUnmountedRef = useRef(true) - const isReadingDir = useRef(false) - const theme = useGetter('common', 'theme') - - useEffect(() => { - isUnmountedRef.current = false - return () => isUnmountedRef.current = true - }, []) - - const readDir = useCallback((path, dirOnly, filter, isRefresh) => { - if (isReadingDir.current) return - isReadingDir.current = true - return handleReadDir(path, dirOnly, filter, isRefresh).then(list => { - if (isUnmountedRef.current) return - setList(list) - setPath(path) - }).catch(err => { - toast(`Read dir error: ${err.message}`, 'long') - // console.log('prevPath', prevPath) - // if (isReadingDir.current) return - // setPath(prevPath) - }).finally(() => { - isReadingDir.current = false - }) - }, [setPath]) - - useEffect(() => { - // console.log(granted) - if (!granted) return - readDir(path, dirOnly, filter) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [granted, filter, dirOnly]) - - const onSetPath = useCallback(pathInfo => { - // console.log('onSetPath') - if (pathInfo.isDir) { - readDir(pathInfo.path, dirOnly, filter) - } else { - onConfirm(pathInfo.path) - // setPath(pathInfo.path) - } - }, [dirOnly, filter, onConfirm, readDir]) - - - const toParentDir = useCallback(() => { - const parentPath = path.substring(0, path.lastIndexOf('/')) - readDir(parentPath.length ? parentPath : externalStorageDirectoryPath, dirOnly, filter) - }, [dirOnly, filter, path, readDir]) - - // const dirList = useMemo(() => [parentDir, ...list], [list, parentDir]) - - return ( - <Modal visible={visible} hideModal={hide} bgHide={false}> - <View style={{ ...styles.container, backgroundColor: theme.primary }}> - <Header refreshDir={path => readDir(path, dirOnly, filter, true)} title={title} path={path} /> - <Main list={list} granted={granted} toParentDir={toParentDir} onSetPath={onSetPath} /> - <Footer onConfirm={() => onConfirm(path)} hide={hide} dirOnly={dirOnly} /> - </View> - </Modal> - ) -} - - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, -}) - diff --git a/src/components/common/ChoosePath/List.tsx b/src/components/common/ChoosePath/List.tsx new file mode 100644 index 000000000..54054aa4b --- /dev/null +++ b/src/components/common/ChoosePath/List.tsx @@ -0,0 +1,168 @@ +import React, { useEffect, useState, useRef, forwardRef, useImperativeHandle } from 'react' +import { View } from 'react-native' +import { readDir, externalStorageDirectoryPath } from '@/utils/fs' +import { createStyle, toast } from '@/utils/tools' +// import { useTranslation } from '@/plugins/i18n' +import Modal, { type ModalType } from '@/components/common/Modal' + +import Header from './components/Header' +import Main from './components/Main' +import Footer from './components/Footer' +import { sizeFormate } from '@/utils' +import { useTheme } from '@/store/theme/hook' +import { type PathItem } from './components/ListItem' +// let prevPath = externalStorageDirectoryPath + +const caches = new Map<string, PathItem[]>() + +const handleReadDir = async(path: string, dirOnly: boolean, filter?: RegExp, isRefresh = false) => { + const cacheKey = `${path}_${dirOnly ? 'true' : 'false'}_${filter ? filter.toString() : 'null'}` + if (!isRefresh && caches.has(cacheKey)) return caches.get(cacheKey) as PathItem[] + return readDir(path).then(paths => { + // console.log('read') + // prevPath = path + const list = [] as PathItem[] + // console.log(paths) + for (const path of paths) { + // console.log(path) + const isDirectory = path.isDirectory() + if (dirOnly) { + if (!isDirectory) continue + list.push({ + name: path.name, + path: path.path, + mtime: path.mtime, + size: path.size, + isDir: true, + sizeText: '', + }) + } else { + if (filter != null && path.isFile() && !filter.test(path.name)) continue + + list.push({ + name: path.name, + path: path.path, + mtime: path.mtime, + size: path.size, + isDir: isDirectory, + sizeText: isDirectory ? '' : sizeFormate(path.size), + }) + } + } + + list.sort((a, b) => a.name.charCodeAt(0) - b.name.charCodeAt(0)) + caches.set(cacheKey, list) + return list + }) +} + +interface ReadOptions { + title: string + dirOnly: boolean + filter?: RegExp +} +const initReadOptions = {} +export interface ListProps { + onConfirm: (path: string) => void + onHide?: () => void +} + +export interface ListType { + show: (title: string, dirOnly?: boolean, filter?: RegExp) => void + hide: () => void +} + +export default forwardRef<ListType, ListProps>(({ + onConfirm, + onHide = () => {}, +}: ListProps, ref) => { + const [path, setPath] = useState(externalStorageDirectoryPath) + const [list, setList] = useState<PathItem[]>([]) + const isUnmountedRef = useRef(true) + const readOptions = useRef<ReadOptions>(initReadOptions as ReadOptions) + const isReadingDir = useRef(false) + const modalRef = useRef<ModalType>(null) + const theme = useTheme() + + useImperativeHandle(ref, () => ({ + show(title, dirOnly = false, filter) { + readOptions.current = { + title, + dirOnly, + filter, + } + modalRef.current?.setVisible(true) + void readDir(path, dirOnly, filter) + }, + hide() { + modalRef.current?.setVisible(false) + }, + })) + + useEffect(() => { + isUnmountedRef.current = false + return () => { + isUnmountedRef.current = true + } + }, []) + + const readDir = async(path: string, dirOnly: boolean, filter?: RegExp, isRefresh?: boolean) => { + if (isReadingDir.current) return + isReadingDir.current = true + return handleReadDir(path, dirOnly, filter, isRefresh).then(list => { + if (isUnmountedRef.current) return + setList(list) + setPath(path) + }).catch((err: any) => { + toast(`Read dir error: ${err.message as string}`, 'long') + // console.log('prevPath', prevPath) + // if (isReadingDir.current) return + // setPath(prevPath) + }).finally(() => { + isReadingDir.current = false + }) + } + + const onSetPath = (pathInfo: PathItem) => { + // console.log('onSetPath') + if (pathInfo.isDir) { + void readDir(pathInfo.path, readOptions.current.dirOnly, readOptions.current.filter) + } else { + onConfirm(pathInfo.path) + // setPath(pathInfo.path) + } + } + + const toParentDir = () => { + const parentPath = path.substring(0, path.lastIndexOf('/')) + void readDir(parentPath.length ? parentPath : externalStorageDirectoryPath, readOptions.current.dirOnly, readOptions.current.filter) + } + + const handleHide = () => { + modalRef.current?.setVisible(false) + onHide() + } + + // const dirList = useMemo(() => [parentDir, ...list], [list, parentDir]) + + return ( + <Modal ref={modalRef} bgHide={false} statusBarPadding={false}> + <View style={{ ...styles.container, backgroundColor: theme['c-content-background'] }}> + <Header + onRefreshDir={async(path) => readDir(path, readOptions.current.dirOnly, readOptions.current.filter, true)} + title={readOptions.current.title} + path={path} /> + <Main list={list} toParentDir={toParentDir} onSetPath={onSetPath} /> + <Footer onConfirm={() => { onConfirm(path) }} onHide={handleHide} dirOnly={readOptions.current.dirOnly} /> + </View> + </Modal> + ) +}) + + +const styles = createStyle({ + container: { + flex: 1, + }, +}) + diff --git a/src/components/common/ChoosePath/components/Footer.js b/src/components/common/ChoosePath/components/Footer.js deleted file mode 100644 index bc1819ec0..000000000 --- a/src/components/common/ChoosePath/components/Footer.js +++ /dev/null @@ -1,40 +0,0 @@ -import React, { memo } from 'react' -import { View, StyleSheet, Text } from 'react-native' -import { useTranslation } from '@/plugins/i18n' -import { useGetter } from '@/store' -import Button from '@/components/common/Button' -import { BorderWidths } from '@/theme' - -export default memo(({ onConfirm, hide, dirOnly }) => { - const { t } = useTranslation() - const theme = useGetter('common', 'theme') - - return ( - <View style={{ ...styles.footer, borderTopColor: theme.secondary30 }} > - <Button style={{ ...styles.footerBtn, backgroundColor: theme.secondary45, width: dirOnly ? '50%' : '100%' }} onPress={hide}> - <Text style={{ color: theme.secondary_5 }}>{t('cancel')}</Text> - </Button> - {dirOnly - ? <Button style={{ ...styles.footerBtn, backgroundColor: theme.secondary45 }} onPress={onConfirm}> - <Text style={{ fontSize: 14, color: theme.secondary_5 }}>{t('confirm')}</Text> - </Button> - : null - } - </View> - ) -}) - -const styles = StyleSheet.create({ - footer: { - flexGrow: 0, - flexShrink: 0, - flexDirection: 'row', - borderTopWidth: BorderWidths.normal2, - }, - footerBtn: { - width: '50%', - paddingTop: 15, - paddingBottom: 15, - alignItems: 'center', - }, -}) diff --git a/src/components/common/ChoosePath/components/Footer.tsx b/src/components/common/ChoosePath/components/Footer.tsx new file mode 100644 index 000000000..3e2b15fe9 --- /dev/null +++ b/src/components/common/ChoosePath/components/Footer.tsx @@ -0,0 +1,45 @@ +import React, { memo } from 'react' +import { View, StyleSheet } from 'react-native' +import Button from '@/components/common/Button' +import Text from '@/components/common/Text' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' + +export default memo(({ onConfirm, onHide, dirOnly }: { + onConfirm: () => void + onHide: () => void + dirOnly: boolean +}) => { + const t = useI18n() + const theme = useTheme() + + return ( + <View style={{ ...styles.footer, backgroundColor: theme['c-content-background'] }}> + <Button style={{ ...styles.footerBtn, width: dirOnly ? '50%' : '100%' }} onPress={onHide}> + <Text color={theme['c-button-font']}>{t('cancel')}</Text> + </Button> + {dirOnly + ? <Button style={styles.footerBtn} onPress={onConfirm}> + <Text color={theme['c-button-font']}>{t('confirm')}</Text> + </Button> + : null + } + </View> + ) +}) + +const styles = StyleSheet.create({ + footer: { + flexGrow: 0, + flexShrink: 0, + flexDirection: 'row', + // borderTopWidth: BorderWidths.normal, + elevation: 8, + }, + footerBtn: { + width: '50%', + paddingTop: 16, + paddingBottom: 16, + alignItems: 'center', + }, +}) diff --git a/src/components/common/ChoosePath/components/Header.js b/src/components/common/ChoosePath/components/Header.js deleted file mode 100644 index 3bc6cb783..000000000 --- a/src/components/common/ChoosePath/components/Header.js +++ /dev/null @@ -1,127 +0,0 @@ -import React, { useCallback, memo, useRef, useState } from 'react' -import { StyleSheet, View, Text, TouchableOpacity, StatusBar, InteractionManager } from 'react-native' -import { useGetter } from '@/store' -import { Icon } from '@/components/common/Icon' -import Input from '@/components/common/Input' -import ConfirmAlert from '@/components/common/ConfirmAlert' -import { useTranslation } from '@/plugins/i18n' -import { toast } from '@/utils/tools' -import { mkdir } from '@/utils/fs' -const filterFileName = /[\\/:*?#"<>|]/ - -export default memo(({ title, path, refreshDir }) => { - const theme = useGetter('common', 'theme') - const [visibleNewFolder, setVisibleNewFolder] = useState(false) - const { t } = useTranslation() - const [text, setText] = useState('') - // const moreButtonRef = useRef() - // const handleShowMenu = useCallback(() => { - // if (moreButtonRef.current && moreButtonRef.current.measure) { - // moreButtonRef.current.measure((fx, fy, width, height, px, py) => { - // // console.log(fx, fy, width, height, px, py) - // showMenu(item, index, { x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }) - // }) - // } - // }, [item, index, showMenu]) - - const refresh = useCallback(() => { - InteractionManager.runAfterInteractions(() => { - refreshDir(path) - }) - }, [refreshDir, path]) - - const handleCancelNewFolderAlert = useCallback(() => { - setVisibleNewFolder(false) - setText('') - }, []) - const handleConfirmNewFolderAlert = useCallback(() => { - if (filterFileName.test(text)) { - toast(t('create_new_folder_error_tip'), 'long') - return - } - const newPath = `${path}/${text}` - mkdir(newPath).then(() => { - refreshDir(path).then(() => { - refreshDir(newPath) - }) - setText('') - }).catch(err => { - toast('Create failed: ' + err.message) - }) - setVisibleNewFolder(false) - }, [path, refreshDir, t, text]) - - return ( - <> - <View style={{ ...styles.header, backgroundColor: theme.secondary }} onStartShouldSetResponder={() => true}> - <View style={styles.titleContent}> - <Text style={{ ...styles.title, color: theme.primary }} numberOfLines={1}>{title}</Text> - <Text style={{ color: theme.primary, fontSize: 12 }} numberOfLines={1}>{path}</Text> - </View> - <View style={styles.actions}> - <TouchableOpacity style={styles.actionBtn} onPress={() => setVisibleNewFolder(true)}><Icon name="folder-plus" style={{ color: theme.primary, fontSize: 20 }} /></TouchableOpacity> - <TouchableOpacity style={styles.actionBtn} onPress={refresh}><Icon name="autorenew" style={{ color: theme.primary, fontSize: 20 }} /></TouchableOpacity> - </View> - </View> - <ConfirmAlert - visible={visibleNewFolder} - onHide={handleCancelNewFolderAlert} - onConfirm={handleConfirmNewFolderAlert} - > - <View style={styles.newFolderContent}> - <Text style={{ color: theme.normal, marginBottom: 5 }}>{t('create_new_folder')}</Text> - <Input - placeholder={t('create_new_folder_tip')} - value={text} - onChangeText={setText} - style={{ ...styles.input, backgroundColor: theme.secondary40 }} - /> - </View> - </ConfirmAlert> - </> - ) -}) - -const styles = StyleSheet.create({ - header: { - flexGrow: 0, - flexShrink: 0, - flexDirection: 'row', - paddingLeft: 15, - paddingRight: 15, - paddingTop: StatusBar.currentHeight, - alignItems: 'center', - }, - titleContent: { - flexGrow: 1, - flexShrink: 1, - height: 57, - paddingRight: 5, - // paddingBottom: 10, - }, - title: { - fontSize: 16, - paddingTop: 10, - }, - actions: { - flexDirection: 'row', - // backgroundColor: 'rgba(0,0,0,0.2)', - }, - actionBtn: { - padding: 8, - }, - newFolderContent: { - flexShrink: 1, - flexDirection: 'column', - }, - input: { - flexGrow: 1, - flexShrink: 1, - minWidth: 240, - borderRadius: 4, - paddingTop: 2, - paddingBottom: 2, - fontSize: 12, - }, -}) - diff --git a/src/components/common/ChoosePath/components/Header.tsx b/src/components/common/ChoosePath/components/Header.tsx new file mode 100644 index 000000000..debe47931 --- /dev/null +++ b/src/components/common/ChoosePath/components/Header.tsx @@ -0,0 +1,179 @@ +import React, { forwardRef, memo, useImperativeHandle, useRef, useState } from 'react' +import { View, TouchableOpacity } from 'react-native' +import Input, { InputType } from '@/components/common/Input' +import Text from '@/components/common/Text' +import { Icon } from '@/components/common/Icon' +import StatusBar from '@/components/common/StatusBar' +import ConfirmAlert, { ConfirmAlertType } from '@/components/common/ConfirmAlert' +import { createStyle, toast } from '@/utils/tools' +import { mkdir } from '@/utils/fs' +import { useTheme } from '@/store/theme/hook' +import { scaleSizeH } from '@/utils/pixelRatio' +const filterFileName = /[\\/:*?#"<>|]/ + + +interface NameInputType { + setName: (text: string) => void + getText: () => string + focus: () => void +} +const NameInput = forwardRef<NameInputType, {}>((props, ref) => { + const theme = useTheme() + const [text, setText] = useState('') + const inputRef = useRef<InputType>(null) + + useImperativeHandle(ref, () => ({ + getText() { + return text.trim() + }, + setName(text) { + setText(text) + }, + focus() { + inputRef.current?.focus() + }, + })) + + return ( + <Input + ref={inputRef} + placeholder={global.i18n.t('create_new_folder_tip')} + value={text} + onChangeText={setText} + style={{ ...styles.input, backgroundColor: theme['c-primary-input-background'] }} + /> + ) +}) + + +export default memo(({ title, path, onRefreshDir }: { + title: string + path: string + onRefreshDir: (dir: string) => Promise<void> +}) => { + const theme = useTheme() + const confirmAlertRef = useRef<ConfirmAlertType>(null) + const nameInputRef = useRef<NameInputType>(null) + + const refresh = () => { + void onRefreshDir(path) + } + + const handleShow = () => { + confirmAlertRef.current?.setVisible(true) + requestAnimationFrame(() => { + setTimeout(() => { + nameInputRef.current?.focus() + }, 300) + }) + } + + const handleHideNewFolderAlert = () => { + nameInputRef.current?.setName('') + } + const handleConfirmNewFolderAlert = () => { + const text = nameInputRef.current?.getText() ?? '' + if (!text) return + if (filterFileName.test(text)) { + toast(global.i18n.t('create_new_folder_error_tip'), 'long') + return + } + const newPath = `${path}/${text}` + mkdir(newPath).then(() => { + void onRefreshDir(path).then(() => { + void onRefreshDir(newPath) + }) + nameInputRef.current?.setName('') + }).catch((err: any) => { + toast('Create failed: ' + (err.message as string)) + }) + confirmAlertRef.current?.setVisible(false) + } + + return ( + <> + <View style={{ + ...styles.header, + height: scaleSizeH(50) + StatusBar.currentHeight, + paddingTop: StatusBar.currentHeight, + backgroundColor: theme['c-content-background'], + }} onStartShouldSetResponder={() => true}> + <View style={styles.titleContent}> + <Text color={theme['c-primary-font']} numberOfLines={1}>{title}</Text> + <Text style={styles.subTitle} color={theme['c-primary-font']} size={13} numberOfLines={1}>{path}</Text> + </View> + <View style={styles.actions}> + <TouchableOpacity style={styles.actionBtn} onPress={handleShow}> + <Icon name="add_folder" color={theme['c-primary-font']} size={22} /> + </TouchableOpacity> + <TouchableOpacity style={styles.actionBtn} onPress={refresh}> + <Icon name="available_updates" color={theme['c-primary-font']} size={22} /> + </TouchableOpacity> + </View> + </View> + <ConfirmAlert + onHide={handleHideNewFolderAlert} + onConfirm={handleConfirmNewFolderAlert} + ref={confirmAlertRef} + > + <View style={styles.newFolderContent}> + <Text style={styles.newFolderTitle}>{global.i18n.t('create_new_folder')}</Text> + <NameInput ref={nameInputRef} /> + </View> + </ConfirmAlert> + </> + ) +}) + +const styles = createStyle({ + header: { + flexGrow: 0, + flexShrink: 0, + flexDirection: 'row', + paddingLeft: 15, + paddingRight: 15, + alignItems: 'center', + elevation: 2, + // borderBottomWidth: BorderWidths.normal, + }, + titleContent: { + flexGrow: 1, + flexShrink: 1, + // height: 57, + // paddingRight: 5, + // paddingBottom: 10, + }, + // title: { + // paddingTop: 10, + // }, + subTitle: { + paddingTop: 1, + }, + actions: { + flexDirection: 'row', + // backgroundColor: 'rgba(0,0,0,0.2)', + }, + actionBtn: { + paddingTop: 8, + paddingBottom: 8, + paddingLeft: 6, + paddingRight: 6, + marginLeft: 10, + }, + newFolderContent: { + flexShrink: 1, + flexDirection: 'column', + }, + newFolderTitle: { + marginBottom: 5, + }, + input: { + flexGrow: 1, + flexShrink: 1, + minWidth: 240, + borderRadius: 4, + paddingTop: 2, + paddingBottom: 2, + }, +}) + diff --git a/src/components/common/ChoosePath/components/ListItem.js b/src/components/common/ChoosePath/components/ListItem.tsx similarity index 54% rename from src/components/common/ChoosePath/components/ListItem.js rename to src/components/common/ChoosePath/components/ListItem.tsx index 5daf19626..3acf41c3a 100644 --- a/src/components/common/ChoosePath/components/ListItem.js +++ b/src/components/common/ChoosePath/components/ListItem.tsx @@ -1,12 +1,25 @@ -import React, { useCallback, memo, useRef } from 'react' -import { StyleSheet, View, Text, TouchableOpacity } from 'react-native' -import { useGetter } from '@/store' -import { BorderWidths } from '@/theme' +import React, { memo } from 'react' +import { View, TouchableOpacity } from 'react-native' import { Icon } from '@/components/common/Icon' +import { useTheme } from '@/store/theme/hook' +import Text from '@/components/common/Text' +import { createStyle } from '@/utils/tools' +export interface PathItem { + name: string + path: string + isDir: boolean + mtime?: Date + desc?: string + size?: number + sizeText?: string +} -export default memo(({ item, onPress }) => { - const theme = useGetter('common', 'theme') +export default memo(({ item, onPress }: { + item: PathItem + onPress: (item: PathItem) => void +}) => { + const theme = useTheme() // const moreButtonRef = useRef() // const handleShowMenu = useCallback(() => { @@ -19,21 +32,23 @@ export default memo(({ item, onPress }) => { // }, [item, index, showMenu]) return ( - <View style={{ ...styles.listItem, borderBottomWidth: BorderWidths.normal, borderBottomColor: theme.borderColor2 }}> + <View style={styles.listItem}> <TouchableOpacity style={styles.listItem} onPress={ () => { onPress(item) } }> <View style={styles.itemInfo}> - <View style={styles.listItemTitle}> - <Text style={{ ...styles.listItemTitleText, color: theme.normal }}>{item.name}</Text> - </View> - <View style={styles.row2}><Text style={{ ...styles.listItemDesc, color: theme.normal50 }} numberOfLines={1}>{item.mtime ? new Date(item.mtime).toLocaleString() : item.desc}</Text></View> + <Text style={styles.listItemTitleText}>{item.name}</Text> + <Text style={styles.listItemDesc} size={12} color={theme['c-font-label']} numberOfLines={1}>{item.mtime ? new Date(item.mtime).toLocaleString() : item.desc}</Text> </View> - {item.isDir ? <Icon name="chevron-right-2" style={{ color: theme.secondary20, fontSize: 18 }} /> : <Text style={{ ...styles.size, color: theme.normal40 }}>{item.sizeText}</Text>} + { + item.isDir + ? <Icon name="chevron-right" color={theme['c-primary-light-100-alpha-600']} size={18} /> + : <Text style={styles.size} size={12} color={theme['c-font-label']}>{item.sizeText}</Text> + } </TouchableOpacity> </View> ) }) -const styles = StyleSheet.create({ +const styles = createStyle({ listItem: { width: '100%', flexDirection: 'row', @@ -49,22 +64,17 @@ const styles = StyleSheet.create({ paddingTop: 10, paddingBottom: 10, }, - listItemTitle: { + listItemTitleText: { flexDirection: 'row', alignItems: 'flex-end', - }, - listItemTitleText: { // backgroundColor: 'rgba(0,0,0,0.2)', flexGrow: 0, flexShrink: 1, - fontSize: 15, }, listItemDesc: { - fontSize: 11, paddingTop: 2, }, size: { - fontSize: 11, alignSelf: 'flex-end', marginBottom: 10, }, diff --git a/src/components/common/ChoosePath/components/Main.js b/src/components/common/ChoosePath/components/Main.js deleted file mode 100644 index 5224c9535..000000000 --- a/src/components/common/ChoosePath/components/Main.js +++ /dev/null @@ -1,57 +0,0 @@ -import React, { useMemo } from 'react' -import { View, StyleSheet, FlatList, Text } from 'react-native' -import { useTranslation } from '@/plugins/i18n' - -import ListItem from './ListItem' - - -export default ({ granted, list, onSetPath, toParentDir }) => { - const { t } = useTranslation() - - const ParentItemComponent = useMemo(() => ( - <ListItem style={{ flexGrow: 0, flexShrink: 0 }} item={{ - name: '..', - desc: t('parent_dir_name'), - isDir: true, - }} onPress={toParentDir} /> - ), [t, toParentDir]) - - const ListComponent = useMemo(() => ( - <FlatList - keyboardShouldPersistTaps={'always'} - style={styles.list} - data={list} - renderItem={({ item }) => <ListItem item={item} onPress={onSetPath} />} - keyExtractor={item => item.path + '/' + item.name} - removeClippedSubviews={true} - /> - ), [list, onSetPath]) - - // const dirList = useMemo(() => [parentDir, ...list], [list, parentDir]) - - return ( - <View style={styles.main}> - { - granted - ? <> - {ParentItemComponent} - {ListComponent} - </> - : null - } - </View> - ) -} - - -const styles = StyleSheet.create({ - main: { - flexGrow: 1, - flexShrink: 1, - }, - list: { - flexGrow: 1, - flexShrink: 1, - }, -}) - diff --git a/src/components/common/ChoosePath/components/Main.tsx b/src/components/common/ChoosePath/components/Main.tsx new file mode 100644 index 000000000..dbeb5dd6f --- /dev/null +++ b/src/components/common/ChoosePath/components/Main.tsx @@ -0,0 +1,61 @@ +import { useI18n } from '@/lang' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import React, { useMemo } from 'react' +import { View, FlatList } from 'react-native' + +import ListItem, { PathItem } from './ListItem' + + +export default ({ list, onSetPath, toParentDir }: { + list: PathItem[] + onSetPath: (item: PathItem) => void + toParentDir: () => void +}) => { + const t = useI18n() + const theme = useTheme() + + const ParentItemComponent = useMemo(() => ( + <View style={{ backgroundColor: theme['c-primary-light-700-alpha-900'] }}> + <ListItem item={{ + name: '..', + desc: t('parent_dir_name'), + isDir: true, + path: '', + }} onPress={toParentDir} /> + </View> + ), [t, theme, toParentDir]) + + const ListComponent = useMemo(() => ( + <FlatList + keyboardShouldPersistTaps={'always'} + style={styles.list} + data={list} + renderItem={({ item }) => <ListItem item={item} onPress={onSetPath} />} + keyExtractor={item => item.path + '/' + item.name} + removeClippedSubviews={true} + /> + ), [list, onSetPath]) + + // const dirList = useMemo(() => [parentDir, ...list], [list, parentDir]) + + return ( + <View style={styles.main}> + {ParentItemComponent} + {ListComponent} + </View> + ) +} + + +const styles = createStyle({ + main: { + flexGrow: 1, + flexShrink: 1, + }, + list: { + flexGrow: 1, + flexShrink: 1, + }, +}) + diff --git a/src/components/common/ChoosePath/index.js b/src/components/common/ChoosePath/index.js deleted file mode 100644 index 32df1aca3..000000000 --- a/src/components/common/ChoosePath/index.js +++ /dev/null @@ -1,78 +0,0 @@ -import React, { memo, useCallback, useEffect, useState, useRef } from 'react' -// import { StyleSheet, View, Text, StatusBar, ScrollView } from 'react-native' - -// import { useGetter, useDispatch } from '@/store' -import List from './List' - -import { useTranslation } from '@/plugins/i18n' -import { checkStoragePermissions, requestStoragePermission } from '@/utils/permissions' -import ConfirmAlert from '@/components/common/ConfirmAlert' -import { toast } from '@/utils/tools' - - -export default ({ - visible = false, - hide = () => {}, - dirOnly = false, - title = '', - filter, - onConfirm = () => {}, -}) => { - const { t } = useTranslation() - const [granted, setGranted] = useState(false) - const [visibleTips, setVisibleTips] = useState(false) - - useEffect(() => { - if (visible) { - checkStoragePermissions().then(isGranted => { - // console.log(isGranted) - if (isGranted) { - setGranted(isGranted) - } else { - setVisibleTips(true) - } - }) - } - }, [visible]) - - const handleTipsCancel = useCallback(() => { - toast(t('disagree_tip'), 'long') - setVisibleTips(false) - hide() - }, [t, hide]) - const handleTipsConfirm = useCallback(() => { - setVisibleTips(false) - if (granted === null) return hide() - requestStoragePermission().then(result => { - // console.log(result) - setGranted(result) - if (!result) { - setVisibleTips(true) - toast(t('storage_permission_tip_disagree'), 'long') - } - }) - }, [granted, t, hide]) - - return ( - <> - <List - dirOnly={dirOnly} - filter={filter} - title={title} - granted={granted} - hide={hide} - onConfirm={onConfirm} - visible={visible} /> - <ConfirmAlert - visible={visibleTips} - onHide={handleTipsCancel} - onConfirm={handleTipsConfirm} - bgHide={false} - closeBtn={false} - showCancel={granted !== null} - cancelText={t('disagree')} - confirmText={t('agree')} - text={t(granted === null ? 'storage_permission_tip_disagree_ask_again' : 'storage_permission_tip_request')} /> - </> - ) -} diff --git a/src/components/common/ChoosePath/index.tsx b/src/components/common/ChoosePath/index.tsx new file mode 100644 index 000000000..6b710998d --- /dev/null +++ b/src/components/common/ChoosePath/index.tsx @@ -0,0 +1,83 @@ +import React, { useState, useRef, forwardRef, useImperativeHandle } from 'react' +// import { StyleSheet, View, Text, StatusBar, ScrollView } from 'react-native' + +// import { useGetter, useDispatch } from '@/store' +import List, { ListType } from './List' + +import ConfirmAlert, { ConfirmAlertType } from '@/components/common/ConfirmAlert' +import { checkStoragePermissions, requestStoragePermission, toast } from '@/utils/tools' +import { useI18n } from '@/lang' + +interface ReadOptions { + title: string + dirOnly?: boolean + filter?: RegExp +} +const initReadOptions = {} + +interface ChoosePathProps { + onConfirm: (path: string) => void +} + +export interface ChoosePathType { + show: (options: ReadOptions) => void +} + +export default forwardRef<ChoosePathType, ChoosePathProps>(({ + onConfirm = () => {}, +}: ChoosePathProps, ref) => { + const t = useI18n() + const listRef = useRef<ListType>(null) + const confirmAlertRef = useRef<ConfirmAlertType>(null) + const [deny, setDeny] = useState(false) + const readOptions = useRef<ReadOptions>(initReadOptions as ReadOptions) + + useImperativeHandle(ref, () => ({ + show(options) { + void checkStoragePermissions().then(isGranted => { + readOptions.current = options + if (isGranted) { + listRef.current?.show(options.title, options.dirOnly, options.filter) + } else { + confirmAlertRef.current?.setVisible(true) + } + }) + }, + })) + + const handleTipsCancel = () => { + toast(t('disagree_tip'), 'long') + } + const handleTipsConfirm = () => { + confirmAlertRef.current?.setVisible(false) + void requestStoragePermission().then(result => { + // console.log(result) + setDeny(result == null) + if (result) { + listRef.current?.show(readOptions.current.title, readOptions.current.dirOnly, readOptions.current.filter) + } else { + toast(t('storage_permission_tip_disagree'), 'long') + } + }) + } + const onPathConfirm = (path: string) => { + listRef.current?.hide() + onConfirm(path) + } + + return ( + <> + <List ref={listRef} onConfirm={onPathConfirm} /> + <ConfirmAlert + ref={confirmAlertRef} + onCancel={handleTipsCancel} + onConfirm={handleTipsConfirm} + bgHide={false} + closeBtn={false} + showConfirm={!deny} + cancelText={t('disagree')} + confirmText={t('agree')} + text={t(deny ? 'storage_permission_tip_disagree_ask_again' : 'storage_permission_tip_request')} /> + </> + ) +}) diff --git a/src/components/common/ConfirmAlert.js b/src/components/common/ConfirmAlert.js deleted file mode 100644 index 3ae078de3..000000000 --- a/src/components/common/ConfirmAlert.js +++ /dev/null @@ -1,102 +0,0 @@ -import React, { useMemo } from 'react' -import { StyleSheet, View, Text, ScrollView } from 'react-native' -import { useTranslation } from '@/plugins/i18n' -import Dialog from './Dialog' -import Button from './Button' -import { useGetter } from '@/store' - -const styles = StyleSheet.create({ - main: { - // flexGrow: 0, - flexShrink: 1, - marginTop: 15, - marginLeft: 5, - marginRight: 5, - marginBottom: 25, - }, - content: { - flexGrow: 0, - paddingLeft: 10, - paddingRight: 10, - }, - title: { - fontSize: 14, - }, - btns: { - flexDirection: 'row', - justifyContent: 'center', - paddingBottom: 15, - // paddingRight: 15, - }, - btnsDirection: { - paddingLeft: 15, - }, - btnsReversedDirection: { - paddingLeft: 15, - flexDirection: 'row-reverse', - }, - btn: { - flex: 1, - paddingTop: 10, - paddingBottom: 10, - paddingLeft: 10, - paddingRight: 10, - alignItems: 'center', - borderRadius: 4, - }, - btnDirection: { - marginRight: 15, - }, - btnReversedDirection: { - marginLeft: 15, - }, -}) - - -export default ({ - visible = false, - onHide = () => {}, - onCancel, - onConfirm = () => {}, - keyHide, - bgHide, - closeBtn, - title = '', - text = '', - cancelText = '', - confirmText = '', - showConfirm = true, - children, - reverseBtn = false, -}) => { - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - - const handleCancel = () => { - if (onCancel) { - onCancel() - } else { - onHide() - } - } - - return ( - <Dialog visible={visible} hideDialog={onHide} keyHide={keyHide} bgHide={bgHide} closeBtn={closeBtn} title={title}> - <View style={styles.main}> - <ScrollView style={styles.content} keyboardShouldPersistTaps={'always'}> - {children || <Text style={{ ...styles.title, color: theme.normal }}>{text}</Text>} - </ScrollView> - </View> - <View style={{ ...styles.btns, ...(reverseBtn ? styles.btnsReversedDirection : styles.btnsDirection) }}> - <Button style={{ ...styles.btn, ...(reverseBtn ? styles.btnReversedDirection : styles.btnDirection), backgroundColor: theme.secondary45 }} onPress={handleCancel}> - <Text style={{ color: theme.secondary_5 }}>{cancelText || t('cancel')}</Text> - </Button> - {showConfirm - ? <Button style={{ ...styles.btn, ...(reverseBtn ? styles.btnReversedDirection : styles.btnDirection), backgroundColor: theme.secondary45 }} onPress={onConfirm}> - <Text style={{ fontSize: 14, color: theme.secondary_5 }}>{confirmText || t('confirm')}</Text> - </Button> - : null} - </View> - </Dialog> - ) -} diff --git a/src/components/common/ConfirmAlert.tsx b/src/components/common/ConfirmAlert.tsx new file mode 100644 index 000000000..4a0fd20bb --- /dev/null +++ b/src/components/common/ConfirmAlert.tsx @@ -0,0 +1,124 @@ +import React, { forwardRef, useImperativeHandle, useRef } from 'react' +import { View, ScrollView } from 'react-native' +import Dialog, { type DialogType } from './Dialog' +import Button from './Button' +import { createStyle } from '@/utils/tools' +import { useI18n } from '@/lang/index' +import { useTheme } from '@/store/theme/hook' +import Text from './Text' + +const styles = createStyle({ + main: { + // flexGrow: 0, + flexShrink: 1, + marginTop: 15, + marginLeft: 5, + marginRight: 5, + marginBottom: 25, + }, + content: { + flexGrow: 0, + paddingLeft: 10, + paddingRight: 10, + }, + btns: { + flexDirection: 'row', + justifyContent: 'center', + paddingBottom: 15, + // paddingRight: 15, + }, + btnsDirection: { + paddingLeft: 15, + }, + btnsReversedDirection: { + paddingLeft: 15, + flexDirection: 'row-reverse', + }, + btn: { + flex: 1, + paddingTop: 9, + paddingBottom: 9, + paddingLeft: 10, + paddingRight: 10, + alignItems: 'center', + borderRadius: 4, + }, + btnDirection: { + marginRight: 15, + }, + btnReversedDirection: { + marginLeft: 15, + }, +}) + +export interface ConfirmAlertProps { + onCancel?: () => void + onHide?: () => void + onConfirm?: () => void + keyHide?: boolean + bgHide?: boolean + closeBtn?: boolean + title?: string + text?: string + cancelText?: string + confirmText?: string + showConfirm?: boolean + reverseBtn?: boolean + children?: React.ReactNode | React.ReactNode[] +} + +export interface ConfirmAlertType { + setVisible: (visible: boolean) => void +} + +export default forwardRef<ConfirmAlertType, ConfirmAlertProps>(({ + onHide, + onCancel, + onConfirm = () => {}, + keyHide, + bgHide, + closeBtn, + title = '', + text = '', + cancelText = '', + confirmText = '', + showConfirm = true, + children, + reverseBtn = false, +}: ConfirmAlertProps, ref) => { + const theme = useTheme() + const t = useI18n() + + const dialogRef = useRef<DialogType>(null) + + useImperativeHandle(ref, () => ({ + setVisible(visible: boolean) { + dialogRef.current?.setVisible(visible) + }, + })) + + const handleCancel = () => { + onCancel?.() + dialogRef.current?.setVisible(false) + } + + return ( + <Dialog onHide={onHide} keyHide={keyHide} bgHide={bgHide} closeBtn={closeBtn} title={title} ref={dialogRef}> + <View style={styles.main}> + <ScrollView style={styles.content} keyboardShouldPersistTaps={'always'}> + {children ?? <Text>{text}</Text>} + </ScrollView> + </View> + <View style={{ ...styles.btns, ...(reverseBtn ? styles.btnsReversedDirection : styles.btnsDirection) }}> + <Button style={{ ...styles.btn, ...(reverseBtn ? styles.btnReversedDirection : styles.btnDirection), backgroundColor: theme['c-button-background'] }} onPress={handleCancel}> + <Text color={theme['c-button-font']}>{cancelText || t('cancel')}</Text> + </Button> + {showConfirm + ? <Button style={{ ...styles.btn, ...(reverseBtn ? styles.btnReversedDirection : styles.btnDirection), backgroundColor: theme['c-button-background'] }} onPress={onConfirm}> + <Text color={theme['c-button-font']}>{confirmText || t('confirm')}</Text> + </Button> + : null} + </View> + </Dialog> + ) +}) diff --git a/src/components/common/Dialog.js b/src/components/common/Dialog.js deleted file mode 100644 index a84fb81ba..000000000 --- a/src/components/common/Dialog.js +++ /dev/null @@ -1,85 +0,0 @@ -import React, { useMemo } from 'react' -import { StyleSheet, View, Text, TouchableHighlight } from 'react-native' - -import Modal from './Modal' -import { Icon } from '@/components/common/Icon' -import { useGetter } from '@/store' -import { useKeyboard } from '@/utils/hooks' - -const styles = StyleSheet.create({ - centeredView: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - }, - modalView: { - maxWidth: '90%', - minWidth: '60%', - maxHeight: '78%', - // backgroundColor: 'white', - borderRadius: 4, - // shadowColor: '#000', - // shadowOffset: { - // width: 0, - // height: 2, - // }, - // shadowOpacity: 0.25, - // shadowRadius: 4, - elevation: 3, - }, - header: { - flexGrow: 0, - flexShrink: 0, - flexDirection: 'row', - borderTopLeftRadius: 4, - borderTopRightRadius: 4, - height: 20, - }, - title: { - fontSize: 13, - paddingLeft: 5, - paddingRight: 25, - lineHeight: 20, - }, - closeBtn: { - position: 'absolute', - right: 0, - borderTopRightRadius: 4, - flexGrow: 0, - flexShrink: 0, - height: 20, - width: 20, - justifyContent: 'center', - alignItems: 'center', - }, -}) - - -export default ({ - visible = false, - hideDialog = () => {}, - keyHide = true, - bgHide = true, - closeBtn = true, - title = '', - children, -}) => { - const theme = useGetter('common', 'theme') - const { keyboardShown, keyboardHeight } = useKeyboard() - - const closeBtnComponent = useMemo(() => closeBtn ? <TouchableHighlight style={styles.closeBtn} underlayColor={theme.secondary_5} onPress={hideDialog}><Icon name="close" style={{ color: theme.secondary40, fontSize: 10 }} /></TouchableHighlight> : null, [closeBtn, hideDialog, theme]) - - return ( - <Modal visible={visible} hideModal={hideDialog} keyHide={keyHide} bgHide={bgHide} bgColor="rgba(50,50,50,.3)"> - <View style={{ ...styles.centeredView, paddingBottom: keyboardShown ? keyboardHeight : 0 }}> - <View style={{ ...styles.modalView, backgroundColor: theme.primary }} onStartShouldSetResponder={() => true}> - <View style={{ ...styles.header, backgroundColor: theme.secondary }}> - <Text style={{ ...styles.title, color: theme.primary }} numberOfLines={1}>{title}</Text> - {closeBtnComponent} - </View> - {children} - </View> - </View> - </Modal> - ) -} diff --git a/src/components/common/Dialog.tsx b/src/components/common/Dialog.tsx new file mode 100644 index 000000000..c6dece8be --- /dev/null +++ b/src/components/common/Dialog.tsx @@ -0,0 +1,111 @@ +import React, { useImperativeHandle, forwardRef, useMemo, useRef } from 'react' +import { View, TouchableHighlight } from 'react-native' + +import Modal, { type ModalType } from './Modal' +import { Icon } from '@/components/common/Icon' +import { useKeyboard } from '@/utils/hooks' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import Text from './Text' +import { scaleSizeH } from '@/utils/pixelRatio' + +const HEADER_HEIGHT = 20 +const styles = createStyle({ + centeredView: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + modalView: { + maxWidth: '90%', + minWidth: '60%', + maxHeight: '78%', + // backgroundColor: 'white', + borderRadius: 4, + // shadowColor: '#000', + // shadowOffset: { + // width: 0, + // height: 2, + // }, + // shadowOpacity: 0.25, + // shadowRadius: 4, + elevation: 3, + }, + header: { + flexGrow: 0, + flexShrink: 0, + flexDirection: 'row', + borderTopLeftRadius: 4, + borderTopRightRadius: 4, + height: HEADER_HEIGHT, + }, + title: { + paddingLeft: 5, + paddingRight: 25, + lineHeight: HEADER_HEIGHT, + }, + closeBtn: { + position: 'absolute', + right: 0, + borderTopRightRadius: 4, + flexGrow: 0, + flexShrink: 0, + height: HEADER_HEIGHT, + justifyContent: 'center', + alignItems: 'center', + }, +}) + +export interface DialogProps { + onHide?: () => void + keyHide?: boolean + bgHide?: boolean + closeBtn?: boolean + title?: string + children: React.ReactNode | React.ReactNode[] +} + +export interface DialogType { + setVisible: (visible: boolean) => void +} + +export default forwardRef<DialogType, DialogProps>(({ + onHide, + keyHide = true, + bgHide = true, + closeBtn = true, + title = '', + children, +}: DialogProps, ref) => { + const theme = useTheme() + const { keyboardShown, keyboardHeight } = useKeyboard() + const modalRef = useRef<ModalType>(null) + + useImperativeHandle(ref, () => ({ + setVisible(visible: boolean) { + modalRef.current?.setVisible(visible) + }, + })) + + const closeBtnComponent = useMemo(() => { + return closeBtn + ? <TouchableHighlight style={{ ...styles.closeBtn, width: scaleSizeH(HEADER_HEIGHT) }} underlayColor={theme['c-primary-dark-200-alpha-600']} onPress={() => modalRef.current?.setVisible(false)}> + <Icon name="close" color={theme['c-primary-dark-500-alpha-500']} size={10} /> + </TouchableHighlight> + : null + }, [closeBtn, theme]) + + return ( + <Modal onHide={onHide} keyHide={keyHide} bgHide={bgHide} bgColor="rgba(50,50,50,.3)" ref={modalRef}> + <View style={{ ...styles.centeredView, paddingBottom: keyboardShown ? keyboardHeight : 0 }}> + <View style={{ ...styles.modalView, backgroundColor: theme['c-content-background'] }} onStartShouldSetResponder={() => true}> + <View style={{ ...styles.header, backgroundColor: theme['c-primary-light-100-alpha-100'] }}> + <Text style={styles.title} size={13} color={theme['c-primary-light-1000']} numberOfLines={1}>{title}</Text> + {closeBtnComponent} + </View> + {children} + </View> + </View> + </Modal> + ) +}) diff --git a/src/components/common/DorpDownMenu.js b/src/components/common/DorpDownMenu.js deleted file mode 100644 index 29e85d541..000000000 --- a/src/components/common/DorpDownMenu.js +++ /dev/null @@ -1,56 +0,0 @@ -import React, { useState, useCallback, useRef } from 'react' -// import { View } from 'react-native' - -import Menu from './Menu' -import Button from './Button' - - -export default ({ - children, - menus = [], - onPress, - longPress, - width, - height, - center, -}) => { - const [visible, setVisible] = useState(false) - const [buttonPosition, setButtonPosition] = useState({}) - - const hideMenu = useCallback(() => { - setVisible(false) - }, [setVisible]) - - const buttonRef = useRef() - const setPosition = useCallback((callback = () => {}) => { - if (buttonRef.current && buttonRef.current.measure) { - buttonRef.current.measure((fx, fy, width, height, px, py) => { - // console.log(fx, fy, width, height, px, py) - setButtonPosition({ x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }) - callback() - }) - } - }, []) - - const showMenu = useCallback(() => { - setPosition(() => { - setVisible(true) - }) - }, [setPosition, setVisible]) - - return ( - <Button ref={buttonRef} onPress={showMenu}> - {children} - <Menu menus={menus} - buttonPosition={buttonPosition} - center={center} - onPress={onPress} - longPress={longPress} - visible={visible} - hideMenu={hideMenu} - width={width} - height={height} - /> - </Button> - ) -} diff --git a/src/components/common/DorpDownMenu.tsx b/src/components/common/DorpDownMenu.tsx new file mode 100644 index 000000000..0a5dd33ca --- /dev/null +++ b/src/components/common/DorpDownMenu.tsx @@ -0,0 +1,48 @@ +import React, { useRef } from 'react' +// import { View } from 'react-native' + +import Menu, { type MenuType, type MenuProps, type Menus } from './Menu' +import Button, { type BtnType } from './Button' +// import { useLayout } from '@/utils/hooks' + +export interface DorpDownMenuProps<T extends Menus> extends Omit<MenuProps<T>, 'width'> { + children: React.ReactNode +} + +export default <T extends Menus>({ + menus, + onPress, + height, + fontSize, + center, + children, + activeId, +}: DorpDownMenuProps<T>) => { + const buttonRef = useRef<BtnType>(null) + const menuRef = useRef<MenuType>(null) + + const showMenu = () => { + buttonRef.current?.measure((fx, fy, width, height, px, py) => { + // console.log(fx, fy, width, height, px, py) + menuRef.current?.show({ x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }, { + width, + height, + }) + }) + } + + return ( + <Button ref={buttonRef} onPress={showMenu}> + {children} + <Menu + ref={menuRef} + menus={menus} + center={center} + onPress={onPress} + fontSize={fontSize} + height={height} + activeId={activeId} + /> + </Button> + ) +} diff --git a/src/components/common/DorpDownPanel/Panel.js b/src/components/common/DorpDownPanel/Panel.tsx similarity index 54% rename from src/components/common/DorpDownPanel/Panel.js rename to src/components/common/DorpDownPanel/Panel.tsx index 895d4da7f..995c5eb6f 100644 --- a/src/components/common/DorpDownPanel/Panel.js +++ b/src/components/common/DorpDownPanel/Panel.tsx @@ -1,14 +1,16 @@ -import React, { useMemo, useCallback, memo } from 'react' -import { StyleSheet, View, Text, ScrollView, TouchableHighlight, TouchableWithoutFeedback } from 'react-native' +import React, { useMemo, useRef, useImperativeHandle, forwardRef, useState } from 'react' +import { View, TouchableWithoutFeedback } from 'react-native' import { useDimensions } from '@/utils/hooks' -import Modal from '@/components/common/Modal' +import Modal, { ModalType } from '@/components/common/Modal' +import { createStyle } from '@/utils/tools' // import { useGetter } from '@/store' // const menuItemHeight = 42 // const menuItemWidth = 100 +interface Position { w: number, h: number, x: number, y: number } -const styles = StyleSheet.create({ +const styles = createStyle({ menu: { position: 'absolute', // borderWidth: StyleSheet.hairlineWidth, @@ -32,9 +34,13 @@ const styles = StyleSheet.create({ const Panel = ({ buttonPosition, - panelStyle = {}, - hidePanel, + // panelStyle = {}, + onHide, children, +}: { + buttonPosition: Position + onHide: () => void + children: React.ReactNode | React.ReactNode[] }) => { // const dimensions = useDimensions() const { window: windowSize } = useDimensions() @@ -45,9 +51,9 @@ const Panel = ({ // console.log(dimensions) const style = useMemo(() => { const isBottom = buttonPosition.y > windowSize.height / 2 - let top - let height - let justifyContent + let top: number + let height: number + let justifyContent: 'flex-end' | 'flex-start' if (isBottom) { const buttonPositionY = Math.ceil(buttonPosition.y) height = buttonPositionY - windowSize.height * 0.3 @@ -69,7 +75,7 @@ const Panel = ({ }, [windowSize, buttonPosition]) return ( - <TouchableWithoutFeedback onPress={hidePanel}> + <TouchableWithoutFeedback onPress={onHide}> <View style={{ ...styles.menu, ...style }}> <View onStartShouldSetResponder={() => true}> {children} @@ -78,12 +84,39 @@ const Panel = ({ </TouchableWithoutFeedback> ) } +export interface PanelProps { + onHide?: () => void + keyHide?: boolean + bgHide?: boolean + closeBtn?: boolean + title?: string + children: React.ReactNode | React.ReactNode[] + // style: +} + +export interface PanelType { + show: (position: Position) => void + hide: () => void +} + +export default forwardRef<PanelType, PanelProps>(({ onHide, keyHide, bgHide, children }, ref) => { + const modalRef = useRef<ModalType>(null) + const [position, setPosition] = useState<Position>({ w: 0, h: 0, x: 0, y: 0 }) + + useImperativeHandle(ref, () => ({ + show(newPosition) { + setPosition(newPosition) + modalRef.current?.setVisible(true) + }, + hide() { + modalRef.current?.setVisible(false) + }, + })) -export default memo(({ visible, hidePanel, buttonPosition, children, panelStyle }) => { // console.log(visible) return ( - <Modal visible={visible} hideModal={hidePanel} onStartShouldSetResponder={() => true}> - <Panel buttonPosition={buttonPosition} panelStyle={panelStyle} visible={visible} hidePanel={hidePanel}> + <Modal ref={modalRef} onHide={onHide} onStartShouldSetResponder={() => true} keyHide={keyHide} bgHide={bgHide}> + <Panel buttonPosition={position} onHide={() => modalRef.current?.setVisible(false)}> {children} </Panel> </Modal> diff --git a/src/components/common/DorpDownPanel/index.js b/src/components/common/DorpDownPanel/index.js deleted file mode 100644 index b9f38d767..000000000 --- a/src/components/common/DorpDownPanel/index.js +++ /dev/null @@ -1,51 +0,0 @@ -import React, { useState, useCallback, useRef } from 'react' -// import { View } from 'react-native' - -import Panel from './Panel' -import Button from '@/components/common/Button' - - -export default ({ - children, - panelStyle, - PanelContent, - visible, - setVisible, -}) => { - const [buttonPosition, setButtonPosition] = useState({}) - - const hidePanel = useCallback(() => { - setVisible(false) - }, [setVisible]) - - const buttonRef = useRef() - const setPosition = useCallback((callback = () => {}) => { - if (buttonRef.current && buttonRef.current.measure) { - buttonRef.current.measure((fx, fy, width, height, px, py) => { - // console.log(fx, fy, width, height, px, py) - setButtonPosition({ x: px, y: py, w: width, h: height }) - callback() - }) - } - }, []) - - const showMenu = useCallback(() => { - setPosition(() => { - setVisible(true) - }) - }, [setPosition, setVisible]) - - return ( - <Button ref={buttonRef} onPress={showMenu}> - {children} - <Panel - buttonPosition={buttonPosition} - visible={visible} - panelStyle={panelStyle} - hidePanel={hidePanel} - > - {PanelContent} - </Panel> - </Button> - ) -} diff --git a/src/components/common/DorpDownPanel/index.tsx b/src/components/common/DorpDownPanel/index.tsx new file mode 100644 index 000000000..9f038148c --- /dev/null +++ b/src/components/common/DorpDownPanel/index.tsx @@ -0,0 +1,40 @@ +import React, { useRef, forwardRef } from 'react' +// import { View } from 'react-native' + +import Panel, { PanelType } from './Panel' +import Button, { BtnType } from '@/components/common/Button' + + +export interface DorpDownPanelProps { + onHide?: () => void + children: React.ReactNode | React.ReactNode[] + PanelContent: React.ReactNode | React.ReactNode[] +} +export interface DorpDownPanelType { + hide: () => void +} + +export default forwardRef<DorpDownPanelType, DorpDownPanelProps>(({ + children, + PanelContent, + onHide, +}) => { + const buttonRef = useRef<BtnType>(null) + const panelRef = useRef<PanelType>(null) + + const showMenu = () => { + buttonRef.current?.measure((fx, fy, width, height, px, py) => { + // console.log(fx, fy, width, height, px, py) + panelRef.current?.show({ x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }) + }) + } + + return ( + <Button ref={buttonRef} onPress={showMenu}> + {children} + <Panel ref={panelRef} onHide={onHide}> + {PanelContent} + </Panel> + </Button> + ) +}) diff --git a/src/components/common/DrawerLayoutFixed.tsx b/src/components/common/DrawerLayoutFixed.tsx new file mode 100644 index 000000000..26aecaf04 --- /dev/null +++ b/src/components/common/DrawerLayoutFixed.tsx @@ -0,0 +1,73 @@ +import React, { forwardRef, useCallback, useRef, useState } from 'react' +import { DrawerLayoutAndroid, type DrawerLayoutAndroidProps, View, type LayoutChangeEvent } from 'react-native' +// import { getWindowSise } from '@/utils/tools' +import { usePageVisible } from '@/store/common/hook' +import { type COMPONENT_IDS } from '@/config/constant' + +interface Props extends DrawerLayoutAndroidProps { + visibleNavNames: COMPONENT_IDS[] + widthPercentage: number + widthPercentageMax?: number +} + +const DrawerLayoutFixed = forwardRef<DrawerLayoutAndroid, Props>(({ visibleNavNames, widthPercentage, widthPercentageMax, children, ...props }, ref) => { + const [w, setW] = useState<number | string>('100%') + const [drawerWidth, setDrawerWidth] = useState(0) + const changedRef = useRef({ width: 0, changed: false }) + + // 修复 DrawerLayoutAndroid 在导航到其他屏幕再返回后无法打开的问题 + usePageVisible(visibleNavNames, useCallback((visible) => { + if (!visible || !changedRef.current.width) return + changedRef.current.changed = true + // console.log('usePageVisible', visible, changedRef.current.width) + setW(changedRef.current.width - 1) + }, [])) + + const handleLayout = useCallback((e: LayoutChangeEvent) => { + // console.log('handleLayout', e.nativeEvent.layout.width, changedRef.current.width) + if (changedRef.current.changed) { + // setW(e.nativeEvent.layout.width - 1) + setW('100%') + changedRef.current.changed = false + } else { + const width = e.nativeEvent.layout.width + if (changedRef.current.width == width) return + changedRef.current.width = width + + // 重新设置面板宽度 + const wp = Math.floor(width * widthPercentage) + // console.log(wp, widthPercentageMax) + setDrawerWidth(widthPercentageMax ? Math.min(wp, widthPercentageMax) : wp) + + // 强制触发渲染以应用更改 + changedRef.current.changed = true + setW(width - 1) + } + }, [widthPercentage, widthPercentageMax]) + + return ( + <View + onLayout={handleLayout} + style={{ width: w, flex: 1 }} + > + <DrawerLayoutAndroid + ref={ref} + keyboardDismissMode="on-drag" + drawerWidth={drawerWidth} + {...props} + > + <View style={{ marginRight: w == '100%' ? 0 : -1, flex: 1 }}> + {children} + </View> + </DrawerLayoutAndroid> + </View> + ) +}) + +// const styles = createStyle({ +// container: { +// flex: 1, +// }, +// }) + +export default DrawerLayoutFixed diff --git a/src/components/common/Icon.js b/src/components/common/Icon.tsx similarity index 76% rename from src/components/common/Icon.js rename to src/components/common/Icon.tsx index fcac532fa..2f399d08d 100644 --- a/src/components/common/Icon.js +++ b/src/components/common/Icon.tsx @@ -1,5 +1,8 @@ import { createIconSetFromIcoMoon } from 'react-native-vector-icons' import icoMoonConfig from '@/resources/fonts/selection.json' +import { scaleSizeW } from '@/utils/pixelRatio' +import { ComponentProps } from 'react' +import { useTheme } from '@/store/theme/hook' // import IconAntDesign from 'react-native-vector-icons/AntDesign' // import IconEntypo from 'react-native-vector-icons/Entypo' @@ -17,13 +20,19 @@ import icoMoonConfig from '@/resources/fonts/selection.json' // import IconSimpleLineIcons from 'react-native-vector-icons/SimpleLineIcons' -const Icon = createIconSetFromIcoMoon(icoMoonConfig) +const IcoMoon = createIconSetFromIcoMoon(icoMoonConfig) + // https://oblador.github.io/react-native-vector-icons/ -export { - Icon, +type IconType = ReturnType<typeof createIconSetFromIcoMoon> +export const Icon = ({ size = 15, color, ...props }: ComponentProps<IconType>) => { + const theme = useTheme() + return <IcoMoon size={scaleSizeW(size)} color={color ?? theme['c-font']} {...props} /> +} + +export { // IconAntDesign, // IconEntypo, // IconEvilIcons, diff --git a/src/components/common/Input.js b/src/components/common/Input.tsx similarity index 60% rename from src/components/common/Input.js rename to src/components/common/Input.tsx index 60f5ad9f0..5ef6ec9f1 100644 --- a/src/components/common/Input.js +++ b/src/components/common/Input.tsx @@ -1,27 +1,78 @@ import React, { useRef, useImperativeHandle, forwardRef, useCallback } from 'react' -import { TextInput, StyleSheet, View, TouchableOpacity } from 'react-native' +import { TextInput, View, TouchableOpacity, StyleSheet, TextInputProps } from 'react-native' import { Icon } from '@/components/common/Icon' -import { useGetter } from '@/store' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' -const Input = ({ onChangeText, onClearText, clearBtn, style, ...props }, ref) => { - const inputRef = useRef() - const theme = useGetter('common', 'theme') +const styles = createStyle({ + content: { + flexDirection: 'row', + // backgroundColor: 'rgba(0,0,0,0.1)', + flexGrow: 1, + flexShrink: 1, + // height: 38, + alignItems: 'center', + // paddingRight: 5, + }, + input: { + // backgroundColor: 'rgba(0,0,0,0.1)', + // backgroundColor: 'white', + borderRadius: 2, + paddingTop: 0, + paddingBottom: 0, + height: 32, + paddingLeft: 5, + paddingRight: 0, + flexGrow: 1, + flexShrink: 1, + // height: '100%', + // width: '100%', + fontSize: 14, + }, + clearBtnContent: { + flexGrow: 0, + flexShrink: 0, + }, + clearBtn: { + height: '70%', + paddingLeft: 5, + paddingRight: 5, + justifyContent: 'center', + // backgroundColor: 'rgba(0,0,0,0.2)', + }, +}) + +export interface InputProps extends TextInputProps { + onChangeText?: (value: string) => void + onClearText?: () => void + clearBtn?: boolean +} + + +export interface InputType { + blur: () => void + focus: () => void + clear: () => void + isFocused: () => boolean +} + +export default forwardRef<InputType, InputProps>(({ onChangeText, onClearText, clearBtn, style, ...props }, ref) => { + const inputRef = useRef<TextInput>(null) + const theme = useTheme() // const scaleClearBtn = useRef(new Animated.Value(0)).current useImperativeHandle(ref, () => ({ blur() { - if (!inputRef.current) return - inputRef.current.blur() + inputRef.current?.blur() }, focus() { - if (!inputRef.current) return - inputRef.current.focus() + inputRef.current?.focus() }, clear() { - inputRef.current.clear() + inputRef.current?.clear() }, isFocused() { - return inputRef.current.isFocused() + return inputRef.current?.isFocused() ?? false }, })) @@ -41,19 +92,19 @@ const Input = ({ onChangeText, onClearText, clearBtn, style, ...props }, ref) => // }, [scaleClearBtn]) const clearText = useCallback(() => { - inputRef.current.clear() + inputRef.current?.clear() // hideClearBtn() - onChangeText && onChangeText('') - onClearText && onClearText() + onChangeText?.('') + onClearText?.() }, [onChangeText, onClearText]) - const changeText = useCallback(text => { + const changeText = useCallback((text: string) => { // if (text.length) { // showClearBtn() // } else { // hideClearBtn() // } - onChangeText && onChangeText(text) + onChangeText?.(text) }, [onChangeText]) return ( @@ -61,17 +112,17 @@ const Input = ({ onChangeText, onClearText, clearBtn, style, ...props }, ref) => <TextInput autoCapitalize="none" onChangeText={changeText} - autoCompleteType="off" - style={{ ...styles.input, color: theme.normal, ...style }} - placeholderTextColor={theme.normal50} - selectionColor={theme.secondary10} + autoComplete="off" + style={StyleSheet.compose({ ...styles.input, color: theme['c-font'] }, style)} + placeholderTextColor={theme['c-primary-dark-100-alpha-600']} + selectionColor={theme['c-primary-light-100-alpha-300']} ref={inputRef} {...props} /> {/* <View style={styles.clearBtnContent}> <Animated.View style={{ ...styles.clearBtnContent, transform: [{ scale: scaleClearBtn }] }}> */} {clearBtn ? <View style={styles.clearBtnContent}> <TouchableOpacity style={styles.clearBtn} onPress={clearText}> - <Icon name="remove" style={{ fontSize: 14, color: theme.normal50 }} /> + <Icon name="remove" color={theme['c-primary-dark-100-alpha-500']} size={11} /> </TouchableOpacity> </View> : null @@ -80,42 +131,5 @@ const Input = ({ onChangeText, onClearText, clearBtn, style, ...props }, ref) => </View> */} </View> ) -} - -const styles = StyleSheet.create({ - content: { - flexDirection: 'row', - // backgroundColor: 'rgba(0,0,0,0.1)', - flexGrow: 1, - flexShrink: 1, - // height: 38, - alignItems: 'center', - // paddingRight: 5, - }, - input: { - // backgroundColor: 'rgba(0,0,0,0.1)', - // backgroundColor: 'white', - borderRadius: 2, - paddingTop: 2, - paddingBottom: 2, - paddingLeft: 5, - paddingRight: 0, - flexGrow: 1, - flexShrink: 1, - height: '100%', - }, - clearBtnContent: { - flexGrow: 0, - flexShrink: 0, - }, - clearBtn: { - height: '70%', - paddingLeft: 5, - paddingRight: 5, - justifyContent: 'center', - // backgroundColor: 'rgba(0,0,0,0.2)', - }, }) -export default forwardRef(Input) - diff --git a/src/components/common/LoadingMask.js b/src/components/common/LoadingMask.tsx similarity index 59% rename from src/components/common/LoadingMask.js rename to src/components/common/LoadingMask.tsx index 642a469f5..14e258411 100644 --- a/src/components/common/LoadingMask.js +++ b/src/components/common/LoadingMask.tsx @@ -1,13 +1,29 @@ -import React, { useState, useCallback, memo, useMemo, useRef, useEffect } from 'react' -import { StyleSheet, Animated, Text } from 'react-native' -import { useGetter } from '@/store' -import { useTranslation } from '@/plugins/i18n' +import React, { useState, useCallback, useMemo, useRef, forwardRef, useImperativeHandle } from 'react' +import { Animated } from 'react-native' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import Text from './Text' -export default memo(({ visible }) => { - const theme = useGetter('common', 'theme') +// interface LoadingMaskProps { + +// } + +export interface LoadingMaskType { + setVisible: (visible: boolean) => void +} + +export default forwardRef<LoadingMaskType, {}>((props, ref) => { + const theme = useTheme() + const t = useI18n() const animFade = useRef(new Animated.Value(0)).current const [maskVisible, setMaskVisible] = useState(false) - const { t } = useTranslation() + + useImperativeHandle(ref, () => ({ + setVisible(visible: boolean) { + visible ? handleShow() : handleHide() + }, + })) const handleShow = useCallback(() => { // console.log('handleShow') @@ -38,21 +54,17 @@ export default memo(({ visible }) => { }) }, [animFade]) - useEffect(() => { - if (visible === maskVisible) return - visible ? handleShow() : handleHide() - }, [handleHide, handleShow, maskVisible, visible]) const maskComponent = useMemo(() => ( - <Animated.View style={{ ...styles.container, backgroundColor: theme.primary, opacity: animFade }}> - <Text style={{ ...styles.text, color: theme.normal40 }}>{t('list_loading')}</Text> + <Animated.View style={{ ...styles.container, backgroundColor: theme['c-main-background'], opacity: animFade }}> + <Text size={20} color={theme['c-font-label']}>{t('list_loading')}</Text> </Animated.View> ), [animFade, t, theme]) return maskVisible ? maskComponent : null }) -const styles = StyleSheet.create({ +const styles = createStyle({ container: { position: 'absolute', left: 0, @@ -63,7 +75,4 @@ const styles = StyleSheet.create({ justifyContent: 'center', alignItems: 'center', }, - text: { - fontSize: 20, - }, }) diff --git a/src/components/common/Menu.js b/src/components/common/Menu.js deleted file mode 100644 index 9a49e22ea..000000000 --- a/src/components/common/Menu.js +++ /dev/null @@ -1,136 +0,0 @@ -import React, { useMemo, useCallback, memo } from 'react' -import { StyleSheet, View, Text, Animated, TouchableHighlight } from 'react-native' -import { useDimensions } from '@/utils/hooks' - -import Modal from './Modal' -import { useGetter } from '@/store' - -// const menuItemHeight = 42 -// const menuItemWidth = 100 - -const styles = StyleSheet.create({ - mask: { - position: 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - opacity: 0, - backgroundColor: 'black', - }, - menu: { - position: 'absolute', - // borderWidth: StyleSheet.hairlineWidth, - borderColor: 'lightgray', - borderRadius: 2, - backgroundColor: 'white', - elevation: 3, - }, - menuItem: { - paddingLeft: 10, - paddingRight: 10, - // height: menuItemHeight, - // width: menuItemWidth, - // alignItems: 'center', - justifyContent: 'center', - // backgroundColor: '#ccc', - }, - menuText: { - // textAlign: 'center', - }, -}) - -const Menu = ({ - buttonPosition, - menus, - onPress = () => {}, - longPress = () => {}, - center = false, - hideMenu, - width = 100, - height = 42, -}) => { - const theme = useGetter('common', 'theme') - const { window: windowSize } = useDimensions() - // const fadeAnim = useRef(new Animated.Value(0)).current - // console.log(buttonPosition) - - const menuStyle = useMemo(() => { - let menuHeight = menus.length * height + 1 - const topHeight = buttonPosition.y - 20 - const bottomHeight = windowSize.height - buttonPosition.y - buttonPosition.h - 20 - if (menuHeight > topHeight && menuHeight > bottomHeight) menuHeight = Math.max(topHeight, bottomHeight) - - const menuWidth = width - const bottomSpace = windowSize.height - buttonPosition.y - buttonPosition.h - 20 - const rightSpace = windowSize.width - buttonPosition.x - menuWidth - 20 - const showInBottom = bottomSpace >= menuHeight - const showInRight = rightSpace >= menuWidth - const frameStyle = { - height: menuHeight, - top: showInBottom ? buttonPosition.y + buttonPosition.h : buttonPosition.y - menuHeight, - } - if (showInRight) { - frameStyle.left = buttonPosition.x - } else { - frameStyle.right = windowSize.width - buttonPosition.x - buttonPosition.w - } - return frameStyle - }, [windowSize, buttonPosition, menus, width, height]) - - const menuPress = useCallback((menu, index) => { - // if (menu.disabled) return - onPress(menu, index) - hideMenu() - }, [onPress, hideMenu]) - - const menuLongPress = useCallback((menu, index) => { - // if (menu.disabled) return - longPress(menu, index) - // hideMenu() - }, [longPress]) - - // console.log(menuStyle) - return ( - <View style={{ ...styles.menu, ...menuStyle, backgroundColor: theme.primary }} onStartShouldSetResponder={() => true}> - <Animated.ScrollView keyboardShouldPersistTaps={'always'}> - { - menus.map((menu, index) => ( - menu.disabled - ? ( - <View - key={menu.action} - style={{ ...styles.menuItem, width: width, height: height, opacity: 0.4 }} - underlayColor={theme.secondary40} - > - <Text style={{ ...styles.menuText, textAlign: center ? 'center' : 'left', color: theme.normal }} numberOfLines={1}>{menu.label}</Text> - </View> - ) - : ( - <TouchableHighlight - key={menu.action} - style={{ ...styles.menuItem, width: width, height: height }} - underlayColor={theme.secondary40} - onPress={() => { menuPress(menu, index) }} - onLongPress={() => { menuLongPress(menu, index) }} - > - <Text style={{ ...styles.menuText, textAlign: center ? 'center' : 'left', color: theme.normal }} numberOfLines={1}>{menu.label}</Text> - </TouchableHighlight> - ) - - )) - } - </Animated.ScrollView> - </View> - ) -} - -export default memo(({ visible, hideMenu, buttonPosition, menus, longPress, onPress, width, height }) => { - // console.log(visible) - return ( - <Modal visible={visible} hideModal={hideMenu} onStartShouldSetResponder={() => true}> - <Menu menus={menus} buttonPosition={buttonPosition} longPress={longPress} onPress={onPress} visible={visible} hideMenu={hideMenu} width={width} height={height} /> - </Modal> - ) -}) - diff --git a/src/components/common/Menu.tsx b/src/components/common/Menu.tsx new file mode 100644 index 000000000..133811558 --- /dev/null +++ b/src/components/common/Menu.tsx @@ -0,0 +1,211 @@ +import React, { useImperativeHandle, forwardRef, useMemo, useRef, useState, type Ref } from 'react' +import { View, Animated, TouchableHighlight } from 'react-native' +import { useDimensions } from '@/utils/hooks' + +import Modal, { type ModalType } from './Modal' + +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import Text from './Text' +import { scaleSizeH, scaleSizeW } from '@/utils/pixelRatio' + +const menuItemHeight = scaleSizeH(38) +const menuItemWidth = scaleSizeW(100) + +export interface Position { w: number, h: number, x: number, y: number, menuWidth?: number, menuHeight?: number } +export interface MenuSize { width?: number, height?: number } +export type Menus = Readonly<Array<{ action: string, label: string, disabled?: boolean }>> + +const styles = createStyle({ + mask: { + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + opacity: 0, + backgroundColor: 'black', + }, + menu: { + position: 'absolute', + // borderWidth: StyleSheet.hairlineWidth, + borderColor: 'lightgray', + borderRadius: 2, + backgroundColor: 'white', + elevation: 3, + }, + menuItem: { + paddingLeft: 10, + paddingRight: 10, + // height: menuItemHeight, + // width: menuItemWidth, + // alignItems: 'center', + justifyContent: 'center', + // backgroundColor: '#ccc', + }, + // menuText: { + // // textAlign: 'center', + // fontSize: 14, + // }, +}) + +interface Props<M extends Menus = Menus> { + menus: Readonly<M> + onPress?: (menu: M[number]) => void + buttonPosition: Position + menuSize: MenuSize + onHide: () => void + width?: number + height?: number + fontSize?: number + center?: boolean + activeId?: M[number]['action'] | null +} + +const Menu = ({ + buttonPosition, + menuSize, + menus, + onPress = () => {}, + onHide, + activeId, + fontSize = 15, + center = false, +}: Props) => { + const theme = useTheme() + const { window: windowSize } = useDimensions() + // const fadeAnim = useRef(new Animated.Value(0)).current + // console.log(buttonPosition) + + const menuItemStyle = useMemo(() => { + return { + width: menuSize.width ?? menuItemWidth, + height: menuSize.height ?? menuItemHeight, + } + }, [menuSize]) + + const menuStyle = useMemo(() => { + let menuHeight = menus.length * menuItemStyle.height + const topHeight = buttonPosition.y - 20 + const bottomHeight = windowSize.height - buttonPosition.y - buttonPosition.h - 20 + if (menuHeight > topHeight && menuHeight > bottomHeight) menuHeight = Math.max(topHeight, bottomHeight) + + const menuWidth = menuItemStyle.width + const bottomSpace = windowSize.height - buttonPosition.y - buttonPosition.h - 20 + const rightSpace = windowSize.width - buttonPosition.x - menuWidth + const showInBottom = bottomSpace >= menuHeight + const showInRight = rightSpace >= menuWidth + const frameStyle: { + height: number + width: number + top: number + left?: number + right?: number + } = { + height: menuHeight, + top: showInBottom ? buttonPosition.y + buttonPosition.h : buttonPosition.y - menuHeight, + width: menuWidth, + } + if (showInRight) { + frameStyle.left = buttonPosition.x + } else { + frameStyle.right = windowSize.width - buttonPosition.x - buttonPosition.w + } + return frameStyle + }, [menus.length, menuItemStyle, buttonPosition, windowSize]) + + const menuPress = (menu: Menus[number]) => { + // if (menu.disabled) return + onPress(menu) + onHide() + } + + // console.log('render menu') + // console.log(activeId) + // console.log(menuStyle) + // console.log(menuItemStyle) + return ( + <View style={{ ...styles.menu, ...menuStyle, backgroundColor: theme['c-content-background'] }} onStartShouldSetResponder={() => true}> + <Animated.ScrollView keyboardShouldPersistTaps={'always'}> + { + menus.map((menu, index) => ( + menu.disabled + ? ( + <View + key={menu.action} + style={{ ...styles.menuItem, width: menuItemStyle.width, height: menuItemStyle.height, opacity: 0.4 }} + > + <Text style={{ textAlign: center ? 'center' : 'left' }} size={fontSize} numberOfLines={1}>{menu.label}</Text> + </View> + ) + : menu.action == activeId + ? ( + <View + key={menu.action} + style={{ ...styles.menuItem, width: menuItemStyle.width, height: menuItemStyle.height }} + > + <Text style={{ textAlign: center ? 'center' : 'left' }} color={theme['c-primary-font-active']} size={fontSize} numberOfLines={1}>{menu.label}</Text> + </View> + ) + : ( + <TouchableHighlight + key={menu.action} + style={{ ...styles.menuItem, width: menuItemStyle.width, height: menuItemStyle.height }} + underlayColor={theme['c-primary-background-active']} + onPress={() => { menuPress(menu) }} + > + <Text style={{ textAlign: center ? 'center' : 'left' }} size={fontSize} numberOfLines={1}>{menu.label}</Text> + </TouchableHighlight> + ) + + )) + } + </Animated.ScrollView> + </View> + ) +} + +export interface MenuProps<M extends Menus = Menus> { + menus: M + onPress: (menu: M[number]) => void + onHide?: () => void + width?: number + height?: number + fontSize?: number + center?: boolean + activeId?: M[number]['action'] | null +} + +export interface MenuType { + show: (position: Position, menuSize?: MenuSize) => void + hide: () => void +} + +const Component = <M extends Menus>({ menus, activeId, onHide, onPress, fontSize, center }: MenuProps<M>, ref: Ref<MenuType>) => { + // console.log(visible) + const modalRef = useRef<ModalType>(null) + const [position, setPosition] = useState<Position>({ w: 0, h: 0, x: 0, y: 0 }) + const [menuSize, setMenuSize] = useState<MenuSize>({ }) + const hide = () => { + modalRef.current?.setVisible(false) + } + useImperativeHandle(ref, () => ({ + show(newPosition, menuSize) { + setPosition(newPosition) + if (menuSize) setMenuSize(menuSize) + modalRef.current?.setVisible(true) + }, + hide() { + hide() + }, + })) + + return ( + <Modal onHide={onHide} ref={modalRef}> + <Menu menus={menus} activeId={activeId} buttonPosition={position} menuSize={menuSize} onPress={onPress} onHide={hide} fontSize={fontSize} center={center} /> + </Modal> + ) +} + +// export default forwardRef(Component) as ForwardRefFn<MenuType> +export default forwardRef(Component) as <M extends Menus>(p: MenuProps<M> & { ref?: Ref<MenuType> }) => JSX.Element | null diff --git a/src/components/common/Modal.js b/src/components/common/Modal.js deleted file mode 100644 index e97315381..000000000 --- a/src/components/common/Modal.js +++ /dev/null @@ -1,48 +0,0 @@ -import React, { memo, useCallback } from 'react' -import { Modal, TouchableWithoutFeedback, StyleSheet, View } from 'react-native' -// import { useDimensions } from '@/utils/hooks' - -const styles = StyleSheet.create({ - mask: { - position: 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - }, -}) - -export default memo(({ - visible = false, - hideModal = () => {}, - keyHide = true, - bgHide = true, - bgColor = 'rgba(0,0,0,0)', - children, -}) => { - // const { window: windowSize } = useDimensions() - const handleRequestClose = useCallback(() => { - if (keyHide) hideModal(false) - }, [hideModal, keyHide]) - const handleBgClose = useCallback(() => { - if (bgHide) hideModal(false) - }, [hideModal, bgHide]) - - return ( - <Modal - animationType="fade" - transparent={true} - hardwareAccelerated={true} - statusBarTranslucent={true} - visible={visible} - onRequestClose={handleRequestClose} - > - <> - <TouchableWithoutFeedback style={{ ...styles.mask }} onPress={handleBgClose}> - <View style={{ ...styles.mask, backgroundColor: bgColor }}></View> - </TouchableWithoutFeedback> - {children} - </> - </Modal> - ) -}) diff --git a/src/components/common/Modal.tsx b/src/components/common/Modal.tsx new file mode 100644 index 000000000..8e3d7d71f --- /dev/null +++ b/src/components/common/Modal.tsx @@ -0,0 +1,100 @@ +import { createStyle } from '@/utils/tools' +import React, { useImperativeHandle, forwardRef, useState, useMemo } from 'react' +import { Modal, TouchableWithoutFeedback, View, type ModalProps as _ModalProps } from 'react-native' +import StatusBar from './StatusBar' +// import { useDimensions } from '@/utils/hooks' + +const styles = createStyle({ + // container: { + // flex: 1, + // }, + mask: { + position: 'absolute', + top: 0, + left: 0, + bottom: 0, + right: 0, + // width: '100%', + // height: '100%', + }, +}) + +export interface ModalProps extends Omit<_ModalProps, 'visible'> { + onHide?: () => void + /** + * 按返回键是否隐藏 + */ + keyHide?: boolean + /** + * 点击背景是否隐藏 + */ + bgHide?: boolean + /** + * 背景颜色 + */ + bgColor?: string + /** + * 是否填充状态栏 + */ + statusBarPadding?: boolean +} + + +export interface ModalType { + setVisible: (visible: boolean) => void +} + +export default forwardRef<ModalType, ModalProps>(({ + onHide = () => {}, + keyHide = true, + bgHide = true, + bgColor = 'rgba(0,0,0,0)', + statusBarPadding = true, + children, + ...props +}: ModalProps, ref) => { + const [visible, setVisible] = useState(false) + // const { window: windowSize } = useDimensions() + const handleRequestClose = () => { + if (keyHide) { + setVisible(false) + onHide() + } + } + const handleBgClose = () => { + if (bgHide) { + setVisible(false) + onHide() + } + } + + useImperativeHandle(ref, () => ({ + setVisible(_visible) { + if (visible == _visible) return + setVisible(_visible) + if (!_visible) onHide() + }, + })) + + const memoChildren = useMemo(() => children, [children]) + + return ( + <Modal + animationType="fade" + transparent={true} + hardwareAccelerated={true} + statusBarTranslucent={true} + visible={visible} + onRequestClose={handleRequestClose} + {...props} + > + {/* <StatusBar /> */} + <View style={{ flex: 1, paddingTop: statusBarPadding ? StatusBar.currentHeight : 0 }}> + <TouchableWithoutFeedback style={styles.mask} onPress={handleBgClose}> + <View style={{ ...styles.mask, backgroundColor: bgColor }}></View> + </TouchableWithoutFeedback> + {memoChildren} + </View> + </Modal> + ) +}) diff --git a/src/components/common/Popup.js b/src/components/common/Popup.js deleted file mode 100644 index 8d9d3571b..000000000 --- a/src/components/common/Popup.js +++ /dev/null @@ -1,130 +0,0 @@ -import React, { useMemo } from 'react' -import { StyleSheet, View, Text, TouchableOpacity } from 'react-native' - -import Modal from './Modal' -import { Icon } from '@/components/common/Icon' -import { useGetter } from '@/store' -import { useKeyboard } from '@/utils/hooks' -import StatusBar from '@/components/common/StatusBar' - -const styles = StyleSheet.create({ - centeredView: { - flex: 1, - // justifyContent: 'flex-end', - // alignItems: 'center', - }, - modalView: { - elevation: 6, - flexGrow: 0, - flexShrink: 1, - }, - header: { - flex: 0, - flexDirection: 'row', - borderTopLeftRadius: 8, - borderTopRightRadius: 8, - }, - title: { - fontSize: 13, - paddingLeft: 10, - paddingRight: 25, - paddingTop: 10, - paddingBottom: 10, - // lineHeight: 20, - }, - closeBtn: { - position: 'absolute', - right: 0, - // borderTopRightRadius: 8, - flexGrow: 0, - flexShrink: 0, - height: 30, - width: 30, - justifyContent: 'center', - alignItems: 'center', - // backgroundColor: '#eee', - }, -}) - - -export default ({ - visible = false, - hide = () => {}, - keyHide = true, - bgHide = true, - closeBtn = true, - position = 'bottom', - title = '', - children, -}) => { - const theme = useGetter('common', 'theme') - const { keyboardShown, keyboardHeight } = useKeyboard() - - const closeBtnComponent = useMemo(() => closeBtn ? <TouchableOpacity style={styles.closeBtn} onPress={hide}><Icon name="close" style={{ color: theme.normal50, fontSize: 12 }} /></TouchableOpacity> : null, [closeBtn, hide, theme]) - - const [centeredViewStyle, modalViewStyle] = useMemo(() => { - switch (position) { - case 'top': - return [ - { justifyContent: 'flex-start' }, - { - width: '100%', - maxHeight: '78%', - minHeight: '20%', - backgroundColor: 'white', - paddingTop: StatusBar.currentHeight, - }, - ] - case 'left': - return [ - { flexDirection: 'row', justifyContent: 'flex-start' }, - { - minWidth: '45%', - maxWidth: '78%', - height: '100%', - backgroundColor: 'white', - paddingTop: StatusBar.currentHeight, - }, - ] - case 'right': - return [ - { flexDirection: 'row', justifyContent: 'flex-end' }, - { - minWidth: '45%', - maxWidth: '78%', - height: '100%', - backgroundColor: 'white', - paddingTop: StatusBar.currentHeight, - }, - ] - case 'bottom': - default: - return [ - { justifyContent: 'flex-end' }, - { - width: '100%', - maxHeight: '78%', - minHeight: '20%', - backgroundColor: 'white', - borderTopLeftRadius: 8, - borderTopRightRadius: 8, - }, - ] - } - }, [position]) - - return ( - <Modal visible={visible} hideModal={hide} keyHide={keyHide} bgHide={bgHide} bgColor="rgba(50,50,50,.3)"> - <StatusBar /> - <View style={{ ...styles.centeredView, ...centeredViewStyle, paddingBottom: keyboardShown ? keyboardHeight : 0 }}> - <View style={{ ...styles.modalView, ...modalViewStyle, backgroundColor: theme.primary }} onStartShouldSetResponder={() => true}> - <View style={styles.header}> - <Text style={{ ...styles.title, color: theme.normal40 }} numberOfLines={1}>{title}</Text> - {closeBtnComponent} - </View> - {children} - </View> - </View> - </Modal> - ) -} diff --git a/src/components/common/Popup.tsx b/src/components/common/Popup.tsx new file mode 100644 index 000000000..deeb5d137 --- /dev/null +++ b/src/components/common/Popup.tsx @@ -0,0 +1,183 @@ +import React, { forwardRef, useImperativeHandle, useMemo, useRef } from 'react' +import { View, TouchableOpacity } from 'react-native' + +import Modal, { type ModalType } from './Modal' +import { Icon } from '@/components/common/Icon' +import { useKeyboard } from '@/utils/hooks' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import Text from './Text' +import StatusBar from './StatusBar' + +const styles = createStyle({ + centeredView: { + flex: 1, + // justifyContent: 'flex-end', + // alignItems: 'center', + }, + modalView: { + elevation: 6, + flexGrow: 0, + flexShrink: 1, + }, + header: { + flex: 0, + flexDirection: 'row', + borderTopLeftRadius: 8, + borderTopRightRadius: 8, + }, + title: { + paddingLeft: 10, + paddingRight: 25, + paddingTop: 10, + paddingBottom: 10, + // lineHeight: 20, + }, + closeBtn: { + position: 'absolute', + right: 0, + // borderTopRightRadius: 8, + flexGrow: 0, + flexShrink: 0, + height: 30, + width: 30, + justifyContent: 'center', + alignItems: 'center', + // backgroundColor: '#eee', + }, +}) + +export interface PopupProps { + onHide?: () => void + keyHide?: boolean + bgHide?: boolean + closeBtn?: boolean + position?: 'top' | 'left' | 'right' | 'bottom' + title?: string + children: React.ReactNode +} + +export interface PopupType { + setVisible: (visible: boolean) => void +} + +export default forwardRef<PopupType, PopupProps>(({ + onHide = () => {}, + keyHide = true, + bgHide = true, + closeBtn = true, + position = 'bottom', + title = '', + children, +}: PopupProps, ref) => { + const theme = useTheme() + const { keyboardShown, keyboardHeight } = useKeyboard() + + const modalRef = useRef<ModalType>(null) + + useImperativeHandle(ref, () => ({ + setVisible(visible: boolean) { + modalRef.current?.setVisible(visible) + }, + })) + + const closeBtnComponent = useMemo(() => closeBtn + ? <TouchableOpacity style={styles.closeBtn} onPress={() => modalRef.current?.setVisible(false)}> + <Icon name="close" style={{ color: theme['c-font-label'] }} size={12} /> + </TouchableOpacity> + : null, [closeBtn, theme]) + + const [centeredViewStyle, modalViewStyle] = useMemo(() => { + switch (position) { + case 'top': + return [ + { + position: 'absolute', + left: 0, + right: 0, + bottom: 0, + top: 0, + justifyContent: 'flex-start', + }, + { + width: '100%', + maxHeight: '78%', + minHeight: '20%', + // backgroundColor: 'white', + }, + ] as const + case 'left': + return [ + { + position: 'absolute', + left: 0, + right: 0, + bottom: 0, + top: 0, + flexDirection: 'row', + justifyContent: 'flex-start', + }, + { + minWidth: '45%', + maxWidth: '78%', + height: '100%', + paddingTop: StatusBar.currentHeight, + // backgroundColor: 'white', + }, + ] as const + case 'right': + return [ + { + position: 'absolute', + left: 0, + right: 0, + bottom: 0, + top: 0, + flexDirection: 'row', + justifyContent: 'flex-end', + }, + { + minWidth: '45%', + maxWidth: '78%', + height: '100%', + paddingTop: StatusBar.currentHeight, + // backgroundColor: 'white', + }, + ] as const + case 'bottom': + default: + return [ + { + position: 'absolute', + left: 0, + right: 0, + bottom: 0, + top: 0, + justifyContent: 'flex-end', + }, + { + width: '100%', + maxHeight: '78%', + minHeight: '20%', + // backgroundColor: 'white', + borderTopLeftRadius: 8, + borderTopRightRadius: 8, + }, + ] as const + } + }, [position]) + + return ( + <Modal onHide={onHide} keyHide={keyHide} bgHide={bgHide} bgColor="rgba(50,50,50,.2)" ref={modalRef}> + <View style={{ ...styles.centeredView, ...centeredViewStyle, paddingBottom: keyboardShown ? keyboardHeight : 0 }}> + <View style={{ ...styles.modalView, ...modalViewStyle, backgroundColor: theme['c-content-background'] }} onStartShouldSetResponder={() => true}> + <View style={styles.header}> + <Text size={13} style={styles.title} numberOfLines={1}>{title}</Text> + {closeBtnComponent} + </View> + {children} + </View> + </View> + </Modal> + ) +}) diff --git a/src/components/common/ScaledImage.tsx b/src/components/common/ScaledImage.tsx new file mode 100644 index 000000000..03c1040f7 --- /dev/null +++ b/src/components/common/ScaledImage.tsx @@ -0,0 +1,48 @@ +import React, { useEffect, useState } from 'react' +import { Image, StyleSheet, type ImageProps } from 'react-native' + +export interface ScaledImageProps extends Pick<ImageProps, 'style'> { + uri: string + width?: number + height?: number + maxWidth?: number + maxHeight?: number +} + +export default ({ uri, width, height, maxWidth, maxHeight, style }: ScaledImageProps) => { + const [wh, setWH] = useState({ width: 0, height: 0 }) + + useEffect(() => { + Image.getSize(uri, (realWidth, realHeight) => { + let w = width ?? 0 + let h = height ?? 0 + + if (w && !h) { + h = realHeight * (w / realWidth) + } else if (!w && h) { + w = realWidth * (h / realHeight) + } else { + if (maxWidth && realWidth > maxWidth) { + w = maxWidth + h = realHeight * (w / realWidth) + + if (maxHeight && h > maxHeight) { + w = realWidth * (maxHeight / realHeight) + h = maxHeight + } + } else if (maxHeight && realHeight > maxHeight) { + w = realWidth * (h / realHeight) + h = maxHeight + } + } + setWH({ width: w || realWidth, height: h || realHeight }) + }) + }, [height, maxHeight, maxWidth, uri, width]) + + return ( + <Image + source={{ uri }} + style={StyleSheet.compose({ height: wh.height, width: wh.width }, style)} + /> + ) +} diff --git a/src/components/common/Slider.js b/src/components/common/Slider.js deleted file mode 100644 index 5ef48c97d..000000000 --- a/src/components/common/Slider.js +++ /dev/null @@ -1,37 +0,0 @@ -import React, { memo } from 'react' - -import Slider from '@react-native-community/slider' -import { StyleSheet } from 'react-native' -import { useGetter } from '@/store' - -export default memo(({ value, minimumValue, maximumValue, onSlidingStart, onSlidingComplete, onValueChange, step }) => { - const theme = useGetter('common', 'theme') - - return ( - <Slider - value={value} - style={styles.slider} - minimumValue={minimumValue} - maximumValue={maximumValue} - minimumTrackTintColor={theme.secondary30} - maximumTrackTintColor={theme.secondary30} - thumbTintColor={theme.secondary} - onSlidingStart={onSlidingStart} - onSlidingComplete={onSlidingComplete} - onValueChange={onValueChange} - step={step} - /> - ) -}) - - -const styles = StyleSheet.create({ - slider: { - flexShrink: 0, - flexGrow: 1, - // width: '100%', - // maxWidth: 300, - height: 40, - // backgroundColor: '#eee', - }, -}) diff --git a/src/components/common/Slider.tsx b/src/components/common/Slider.tsx new file mode 100644 index 000000000..c537e6dc3 --- /dev/null +++ b/src/components/common/Slider.tsx @@ -0,0 +1,47 @@ +import React, { memo } from 'react' + +import Slider, { SliderProps as _SliderProps } from '@react-native-community/slider' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' + +export type SliderProps = Pick<_SliderProps, +'value' +| 'minimumValue' +| 'maximumValue' +| 'onSlidingStart' +| 'onSlidingComplete' +| 'onValueChange' +| 'step' +> + +export default memo(({ value, minimumValue, maximumValue, onSlidingStart, onSlidingComplete, onValueChange, step }: SliderProps) => { + const theme = useTheme() + + return ( + <Slider + value={value} + style={styles.slider} + minimumValue={minimumValue} + maximumValue={maximumValue} + minimumTrackTintColor={theme['c-primary-alpha-500']} + maximumTrackTintColor={theme['c-primary-alpha-500']} + thumbTintColor={theme['c-primary']} + onSlidingStart={onSlidingStart} + onSlidingComplete={onSlidingComplete} + onValueChange={onValueChange} + step={step} + /> + ) +}) + + +const styles = createStyle({ + slider: { + flexShrink: 0, + flexGrow: 1, + // width: '100%', + // maxWidth: 300, + height: 40, + // backgroundColor: '#eee', + }, +}) diff --git a/src/components/common/StatusBar.js b/src/components/common/StatusBar.tsx similarity index 67% rename from src/components/common/StatusBar.js rename to src/components/common/StatusBar.tsx index 6c200c6d7..b8c1ef31e 100644 --- a/src/components/common/StatusBar.js +++ b/src/components/common/StatusBar.tsx @@ -1,9 +1,10 @@ +import { useTheme } from '@/store/theme/hook' import React from 'react' import { StatusBar as RNStatusBar } from 'react-native' -import { useGetter } from '@/store' const StatusBar = function() { - const statusBarStyle = useGetter('common', 'statusBarStyle') + const theme = useTheme() + const statusBarStyle = theme.isDark ? 'light-content' : 'dark-content' return <RNStatusBar backgroundColor="rgba(0,0,0,0)" barStyle={statusBarStyle} translucent={true} /> } diff --git a/src/components/common/Text.tsx b/src/components/common/Text.tsx new file mode 100644 index 000000000..70f28bd37 --- /dev/null +++ b/src/components/common/Text.tsx @@ -0,0 +1,28 @@ +import React from 'react' +import { Text, type TextProps as _TextProps, StyleSheet } from 'react-native' +import { useTheme } from '@/store/theme/hook' +import { setSpText } from '@/utils/pixelRatio' +// import { AppColors } from '@/theme' + +export interface TextProps extends _TextProps { + /** + * 字体大小 + */ + size?: number + /** + * 字体颜色 + */ + color?: string +} + +export default ({ style, size = 15, color, children, ...props }: TextProps) => { + const theme = useTheme() + + return ( + <Text + style={StyleSheet.compose({ fontSize: setSpText(size), color: color ?? theme['c-font'] }, style)} + {...props} + >{children}</Text> + ) +} + diff --git a/src/components/layout/Header.js b/src/components/layout/Header.js deleted file mode 100644 index ceaa4291e..000000000 --- a/src/components/layout/Header.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react' -import { View, Text, StyleSheet, SafeAreaView } from 'react-native' -import StatusBar from '@/components/common/StatusBar' - -const Header = state => { - return ( - <View style={style.header}> - <StatusBar /> - <SafeAreaView style={style.container}> - {state.menu.map((item, index) => <View style={style.btn} key={item.id}><Text style={style.btnText} onPress={() => this.handlePress(item, index)}>{item.name}</Text></View>)} - </SafeAreaView> - </View> - ) -} - - -const style = StyleSheet.create({ - header: { - backgroundColor: '#fff', - height: 50 + StatusBar.currentHeight, - paddingTop: StatusBar.currentHeight, - // Android shadow - // shadowColor: '#000', - // shadowOffset: { - // width: 0, - // height: 2, - // }, - // shadowOpacity: 0.23, - // shadowRadius: 2.62, - // elevation: 4, - }, - container: { - // width: '100%', - flexDirection: 'row', - }, - btn: { - // flex: 1, - paddingLeft: 10, - paddingRight: 10, - backgroundColor: 'rgba(0,0,0,0);', - alignItems: 'center', - justifyContent: 'center', - height: 50, - }, - btnText: { - fontSize: 16, - color: 'white', - }, -}) - - -export default Header diff --git a/src/components/player/Progress.js b/src/components/player/Progress.js deleted file mode 100644 index 7e6e0afc5..000000000 --- a/src/components/player/Progress.js +++ /dev/null @@ -1,88 +0,0 @@ -import React, { memo } from 'react' -import { View, StyleSheet, TouchableOpacity, Pressable } from 'react-native' -import { useLayout } from '@/utils/hooks' -import { useGetter, useDispatch } from '@/store' -// import { AppColors } from '@/theme' - - -const DefaultBar = memo(() => { - const theme = useGetter('common', 'theme') - - return <View style={{ ...styles.progressBar, backgroundColor: theme.normal75, position: 'absolute', width: '100%', left: 0, top: 0 }}></View> -}) - -const BufferedBar = memo(({ bufferedProgress }) => { - // console.log(bufferedProgress) - const theme = useGetter('common', 'theme') - return <View style={{ ...styles.progressBar, backgroundColor: theme.secondary45, position: 'absolute', width: bufferedProgress + '%', left: 0, top: 0 }}></View> -}) - -const PreassBar = memo(({ duration }) => { - const { onLayout, ...layout } = useLayout() - const setProgress = useDispatch('player', 'setProgress') - const handlePress = event => { - setProgress(event.nativeEvent.locationX / layout.width * duration) - } - - return <Pressable onPress={handlePress} onLayout={onLayout} style={styles.pressBar} /> -}) - - -const Progress = ({ progress, bufferedProgress, duration }) => { - // const { progress } = usePlayTimeBuffer() - const theme = useGetter('common', 'theme') - // console.log(progress) - const progressStr = progress + '%' - - return ( - <View style={styles.progress}> - <View> - <DefaultBar /> - <BufferedBar bufferedProgress={bufferedProgress} /> - <View style={{ ...styles.progressBar, backgroundColor: theme.secondary30, width: progressStr, position: 'absolute', left: 0, top: 0 }}> - <Pressable style={{ ...styles.progressDot, backgroundColor: theme.secondary10 }}></Pressable> - </View> - </View> - <PreassBar duration={duration} /> - {/* <View style={{ ...styles.progressBar, height: '100%', width: progressStr }}><Pressable style={styles.progressDot}></Pressable></View> */} - </View> - ) -} - - -const progressContentPadding = 9 -const progressHeight = 3 -const progressDotSize = 8 -const styles = StyleSheet.create({ - progress: { - width: '100%', - height: progressContentPadding * 2 + progressHeight, - // backgroundColor: 'rgba(0,0,0,0.5)', - paddingTop: progressContentPadding, - paddingBottom: progressContentPadding, - zIndex: 1, - }, - progressBar: { - height: progressHeight, - borderRadius: 4, - }, - progressDot: { - width: progressDotSize, - height: progressDotSize, - borderRadius: progressDotSize, - position: 'absolute', - right: -progressDotSize / 2, - top: -(progressDotSize - progressHeight) / 2, - zIndex: 9, - }, - pressBar: { - position: 'absolute', - // backgroundColor: 'rgba(0,0,0,0.5)', - left: 0, - top: 0, - height: progressContentPadding * 2 + progressHeight, - width: '100%', - }, -}) - -export default Progress diff --git a/src/components/player/Progress.tsx b/src/components/player/Progress.tsx new file mode 100644 index 000000000..102343888 --- /dev/null +++ b/src/components/player/Progress.tsx @@ -0,0 +1,105 @@ +import React, { memo, useMemo } from 'react' +import { View, Pressable, GestureResponderEvent } from 'react-native' +import { useLayout } from '@/utils/hooks' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { scaleSizeW } from '@/utils/pixelRatio' +// import { AppColors } from '@/theme' + + +const DefaultBar = memo(() => { + const theme = useTheme() + + return <View style={{ ...styles.progressBar, backgroundColor: theme['c-primary-light-100-alpha-800'], position: 'absolute', width: '100%', left: 0, top: 0 }}></View> +}) + +// const BufferedBar = memo(({ bufferedProgress }) => { +// // console.log(bufferedProgress) +// const theme = useTheme() +// return <View style={{ ...styles.progressBar, backgroundColor: theme.secondary45, position: 'absolute', width: bufferedProgress + '%', left: 0, top: 0 }}></View> +// }) + +const PreassBar = memo(({ duration }: { duration: number }) => { + const { onLayout, ...layout } = useLayout() + const handlePress = (event: GestureResponderEvent) => { + global.app_event.setProgress(event.nativeEvent.locationX / layout.width * duration) + } + + return <Pressable onPress={handlePress} onLayout={onLayout} style={styles.pressBar} /> +}) + + +const Progress = ({ progress, duration }: { + progress: number + duration: number +}) => { + // const { progress } = usePlayTimeBuffer() + const theme = useTheme() + // console.log(progress) + const progressStr = `${progress * 100}%` + + const progressDotStyle = useMemo(() => { + return { + width: progressDotSize, + height: progressDotSize, + borderRadius: progressDotSize, + position: 'absolute', + right: -progressDotSize / 2, + top: -(progressDotSize - progressHeight) / 2, + backgroundColor: theme['c-primary-light-100'], + zIndex: 9, + } as const + }, [theme]) + + return ( + <View style={styles.progress}> + <View> + <DefaultBar /> + {/* <BufferedBar bufferedProgress={bufferedProgress} /> */} + <View style={{ ...styles.progressBar, backgroundColor: theme['c-primary-light-100-alpha-400'], width: progressStr, position: 'absolute', left: 0, top: 0 }}> + <Pressable style={{ ...styles.progressDot, ...progressDotStyle }}></Pressable> + </View> + </View> + <PreassBar duration={duration} /> + {/* <View style={{ ...styles.progressBar, height: '100%', width: progressStr }}><Pressable style={styles.progressDot}></Pressable></View> */} + </View> + ) +} + + +const progressContentPadding = 9 +const progressHeight = 3 +const progressDotSize = scaleSizeW(8) +const styles = createStyle({ + progress: { + width: '100%', + height: progressContentPadding * 2 + progressHeight, + // backgroundColor: 'rgba(0,0,0,0.5)', + paddingTop: progressContentPadding, + paddingBottom: progressContentPadding, + zIndex: 1, + }, + progressBar: { + height: progressHeight, + borderRadius: 4, + }, + progressDot: { + width: progressDotSize, + height: progressDotSize, + borderRadius: progressDotSize, + position: 'absolute', + right: -progressDotSize / 2, + top: -(progressDotSize - progressHeight) / 2, + zIndex: 9, + }, + pressBar: { + position: 'absolute', + // backgroundColor: 'rgba(0,0,0,0.5)', + left: 0, + top: 0, + height: progressContentPadding * 2 + progressHeight, + width: '100%', + }, +}) + +export default Progress diff --git a/src/components/searchTipList.js b/src/components/searchTipList.js deleted file mode 100644 index 8cdab1ee7..000000000 --- a/src/components/searchTipList.js +++ /dev/null @@ -1,124 +0,0 @@ -import React, { useRef, useState, useEffect, useCallback, useMemo } from 'react' -import { StyleSheet, View, ScrollView, Animated, Text } from 'react-native' -// import PropTypes from 'prop-types' -// import { AppColors } from '@/theme' -import { useGetter } from '@/store' -// import InsetShadow from 'react-native-inset-shadow' - - -export default ({ list, visible, height, hideList, renderItem }) => { - const translateY = useRef(new Animated.Value(0)).current - const scaleY = useRef(new Animated.Value(0)).current - const theme = useGetter('common', 'theme') - // const isShowRef = useRef(false) - const [tipListVisible, setTipListVisible] = useState(false) - - - const handleShowList = useCallback(() => { - // console.log('handleShowList', height, visible) - if (!height) return - setTipListVisible(true) - - translateY.setValue(-height / 2) - scaleY.setValue(0) - - Animated.parallel([ - // Animated.timing(fade, { - // toValue: 1, - // duration: 300, - // useNativeDriver: true, - // }), - Animated.timing(translateY, { - toValue: 0, - duration: 300, - useNativeDriver: true, - }), - Animated.timing(scaleY, { - toValue: 1, - duration: 300, - useNativeDriver: true, - }), - ]).start() - }, [translateY, scaleY, height]) - - const handleHideList = useCallback(() => { - // Will change fadeAnim value to 0 in 5 seconds - // console.log('handleHideList') - Animated.parallel([ - // Animated.timing(fade, { - // toValue: 0, - // duration: 200, - // useNativeDriver: true, - // }), - Animated.timing(translateY, { - toValue: -height / 2, - duration: 300, - useNativeDriver: true, - }), - Animated.timing(scaleY, { - toValue: 0, - duration: 300, - useNativeDriver: true, - }), - ]).start((finished) => { - // console.log(finished) - if (!finished) return - setTipListVisible(false) - hideList && hideList() - }) - }, [translateY, scaleY, hideList, height]) - - const handleBlankPress = useCallback(() => { - if (!hideList) return - handleHideList() - }, [handleHideList, hideList]) - - useEffect(() => { - if (visible === tipListVisible) return - visible ? handleShowList() : handleHideList() - }, [tipListVisible, visible, handleShowList, handleHideList]) - - const listComponent = useMemo(() => ( - <Animated.View - style={{ - ...styles.anima, - transform: [ - { translateY: translateY }, - { scaleY: scaleY }, - ], - }}> - <View - style={{ - ...styles.container, - backgroundColor: theme.secondary40, - }}> - <ScrollView keyboardShouldPersistTaps={'always'}> - {list.map((item, index) => renderItem(item, index))} - </ScrollView> - </View> - <View style={styles.blank} onTouchStart={handleBlankPress}></View> - </Animated.View> - ), [handleBlankPress, list, renderItem, scaleY, theme.secondary40, translateY]) - - return tipListVisible ? listComponent : null -} - -const styles = StyleSheet.create({ - anima: { - position: 'absolute', - left: 0, - top: 0, - height: '100%', - width: '100%', - zIndex: 10, - }, - container: { - flexGrow: 0, - }, - blank: { - flex: 1, - flexGrow: 1, - backgroundColor: 'transparent', - // backgroundColor: 'rgba(0,0,0,0.2)', - }, -}) diff --git a/src/config/constant.js b/src/config/constant.js deleted file mode 100644 index 45c55d141..000000000 --- a/src/config/constant.js +++ /dev/null @@ -1,43 +0,0 @@ - -export const LIST_ID_PLAY_TEMP = null -export const LIST_ID_PLAY_LATER = '__LATER__' -export const LIST_ITEM_HEIGHT = 56 -export const LIST_SCROLL_POSITION_KEY = '__LIST_SCROLL_POSITION_KEY__' - -export const APP_PROVIDER_NAME = 'cn.toside.music.mobile.provider' - -export const VERSION_STATUS = { - checking: 'Checking', - latest: 'Latest', - downloading: 'Downloading', - downloaded: 'Downloaded', - unknown: 'Unknown', - failed: 'Failed', - available: 'Available', -} - -export const NAV_VIEW_NAMES = { - search: 0, - songList: 1, - top: 2, - list: 3, - setting: 4, -} - -export const LXM_FILE_EXT_RXP = /\.(json|lxmc)$/ - -export const MUSIC_TOGGLE_MODE = { - listLoop: 'listLoop', // 列表循环 - random: 'random', // 列表随机 - list: 'list', // 顺序播放 - singleLoop: 'singleLoop', // 单曲循环 - none: 'none', // 禁用 -} - -export const MUSIC_TOGGLE_MODE_LIST = [ - MUSIC_TOGGLE_MODE.listLoop, - MUSIC_TOGGLE_MODE.random, - MUSIC_TOGGLE_MODE.list, - MUSIC_TOGGLE_MODE.singleLoop, - MUSIC_TOGGLE_MODE.none, -] diff --git a/src/config/constant.ts b/src/config/constant.ts new file mode 100644 index 000000000..9def81f83 --- /dev/null +++ b/src/config/constant.ts @@ -0,0 +1,137 @@ +export const HEADER_HEIGHT = 42 +export const LIST_ITEM_HEIGHT = 54 +export const LIST_SCROLL_POSITION_KEY = '__LIST_SCROLL_POSITION_KEY__' + +export const LIST_IDS = { + DEFAULT: 'default', + LOVE: 'love', + TEMP: 'temp', + DOWNLOAD: 'download', + PLAY_LATER: null, +} as const + +// export const COMPONENT_IDS = { +// home: 'home', +// playDetail: 'playDetail', +// } as const +// export type COMPONENT_IDS_TYPE = keyof typeof COMPONENT_IDS +export enum COMPONENT_IDS { + home = 'home', + playDetail = 'playDetail', + songlistDetail = 'songlistDetail', + comment = 'comment', +} + +export enum NAV_SHEAR_NATIVE_IDS { + playDetail_pic = 'playDetail_pic', + playDetail_header = 'playDetail_header', + playDetail_pageIndicator = 'playDetail_pageIndicator', + playDetail_player = 'playDetail_player', + songlistDetail_pic = 'songlistDetail_pic', + songlistDetail_title = 'songlistDetail_title', +} + + +export const storageDataPrefix = { + setting: '@setting_v1', + userList: '@user_list', + viewPrevState: '@view_prev_state', + + list: '@list__', + listScrollPosition: '@list_scroll_position', + listPrevSelectId: '@list_prev_select_id', + + lyric: '@lyric__', + musicUrl: '@music_url__', + musicOtherSource: '@music_other_source__', + playInfo: '@play_info', + + syncAuthKey: '@sync_auth_key', + syncHost: '@sync_host', + syncHostHistory: '@sync_host_history', + + notificationTipEnable: '@notification_tip_enable', + + searchHistoryList: '@search_history_list', + listUpdateInfo: '@list_update_info', + ignoreVersion: '@ignore_version', + leaderboardSetting: '@leaderboard_setting', + songListSetting: '@songist_setting', + searchSetting: '@search_setting', + + fontSize: '@font_size', + + theme: '@theme', +} as const + +// v0.x.x 版本的 data keys +export const storageDataPrefixOld = { + setting: '@setting', + list: '@list__', + listPosition: '@listposition__', + listSort: '@listsort__', + // lyric: '@lyric__', + // musicUrl: '@music_url__', + playInfo: '@play_info', + syncAuthKey: '@sync_auth_key', + syncHost: '@sync_host', + syncHostHistory: '@sync_host_history', + notificationTipEnable: '@notification_tip_enable', +} as const + +export const APP_PROVIDER_NAME = 'cn.toside.music.mobile.provider' + + +export const NAV_MENUS = [ + { id: 'nav_search', icon: 'search-2' }, + { id: 'nav_songlist', icon: 'album' }, + { id: 'nav_top', icon: 'leaderboard' }, + { id: 'nav_love', icon: 'love' }, + // { id: 'download', icon: 'download-2' }, + { id: 'nav_setting', icon: 'setting' }, +] as const + +export type NAV_ID_Type = typeof NAV_MENUS[number]['id'] + +export const LXM_FILE_EXT_RXP = /\.(json|lxmc)$/ + +export const MUSIC_TOGGLE_MODE = { + listLoop: 'listLoop', // 列表循环 + random: 'random', // 列表随机 + list: 'list', // 顺序播放 + singleLoop: 'singleLoop', // 单曲循环 + none: 'none', // 禁用 +} as const + +export const MUSIC_TOGGLE_MODE_LIST = [ + MUSIC_TOGGLE_MODE.listLoop, + MUSIC_TOGGLE_MODE.random, + MUSIC_TOGGLE_MODE.list, + MUSIC_TOGGLE_MODE.singleLoop, + MUSIC_TOGGLE_MODE.none, +] as const + +export const DEFAULT_SETTING = { + leaderboard: { + source: 'kw' as LX.OnlineSource, + boardId: 'kw__16', + }, + + songList: { + source: 'kg' as LX.OnlineSource, + sortId: '5', + tagName: '', + tagId: '', + }, + + search: { + temp_source: 'kw' as LX.OnlineSource, + source: 'all' as LX.OnlineSource | 'all', + type: 'music' as 'music' | 'songlist', + }, + + viewPrevState: { + id: 'nav_search' as NAV_ID_Type, + // query: {}, + }, +} diff --git a/src/config/defaultSetting.js b/src/config/defaultSetting.js deleted file mode 100644 index f5aae20bf..000000000 --- a/src/config/defaultSetting.js +++ /dev/null @@ -1,140 +0,0 @@ -// const path = require('path') -// const os = require('os') -// const { isMac } = require('./utils') -import { MUSIC_TOGGLE_MODE } from './constant' - -const defaultSetting = { - version: '1.26', - player: { - togglePlayMethod: MUSIC_TOGGLE_MODE.listLoop, - highQuality: false, - isSavePlayTime: false, - cacheSize: 1024, // unit MB - timeoutExit: '', - timeoutExitPlayed: true, - isHandleAudioFocus: true, - isShowLyricTranslation: false, - isShowLyricRoma: false, - isShowNotificationImage: true, - isS2t: false, // 是否将歌词从简体转换为繁体 - portrait: { - style: { - lrcFontSize: 160, - }, - }, - landscape: { - style: { - lrcFontSize: 180, - }, - }, - }, - desktopLyric: { - enable: false, - isLock: false, - theme: 'green', - width: 100, - maxLineNum: 5, - isSingleLine: false, - showToggleAnima: true, - // width: 380, - // height: 420, - position: { - x: 0, - y: 0, - }, - textPosition: { - x: 'left', - y: 'top', - }, - style: { - fontSize: 180, - opacity: 100, - // isZoomActiveLrc: true, - }, - }, - list: { - isClickPlayList: false, - isShowSource: true, - prevSelectListId: 'default', - isSaveScrollLocation: true, - addMusicLocationType: 'top', - }, - download: { - enable: false, - // savePath: path.join(os.homedir(), 'Desktop'), - fileName: '歌名 - 歌手', - maxDownloadNum: 3, - isDownloadLrc: false, - isEmbedPic: true, - isEmbedLyric: false, - }, - leaderboard: { - source: 'kw', - tabId: 'kw__16', - }, - songList: { - source: 'kw', - sortId: 'new', - tagInfo: { - name: '默认', - id: null, - }, - }, - odc: { - isAutoClearSearchInput: false, - isAutoClearSearchList: false, - }, - search: { - searchSource: 'kw', - tempSearchSource: 'kw', - isShowHotSearch: false, - isShowHistorySearch: false, - isFocusSearchBox: false, - }, - sync: { - enable: false, - }, - // network: { - // proxy: { - // enable: false, - // host: '', - // port: '', - // username: '', - // password: '', - // }, - // }, - themeId: 'green', - isAutoTheme: true, - langId: null, - sourceId: 'kw', - apiSource: 'temp', - sourceNameType: 'alias', - shareType: 'system', - // randomAnimate: true, - ignoreVersion: null, - isAgreePact: false, - startupAutoPlay: false, - autoHidePlayBar: true, -} - -const overwriteSetting = { - // songList: { - // source: 'kw', - // sortId: '', - // }, - // search: { - // searchSource: 'kw', - // }, - // player: { - // cacheSize: 1024, - // }, -} - -// 使用新年皮肤 -// if (new Date().getMonth() < 2) defaultSetting.themeId = 9 - - -export { - defaultSetting, - overwriteSetting, -} diff --git a/src/config/defaultSetting.ts b/src/config/defaultSetting.ts new file mode 100644 index 000000000..f2f0cde39 --- /dev/null +++ b/src/config/defaultSetting.ts @@ -0,0 +1,67 @@ +const defaultSetting: LX.AppSetting = { + version: '2.0', + 'common.isAutoTheme': true, + 'common.langId': null, + 'common.apiSource': 'temp', + 'common.sourceNameType': 'alias', + 'common.shareType': 'system', + 'common.isAgreePact': false, + 'common.autoHidePlayBar': true, + 'common.drawerLayoutPosition': 'left', + + 'player.startupAutoPlay': false, + 'player.togglePlayMethod': 'listLoop', + 'player.isPlayHighQuality': false, + 'player.isSavePlayTime': false, + 'player.cacheSize': '1024', + 'player.timeoutExit': '', + 'player.timeoutExitPlayed': true, + 'player.isHandleAudioFocus': true, + 'player.isShowLyricTranslation': false, + 'player.isShowLyricRoma': false, + 'player.isShowNotificationImage': true, + 'player.isS2t': false, + 'player.vertical.style.lrcFontSize': 160, + 'player.horizontal.style.lrcFontSize': 180, + + 'desktopLyric.enable': false, + 'desktopLyric.isLock': false, + 'desktopLyric.width': 100, + 'desktopLyric.maxLineNum': 5, + 'desktopLyric.isSingleLine': false, + 'desktopLyric.showToggleAnima': true, + 'desktopLyric.position.x': 0, + 'desktopLyric.position.y': 0, + 'desktopLyric.textPosition.x': 'left', + 'desktopLyric.textPosition.y': 'top', + 'desktopLyric.style.fontSize': 180, + 'desktopLyric.style.opacity': 100, + 'desktopLyric.style.lyricUnplayColor': 'rgba(255, 255, 255, 1)', + 'desktopLyric.style.lyricPlayedColor': 'rgba(7, 197, 86, 1)', + 'desktopLyric.style.lyricShadowColor': 'rgba(0, 0, 0, 0.6)', + + 'search.isShowHotSearch': false, + 'search.isShowHistorySearch': false, + + 'list.isClickPlayList': false, + 'list.isShowSource': true, + 'list.isSaveScrollLocation': true, + 'list.addMusicLocationType': 'top', + + 'download.fileName': '歌名 - 歌手', + + 'sync.enable': false, + + 'theme.id': 'blue_plus', + 'theme.lightId': 'green', + 'theme.darkId': 'black', +} + + +// 使用新年皮肤 +if (new Date().getMonth() < 2) { + defaultSetting['theme.id'] = 'happy_new_year' + defaultSetting['desktopLyric.style.lyricPlayedColor'] = 'rgba(255, 18, 34, 1)' +} + +export default defaultSetting diff --git a/src/config/globalData.js b/src/config/globalData.js deleted file mode 100644 index 5604522f8..000000000 --- a/src/config/globalData.js +++ /dev/null @@ -1,36 +0,0 @@ -import { version } from '../../package.json' -process.versions.app = version - -global.i18n = null - -global.playerStatus = { - isInitialized: false, - isRegisteredService: false, - isIniting: false, -} - -global.restorePlayInfo = null -global.allList = null -global.globalObj = null -global.listScrollPosition = {} -global.listSort = {} - -global.isScreenKeepAwake = false - -// 是否播放完后退出应用 -global.isPlayedExit = false - -global.prevListPlayIndex = -1 - -global.syncKeyInfo = {} -global.isSyncEnableing = false - -global.playInfo = { - isPlaying: false, - currentPlayMusicInfo: null, - duration: 0, -} - -global.isEnableSyncLog = false - -global.playerTrackId = '' diff --git a/src/config/globalData.ts b/src/config/globalData.ts new file mode 100644 index 000000000..f8aefc1bd --- /dev/null +++ b/src/config/globalData.ts @@ -0,0 +1,72 @@ +import { version } from '../../package.json' +import { createAppEventHub } from '@/event/appEvent' +import { createListEventHub } from '@/event/listEvent' +import { createStateEventHub } from '@/event/stateEvent' +if (process.versions == null) { + // @ts-expect-error + process.versions = { + app: version, + } +} else process.versions.app = version + +// global.i18n = null + +// let screenW = Dimensions.get('window').width +// let screenH = Dimensions.get('window').height +// if (screenW > screenH) { +// const temp = screenW +// screenW = screenH +// screenH = temp +// } + + +global.lx = { + fontSize: 1, + playerStatus: { + isInitialized: false, + isRegisteredService: false, + isIniting: false, + }, + + restorePlayInfo: null, + // allList: null, + // globalObj: null, + // listScrollPosition: {}, + // listSort: {}, + + isScreenKeepAwake: false, + + // 是否播放完后退出应用 + isPlayedStop: false, + + // prevListPlayIndex: -1, + + // syncKeyInfo: {}, + isSyncEnableing: false, + + + isEnableSyncLog: false, + + playerTrackId: '', + + gettingUrlId: '', + + qualityList: {}, + + jumpMyListPosition: false, + + // syncKeyInfo: initValue as LX.Sync.KeyInfo, + + // windowInfo: { + // screenW, + // screenH, + // fontScale: PixelRatio.getFontScale(), + // pixelRatio: PixelRatio.get(), + // screenPxW: PixelRatio.getPixelSizeForLayoutSize(screenW), + // screenPxH: PixelRatio.getPixelSizeForLayoutSize(screenH), + // }, +} + +global.app_event = createAppEventHub() +global.list_event = createListEventHub() +global.state_event = createStateEventHub() diff --git a/src/config/index.js b/src/config/index.js index ffaf9c23b..dec3529a5 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -9,16 +9,3 @@ export { } // export const defaultUrl = require('@/resources/medias/Silence02s.mp3') -export const storageDataPrefix = { - setting: '@setting', - list: '@list__', - listPosition: '@listposition__', - listSort: '@listsort__', - lyric: '@lyric__', - musicUrl: '@music_url__', - playInfo: '@play_info', - syncAuthKey: '@sync_auth_key', - syncHost: '@sync_host', - syncHostHistory: '@sync_host_history', - notificationTipEnable: '@notification_tip_enable', -} diff --git a/src/config/migrate.ts b/src/config/migrate.ts new file mode 100644 index 000000000..f3de9fa48 --- /dev/null +++ b/src/config/migrate.ts @@ -0,0 +1,185 @@ +import { filterMusicList, toNewMusicInfo } from '@/utils' +import { LIST_IDS, storageDataPrefix, storageDataPrefixOld } from '@/config/constant' +import { getAllKeys, getData, getDataMultiple, removeData, saveData } from '@/plugins/storage' +import { allMusicList, listDataOverwrite, userLists } from '@/utils/listManage' +import { saveListMusics, saveUserList } from '@/utils/data' + + +interface OldUserListInfo { + name: string + id: string + source?: LX.OnlineSource + sourceListId?: string + locationUpdateTime?: number + list: any[] +} + + +/* export const migrateListData = async() => { + let playList = await parseDataFile<{ defaultList?: { list: any[] }, loveList?: { list: any[] }, tempList?: { list: any[] }, userList?: OldUserListInfo[] }>('playList.json') + let listDataAll: LX.List.ListDataFull = { + defaultList: [], + loveList: [], + userList: [], + tempList: [], + } + let isRequiredSave = false + if (playList) { + if (playList.defaultList) listDataAll.defaultList = filterMusicList(playList.defaultList.list.map(m => toNewMusicInfo(m))) + if (playList.loveList) listDataAll.loveList = filterMusicList(playList.loveList.list.map(m => toNewMusicInfo(m))) + if (playList.tempList) listDataAll.tempList = filterMusicList(playList.tempList.list.map(m => toNewMusicInfo(m))) + if (playList.userList) { + listDataAll.userList = playList.userList.map(l => { + return { + ...l, + locationUpdateTime: l.locationUpdateTime ?? null, + list: filterMusicList(l.list.map(m => toNewMusicInfo(m))), + } + }) + } + isRequiredSave = true + } else { + const config = await parseDataFile<{ list?: { defaultList?: any[], loveList?: any[] } }>('config.json') + if (config?.list) { + const list = config.list + if (list.defaultList) listDataAll.defaultList = filterMusicList(list.defaultList.map(m => toNewMusicInfo(m))) + if (list.loveList) listDataAll.loveList = filterMusicList(list.loveList.map(m => toNewMusicInfo(m))) + isRequiredSave = true + } + } + if (isRequiredSave) await global.lx.worker.dbService.listDataOverwrite(listDataAll) + + const lyricData = await parseDataFile<Record<string, LX.Music.LyricInfo>>('lyrics_edited.json') + if (lyricData) { + for await (const [id, info] of Object.entries(lyricData)) { + await global.lx.worker.dbService.editedLyricAdd(id, info) + } + } +} + */ +export const getAllListData = async(): Promise<{ + defaultList?: { list: any[] } + loveList?: { list: any[] } + tempList?: { list: any[] } + userList?: OldUserListInfo[] +}> => { + const defaultListKey = storageDataPrefixOld.list + 'default' + const loveListKey = storageDataPrefixOld.list + 'love' + let defaultList + let loveList + let userList = [] + let keys = await getAllKeys() + const listKeys: string[] = [] + for (const key of keys) { + if (key.startsWith(storageDataPrefixOld.list)) { + listKeys.push(key) + } + } + const listData = await getDataMultiple(listKeys) as Array<[string, any]> + for (const [key, value] of listData) { + switch (key) { + case defaultListKey: + defaultList = value + break + case loveListKey: + loveList = value + break + default: + userList.push(value) + break + } + } + + const listSort: Record<string, number> = await getData(storageDataPrefixOld.listSort) ?? {} + + userList.sort((a, b) => { + if (listSort[a.id] == null) return listSort[b.id] == null ? -1 : 1 + return listSort[b.id] == null ? 1 : listSort[a.id] - listSort[b.id] + }) + userList.forEach((list, index) => { + if (listSort[list.id] == null) { + listSort[list.id] = index + delete list.location + } + }) + + return { + defaultList, + loveList, + userList, + } +} + +/** + * 迁移 v1.0.0 之前的 list data + * @returns + */ +export const migrateListData = async() => { + const playList = await getAllListData() + let listDataAll: LX.List.ListDataFull = { + defaultList: [], + loveList: [], + userList: [], + tempList: [], + } + if (playList.defaultList) listDataAll.defaultList = filterMusicList(playList.defaultList.list.map(m => toNewMusicInfo(m))) + if (playList.loveList) listDataAll.loveList = filterMusicList(playList.loveList.list.map(m => toNewMusicInfo(m))) + if (playList.userList) { + listDataAll.userList = playList.userList.map(l => { + return { + ...l, + locationUpdateTime: l.locationUpdateTime ?? null, + list: filterMusicList(l.list.map(m => toNewMusicInfo(m))), + } + }) + } + listDataOverwrite(listDataAll) + await saveUserList(userLists) + const allListIds = [LIST_IDS.DEFAULT, LIST_IDS.LOVE, ...userLists.map(l => l.id)] + await saveListMusics([...allListIds.map(id => ({ id, musics: allMusicList.get(id) as LX.List.ListMusics }))]) + await removeData(storageDataPrefixOld.listSort) + + const listPosition = await getData(storageDataPrefixOld.listPosition) + if (listPosition != null) { + await saveData(storageDataPrefix.listScrollPosition, listPosition) + await removeData(storageDataPrefixOld.listPosition) + } +} + +const timeStr2Intv = (timeStr: string) => { + let intvArr = timeStr.split(':') + let intv = 0 + let unit = 1 + while (intvArr.length) { + intv += parseInt(intvArr.pop() as string) * unit + unit *= 60 + } + return intv +} +const migratePlayInfo = async() => { + const playInfo = await getData<any>(storageDataPrefixOld.playInfo) + if (playInfo == null) return + if (playInfo.list !== undefined) delete playInfo.list + if (playInfo.maxTime) playInfo.maxTime = timeStr2Intv(playInfo.maxTime) + await saveData(storageDataPrefix.playInfo, playInfo) +} +/** + * 迁移 v1.0.0 之前的 meta 数据 + * @returns + */ +export const migrateMetaData = async() => { + await migratePlayInfo() + // const [playInfo] = await getDataMultiple([ + // storageDataPrefixOld.listPosition, + // storageDataPrefixOld.playInfo, + // ]) + + // await saveDataMultiple([ + // // [storageDataPrefix.listScrollPosition, listPosition[1]], + // [storageDataPrefix.playInfo, migratePlayInfo(playInfo[1])], + // ]) + // await removeDataMultiple([ + // storageDataPrefix.listScrollPosition, + // ]) +} + diff --git a/src/config/migrateSetting.ts b/src/config/migrateSetting.ts new file mode 100644 index 000000000..f076b8342 --- /dev/null +++ b/src/config/migrateSetting.ts @@ -0,0 +1,50 @@ +import { compareVer } from '@/utils' + +export default (setting: any): Partial<LX.AppSetting> => { + setting = { ...setting } + + // 迁移 v1 之前的配置 + if (compareVer(setting.version, '2.0') < 0) { + setting['player.startupAutoPlay'] = setting.startupAutoPlay + setting['player.togglePlayMethod'] = setting.player?.togglePlayMethod + setting['player.isPlayHighQuality'] = setting.player?.highQuality + setting['player.isSavePlayTime'] = setting.player?.isSavePlayTime + setting['player.cacheSize'] = setting.player?.cacheSize + setting['player.timeoutExit'] = setting.player?.timeoutExit + setting['player.timeoutExitPlayed'] = setting.player?.timeoutExitPlayed + setting['player.isHandleAudioFocus'] = setting.player?.isHandleAudioFocus + setting['player.isShowLyricTranslation'] = setting.player?.isShowLyricTranslation + setting['player.isShowLyricRoma'] = setting.player?.isShowLyricRoma + setting['player.isShowNotificationImage'] = setting.player?.isShowNotificationImage + setting['player.isS2t'] = setting.player?.isS2t + setting['player.portrait.style.lrcFontSize'] = setting.player?.portrait?.style?.lrcFontSize + setting['player.landscape.style.lrcFontSize'] = setting.player?.landscape?.style?.lrcFontSize + setting['desktopLyric.enable'] = setting.desktopLyric?.enable + setting['desktopLyric.isLock'] = setting.desktopLyric?.isLock + setting['desktopLyric.width'] = setting.desktopLyric?.width + setting['desktopLyric.maxLineNum'] = setting.desktopLyric?.maxLineNum + setting['desktopLyric.isSingleLine'] = setting.desktopLyric?.isSingleLine + setting['desktopLyric.showToggleAnima'] = setting.desktopLyric?.showToggleAnima + setting['desktopLyric.position.x'] = setting.desktopLyric?.position?.x + setting['desktopLyric.position.y'] = setting.desktopLyric?.position?.y + setting['desktopLyric.textPosition.x'] = setting.desktopLyric?.textPosition?.x + setting['desktopLyric.textPosition.y'] = setting.desktopLyric?.textPosition?.y + setting['desktopLyric.style.fontSize'] = setting.desktopLyric?.style?.fontSize + setting['desktopLyric.style.opacity'] = setting.desktopLyric?.style?.opacity + setting['list.isClickPlayList'] = setting.list?.isClickPlayList + setting['list.isShowSource'] = setting.list?.isShowSource + setting['list.isSaveScrollLocation'] = setting.list?.isSaveScrollLocation + setting['list.addMusicLocationType'] = setting.list?.addMusicLocationType + setting['common.themeId'] = setting.themeId + setting['common.isAutoTheme'] = setting.isAutoTheme + setting['common.langId'] = setting.langId + setting['common.apiSource'] = setting.apiSource + setting['common.sourceNameType'] = setting.sourceNameType + setting['common.shareType'] = setting.shareType + setting['common.isAgreePact'] = setting.isAgreePact + setting['sync.enable'] = setting.sync?.enable + setting['theme.id'] = setting.themeId + } + + return setting +} diff --git a/src/config/setting.js b/src/config/setting.js deleted file mode 100644 index 25c4431b5..000000000 --- a/src/config/setting.js +++ /dev/null @@ -1,42 +0,0 @@ -import { compareVer, objectDeepMerge } from '../utils' -import { defaultSetting, overwriteSetting } from './defaultSetting' -import apiSource from '../utils/music/api-source-info' - -export const mergeSetting = setting => { - const defaultSettingCopy = JSON.parse(JSON.stringify(defaultSetting)) - const overwriteSettingCopy = JSON.parse(JSON.stringify(overwriteSetting)) - - if (!setting) { - setting = defaultSettingCopy - } else if (compareVer(setting.version, defaultSettingCopy.version) < 0) { - objectDeepMerge(defaultSettingCopy, setting) - objectDeepMerge(defaultSettingCopy, overwriteSettingCopy) - setting = defaultSettingCopy - } - - if (!apiSource.some(api => api.id === setting.apiSource && !api.disabled)) { - const api = apiSource.find(api => !api.disabled) - if (api) setting.apiSource = api.id - } - - return setting -} - -/** - * 初始化设置 - * @param {*} setting - */ - -export const initSetting = () => { - // const { version: settingVersion, setting: newSetting } = mergeSetting(setting, electronStore_config.get('version')) - - - // newSetting.controlBtnPosition = 'right' - // electronStore_config.set('version', settingVersion) - // electronStore_config.set('setting', newSetting) - // return newSetting - return { - setting: defaultSetting, - settingVersion: defaultSetting.version, - } -} diff --git a/src/config/setting.ts b/src/config/setting.ts new file mode 100644 index 000000000..918f0efe8 --- /dev/null +++ b/src/config/setting.ts @@ -0,0 +1,114 @@ +import { storageDataPrefix, storageDataPrefixOld } from '@/config/constant' +import defaultSetting from '@/config/defaultSetting' +import { getData, removeData, saveData } from '@/plugins/storage' +import migrateSetting from './migrateSetting' +import settingState from '@/store/setting/state' +import { migrateMetaData, migrateListData } from './migrate' +import { Alert } from 'react-native' +import { exitApp } from '@/utils/tools' + +// 业务相关工具方法 + + +const primitiveType = ['string', 'boolean', 'number'] +const checkPrimitiveType = (val: any): boolean => val === null || primitiveType.includes(typeof val) + +const mergeSetting = (originSetting: LX.AppSetting, targetSetting?: Partial<LX.AppSetting> | null): { + setting: LX.AppSetting + updatedSettingKeys: Array<keyof LX.AppSetting> + updatedSetting: Partial<LX.AppSetting> +} => { + let originSettingCopy: LX.AppSetting = { ...originSetting } + // const defaultVersion = targetSettingCopy.version + const updatedSettingKeys: Array<keyof LX.AppSetting> = [] + const updatedSetting: Partial<LX.AppSetting> = {} + + if (targetSetting) { + const originSettingKeys = Object.keys(originSettingCopy) + const targetSettingKeys = Object.keys(targetSetting) + + if (originSettingKeys.length > targetSettingKeys.length) { + for (const key of targetSettingKeys as Array<keyof LX.AppSetting>) { + const targetValue: any = targetSetting[key] + const isPrimitive = checkPrimitiveType(targetValue) + // if (checkPrimitiveType(value)) { + if (!isPrimitive || targetValue == originSettingCopy[key] || originSettingCopy[key] === undefined) continue + updatedSettingKeys.push(key) + updatedSetting[key] = targetValue + // @ts-expect-error + originSettingCopy[key] = targetValue + // } else { + // if (!isPrimitive && currentValue != undefined) handleMergeSetting(value, currentValue) + // } + } + } else { + for (const key of originSettingKeys as Array<keyof LX.AppSetting>) { + const targetValue: any = targetSetting[key] + const isPrimitive = checkPrimitiveType(targetValue) + // if (checkPrimitiveType(value)) { + if (!isPrimitive || targetValue == originSettingCopy[key]) continue + updatedSettingKeys.push(key) + updatedSetting[key] = targetValue + // @ts-expect-error + originSettingCopy[key] = targetValue + // } else { + // if (!isPrimitive && currentValue != undefined) handleMergeSetting(value, currentValue) + // } + } + } + } + + return { + setting: originSettingCopy, + updatedSettingKeys, + updatedSetting, + } +} +export const updateSetting = (setting?: Partial<LX.AppSetting> | null, isInit: boolean = false) => { + let originSetting: LX.AppSetting + if (isInit) { + originSetting = { ...defaultSetting } + } else originSetting = settingState.setting + + const result = mergeSetting(originSetting, setting) + + result.setting.version = defaultSetting.version + + return result +} + +export const initSetting = async() => { + let setting: Partial<LX.AppSetting> | null = await getData(storageDataPrefix.setting) + + + // try migrate setting before v1 + if (!setting) { + const config = await getData<{ setting?: any }>(storageDataPrefixOld.setting) + if (config != null) { + setting = migrateSetting(config) + try { + await migrateListData() + await migrateMetaData() + } catch (err: any) { + Alert.alert('数据迁移失败 (Migrate data Failed)', `请加企鹅群(830125506)或到GitHub反馈,为了防止数据丢失,应用将停止运行,错误信息:\n${(err.stack ?? err.message) as string}`, [ + { + text: 'Exit', + onPress() { + exitApp() + }, + }, + ], { + cancelable: false, + }) + throw err + } + await removeData(storageDataPrefixOld.setting) + } + } + + // console.log(setting) + const updatedSetting = updateSetting(setting, true) + void saveData(storageDataPrefix.setting, updatedSetting.setting) + + return updatedSetting +} diff --git a/src/core/apiSource.ts b/src/core/apiSource.ts new file mode 100644 index 000000000..833283d05 --- /dev/null +++ b/src/core/apiSource.ts @@ -0,0 +1,34 @@ +// import { setUserApi as setUserApiAction } from '@renderer/utils/ipc' +import musicSdk from '@/utils/musicSdk' +// import apiSourceInfo from '@renderer/utils/musicSdk/api-source-info' +import { updateSetting } from './common' +import settingState from '@/store/setting/state' + + +export const setUserApi = (apiId: string) => { + if (/^user_api/.test(apiId)) { + // qualityList.value = {} + // userApi.status = false + // userApi.message = 'initing' + + // await setUserApiAction(apiId).then(() => { + // apiSource.value = apiId + // }).catch(err => { + // console.log(err) + // let api = apiSourceInfo.find(api => !api.disabled) + // if (!api) return + // apiSource.value = api.id + // if (api.id != appSetting['common.apiSource']) setApiSource(api.id) + // }) + } else { + // @ts-expect-error + global.lx.qualityList = musicSdk.supportQuality[apiId] as LX.QualityList + // apiSource.value = apiId + // void setUserApiAction(apiId) + } + + if (apiId != settingState.setting['common.apiSource']) { + updateSetting({ 'common.apiSource': apiId }) + } +} + diff --git a/src/core/common.ts b/src/core/common.ts new file mode 100644 index 000000000..4fd983525 --- /dev/null +++ b/src/core/common.ts @@ -0,0 +1,80 @@ +import { hideDesktopLyric } from './desktopLyric' +import { exitApp as utilExitApp } from '@/utils/nativeModules/utils' +import { destroy as destroyPlayer } from '@/plugins/player/utils' +import { initSetting as initAppSetting } from '@/config/setting' +import { setLanguage as applyLanguage } from '@/lang/i18n' + +import settingActions from '@/store/setting/action' +import settingState from '@/store/setting/state' +import commonActions from '@/store/common/action' +import commonState, { type InitState as CommonStateType } from '@/store/common/state' + +import { storageDataPrefix } from '@/config/constant' +import { saveData } from '@/plugins/storage' +import { throttle } from '@/utils/common' +import { saveFontSize, saveViewPrevState } from '@/utils/data' +import { showPactModal as handleShowPactModal } from '@/navigation' + + +const throttleSaveSetting = throttle(() => { + void saveData(storageDataPrefix.setting, settingState.setting) +}) + +/** + * 初始化设置 + */ +export const initSetting = async() => { + const setting = (await initAppSetting()).setting + settingActions.updateSetting(setting) + return setting +} + +/** + * 更新设置 + * @param setting 新设置 + */ +export const updateSetting = (setting: Partial<LX.AppSetting>) => { + settingActions.updateSetting(setting) + throttleSaveSetting() +} + +export const setLanguage = (locale: Parameters<typeof applyLanguage>[0]) => { + updateSetting({ 'common.langId': locale }) + applyLanguage(locale) +} + + +let isDestroying = false +export const exitApp = () => { + if (isDestroying) return + isDestroying = true + Promise.all([ + hideDesktopLyric(), + destroyPlayer(), + ]).finally(() => { + isDestroying = false + utilExitApp() + }) +} + +export const setFontSize = (size: number) => { + commonActions.setFontSize(size) + void saveFontSize(size) +} + +export const setComponentId = (name: keyof CommonStateType['componentIds'], id: string) => { + commonActions.setComponentId(name, id) +} +export const removeComponentId = (name: string) => { + commonActions.removeComponentId(name) +} + +export const setNavActiveId = (id: Parameters<typeof commonActions.setNavActiveId>['0']) => { + if (id == commonState.navActiveId) return + commonActions.setNavActiveId(id) + saveViewPrevState({ id }) +} + +export const showPactModal = () => { + handleShowPactModal() +} diff --git a/src/core/desktopLyric.ts b/src/core/desktopLyric.ts new file mode 100644 index 000000000..c6fa26638 --- /dev/null +++ b/src/core/desktopLyric.ts @@ -0,0 +1,91 @@ +import { + hideLyric, + showLyric, + setLyric, + play, + pause, + toggleTranslation, + toggleRoma, + toggleLock, + setColor, + setAlpha, + setTextSize, + setShowToggleAnima, + setSingleLine, + setPosition, + setMaxLineNum, + setWidth, + setLyricTextPosition, + checkOverlayPermission, + openOverlayPermissionActivity, + onPositionChange, +} from '@/utils/nativeModules/lyricDesktop' +import settingState from '@/store/setting/state' +import playerState from '@/store/player/state' +import { tranditionalize } from '@/utils/simplify-chinese-main' +import { getPosition } from '@/plugins/player' + +export const showDesktopLyric = async() => { + const setting = settingState.setting + await showLyric({ + isShowToggleAnima: setting['desktopLyric.showToggleAnima'], + isSingleLine: setting['desktopLyric.isSingleLine'], + isLock: setting['desktopLyric.isLock'], + unplayColor: setting['desktopLyric.style.lyricUnplayColor'], + playedColor: setting['desktopLyric.style.lyricPlayedColor'], + shadowColor: setting['desktopLyric.style.lyricShadowColor'], + opacity: setting['desktopLyric.style.opacity'], + textSize: setting['desktopLyric.style.fontSize'], + width: setting['desktopLyric.width'], + maxLineNum: setting['desktopLyric.maxLineNum'], + positionX: setting['desktopLyric.position.x'], + positionY: setting['desktopLyric.position.y'], + textPositionX: setting['desktopLyric.textPosition.x'], + textPositionY: setting['desktopLyric.textPosition.y'], + }) + let lrc = playerState.musicInfo.lrc ?? '' + let tlrc = playerState.musicInfo.tlrc ?? '' + let rlrc = playerState.musicInfo.rlrc ?? '' + if (setting['player.isS2t']) { + lrc = tranditionalize(lrc) + tlrc = tranditionalize(tlrc) + } + await setLyric(lrc, tlrc, rlrc) + if (playerState.isPlay && !global.lx.gettingUrlId) { + void getPosition().then(position => { + void play(position * 1000) + }) + } +} + +export const hideDesktopLyric = async() => { + return hideLyric() +} + +export const playDesktopLyric = play +export const pauseDesktopLyric = pause +export const setDesktopLyric = setLyric +export const toggleDesktopLyricTranslation = toggleTranslation +export const toggleDesktopLyricRoma = toggleRoma +export const toggleDesktopLyricLock = toggleLock +export const setDesktopLyricColor = async(unplayColor: string | null, playedColor: string | null, shadowColor: string | null) => { + return setColor(unplayColor ?? settingState.setting['desktopLyric.style.lyricUnplayColor'], + playedColor ?? settingState.setting['desktopLyric.style.lyricPlayedColor'], + shadowColor ?? settingState.setting['desktopLyric.style.lyricShadowColor'], + ) +} +export const setDesktopLyricAlpha = setAlpha +export const setDesktopLyricTextSize = setTextSize +export const setShowDesktopLyricToggleAnima = setShowToggleAnima +export const setDesktopLyricSingleLine = setSingleLine +export const setDesktopLyricPosition = setPosition +export const setDesktopLyricMaxLineNum = setMaxLineNum +export const setDesktopLyricWidth = setWidth +export const setDesktopLyricTextPosition = async(x: LX.AppSetting['desktopLyric.textPosition.x'] | null, y: LX.AppSetting['desktopLyric.textPosition.y'] | null) => { + return setLyricTextPosition(x ?? settingState.setting['desktopLyric.textPosition.x'], y ?? settingState.setting['desktopLyric.textPosition.y']) +} +export const checkDesktopLyricOverlayPermission = checkOverlayPermission +export const openDesktopLyricOverlayPermissionActivity = openOverlayPermissionActivity +export const onDesktopLyricPositionChange = onPositionChange + + diff --git a/src/core/hotSearch.ts b/src/core/hotSearch.ts new file mode 100644 index 000000000..aa6732ea2 --- /dev/null +++ b/src/core/hotSearch.ts @@ -0,0 +1,35 @@ +import hotSearchState, { type Source } from '@/store/hotSearch/state' +import hotSearchActions, { type Lists } from '@/store/hotSearch/action' +import musicSdk from '@/utils/musicSdk' + +export const getList = async(source: Source): Promise<string[]> => { + if (source == 'all') { + let task = [] + for (const source of hotSearchState.sources) { + if (source == 'all') continue + task.push( + hotSearchState.sourceList[source]?.length + ? Promise.resolve({ source, list: hotSearchState.sourceList[source] as Lists[number]['list'] }) + : ((musicSdk[source]?.hotSearch.getList() as Promise<Lists[number]>) ?? Promise.reject(new Error('source not found: ' + source))).catch((err: any) => { + console.log(err) + return { source, list: [] } + }), + ) + } + return Promise.all(task).then((results: Lists) => { + return hotSearchActions.setList(source, results) + }) + } else { + if (hotSearchState.sourceList[source]?.length) return hotSearchState.sourceList[source] as string[] + if (!musicSdk[source]?.hotSearch) { + hotSearchActions.setList(source, []) + return [] + } + return musicSdk[source]?.hotSearch.getList().catch((err: any) => { + console.log(err) + return { source, list: [] } + }).then(data => hotSearchActions.setList(source, data.list)) + } +} + + diff --git a/src/core/init/dataInit.ts b/src/core/init/dataInit.ts new file mode 100644 index 000000000..5d7c759d4 --- /dev/null +++ b/src/core/init/dataInit.ts @@ -0,0 +1,30 @@ +// import { getPlayInfo } from '@/utils/data' +// import { log } from '@/utils/log' +import { init as musicSdkInit } from '@/utils/musicSdk' +import { getUserLists, setUserList } from '@/core/list' +import { setNavActiveId } from '../common' +import { getViewPrevState } from '@/utils/data' +// import { play, playList } from '../player/player' + +// const initPrevPlayInfo = async(appSetting: LX.AppSetting) => { +// const info = await getPlayInfo() +// global.lx.restorePlayInfo = null +// if (!info?.listId || info.index < 0) return +// const list = await getListMusics(info.listId) +// if (!list[info.index]) return +// global.lx.restorePlayInfo = info +// await playList(info.listId, info.index) + +// if (appSetting['player.startupAutoPlay']) setTimeout(play) +// } + +export default async(appSetting: LX.AppSetting) => { + // await Promise.all([ + // initUserApi(), // 自定义API + // ]).catch(err => log.error(err)) + void musicSdkInit() // 初始化音乐sdk + + setUserList(await getUserLists()) // 获取用户列表 + setNavActiveId((await getViewPrevState()).id) + // await initPrevPlayInfo(appSetting).catch(err => log.error(err)) // 初始化上次的歌曲播放信息 +} diff --git a/src/core/init/i18n.ts b/src/core/init/i18n.ts new file mode 100644 index 000000000..d06f88156 --- /dev/null +++ b/src/core/init/i18n.ts @@ -0,0 +1,21 @@ +import { createI18n } from '@/lang/i18n' +import type { I18n } from '@/lang/i18n' +import { deviceLanguage } from '@/utils/tools' +import { setLanguage, updateSetting } from '@/core/common' + + +export default async(setting: LX.AppSetting) => { + let lang = setting['common.langId'] + + global.i18n = createI18n() + + if (!lang || !global.i18n.availableLocales.includes(lang)) { + if (typeof deviceLanguage == 'string' && global.i18n.availableLocales.includes(deviceLanguage as I18n['locale'])) { + lang = deviceLanguage as I18n['locale'] + } else { + lang = 'en_us' + } + updateSetting({ 'common.langId': lang }) + } + setLanguage(lang) +} diff --git a/src/core/init/index.ts b/src/core/init/index.ts new file mode 100644 index 000000000..03fdcc3dc --- /dev/null +++ b/src/core/init/index.ts @@ -0,0 +1,50 @@ +import { initSetting, showPactModal } from '@/core/common' +import registerPlaybackService from '@/plugins/player/service' +import initTheme from './theme' +import initI18n from './i18n' +import initPlayer from './player' +import dataInit from './dataInit' +import initSync from './sync' +// import syncSetting from './syncSetting' +import { setUserApi } from '@/core/apiSource' +import commonActions from '@/store/common/action' +import settingState from '@/store/setting/state' +import { checkUpdate } from '@/core/version' + +let isFirstPush = true +const handlePushedHomeScreen = () => { + if (settingState.setting['common.isAgreePact']) { + if (isFirstPush) { + isFirstPush = false + void checkUpdate() + } + } else { + if (isFirstPush) isFirstPush = false + showPactModal() + } +} + +let isInited = false +export default async() => { + if (isInited) return handlePushedHomeScreen + commonActions.setFontSize(global.lx.fontSize) + const setting = await initSetting() + // console.log(setting) + + await initTheme(setting) + await initI18n(setting) + + setUserApi(setting['common.apiSource']) + + registerPlaybackService() + await initPlayer(setting) + await dataInit(setting) + + void initSync(setting) + + // syncSetting() + + isInited = true + + return handlePushedHomeScreen +} diff --git a/src/core/init/player/index.ts b/src/core/init/player/index.ts new file mode 100644 index 000000000..759bdc411 --- /dev/null +++ b/src/core/init/player/index.ts @@ -0,0 +1,17 @@ +import initPlayer from './player' +import initPlayInfo from './playInfo' +import initPlayStatus from './playStatus' +import initPlayerEvent from './playerEvent' +import initWatchList from './watchList' +import initPlayProgress from './playProgress' +import initLyric from './lyric' + +export default async(setting: LX.AppSetting) => { + await initPlayer(setting) + await initPlayInfo(setting) + initPlayStatus() + initPlayerEvent() + initWatchList() + initPlayProgress() + await initLyric(setting) +} diff --git a/src/core/init/player/lyric.ts b/src/core/init/player/lyric.ts new file mode 100644 index 000000000..0dff57862 --- /dev/null +++ b/src/core/init/player/lyric.ts @@ -0,0 +1,29 @@ +import { init as initLyricPlayer, toggleTranslation, toggleRoma, play, pause, stop, setLyric } from '@/core/lyric' +import { updateSetting } from '@/core/common' +import { onDesktopLyricPositionChange, showDesktopLyric } from '@/core/desktopLyric' + +export default async(setting: LX.AppSetting) => { + await initLyricPlayer() + toggleTranslation(setting['player.isShowLyricTranslation']) + toggleRoma(setting['player.isShowLyricRoma']) + + if (setting['desktopLyric.enable']) { + showDesktopLyric().catch(() => { + updateSetting({ 'desktopLyric.enable': false }) + }) + } + onDesktopLyricPositionChange(position => { + updateSetting({ + 'desktopLyric.position.x': position.x, + 'desktopLyric.position.y': position.y, + }) + }) + + + global.app_event.on('play', play) + global.app_event.on('pause', pause) + global.app_event.on('stop', stop) + global.app_event.on('error', pause) + global.app_event.on('musicToggled', stop) + global.app_event.on('lyricUpdated', setLyric) +} diff --git a/src/core/init/player/playInfo.ts b/src/core/init/player/playInfo.ts new file mode 100644 index 000000000..47656ea99 --- /dev/null +++ b/src/core/init/player/playInfo.ts @@ -0,0 +1,45 @@ +import { getPlayInfo } from '@/utils/data' +import { getListMusics } from '@/core/list' +import { playList, play } from '@/core/player/player' + + +export default async(setting: LX.AppSetting) => { + const info = await getPlayInfo() + global.lx.restorePlayInfo = null + if (!info?.listId || info.index < 0) return + + const list = await getListMusics(info.listId) + if (!list[info.index]) return + global.lx.restorePlayInfo = info + + await playList(info.listId, info.index) + + if (setting['player.startupAutoPlay']) setTimeout(play) + + + // if (!info.list || !info.list[info.index]) { + // const info2 = { ...info } + // if (info2.list) { + // info2.music = info2.list[info2.index]?.name + // info2.list = info2.list.length + // } + // toast('恢复播放数据失败,请去错误日志查看', 'long') + // log.warn('Restore Play Info failed: ', JSON.stringify(info2, null, 2)) + + // return + // } + + // let setting = store.getState().common.setting + // global.restorePlayInfo = { + // info, + // startupAutoPlay: setting.startupAutoPlay, + // } + + // store.dispatch(playerAction.setList({ + // list: { + // list: info.list, + // id: info.listId, + // }, + // index: info.index, + // })) +} diff --git a/src/core/init/player/playProgress.ts b/src/core/init/player/playProgress.ts new file mode 100644 index 000000000..fcfc4e224 --- /dev/null +++ b/src/core/init/player/playProgress.ts @@ -0,0 +1,154 @@ +import { updateListMusics } from '@/core/list' +import { setMaxplayTime, setNowPlayTime } from '@/core/player/progress' +import { setCurrentTime, getDuration, getPosition } from '@/plugins/player' +import { formatPlayTime2 } from '@/utils/common' +import { savePlayInfo } from '@/utils/data' +import { throttleBackgroundTimer } from '@/utils/tools' +import BackgroundTimer from 'react-native-background-timer' +import playerState from '@/store/player/state' +import settingState from '@/store/setting/state' + + +const delaySavePlayInfo = throttleBackgroundTimer(savePlayInfo, 2000) + +export default () => { + // const updateMusicInfo = useCommit('list', 'updateMusicInfo') + + let updateTimeout: number | null = null + + const getCurrentTime = () => { + void getPosition().then(position => { + if (!position || !playerState.isPlay) return + setNowPlayTime(position) + + if (settingState.setting['player.isSavePlayTime'] && !playerState.playMusicInfo.isTempPlay) { + delaySavePlayInfo({ + time: position, + maxTime: playerState.progress.maxPlayTime, + listId: playerState.playMusicInfo.listId as string, + index: playerState.playInfo.playIndex, + }) + } + }) + } + const getMaxTime = async() => { + setMaxplayTime(await getDuration()) + + if (playerState.playMusicInfo.musicInfo && 'source' in playerState.playMusicInfo.musicInfo && !playerState.playMusicInfo.musicInfo.interval) { + // console.log(formatPlayTime2(playProgress.maxPlayTime)) + + if (playerState.playMusicInfo.listId) { + void updateListMusics([{ + id: playerState.playMusicInfo.listId, + musicInfo: { + ...playerState.playMusicInfo.musicInfo, + interval: formatPlayTime2(playerState.progress.maxPlayTime), + }, + }]) + } + } + } + + const clearUpdateTimeout = () => { + if (!updateTimeout) return + BackgroundTimer.clearInterval(updateTimeout) + updateTimeout = null + } + const startUpdateTimeout = () => { + clearUpdateTimeout() + updateTimeout = BackgroundTimer.setInterval(() => { + getCurrentTime() + }, 1000) + getCurrentTime() + } + + const setProgress = (time: number, maxTime?: number) => { + if (!playerState.musicInfo.id) return + // console.log('setProgress', time, maxTime) + setNowPlayTime(time) + void setCurrentTime(time) + + if (maxTime != null) setMaxplayTime(maxTime) + + // if (!isPlay) audio.play() + } + + + const handlePlay = () => { + void getMaxTime() + // prevProgressStatus = 'normal' + // handleSetTaskBarState(playProgress.progress, prevProgressStatus) + startUpdateTimeout() + } + const handlePause = () => { + // prevProgressStatus = 'paused' + // handleSetTaskBarState(playProgress.progress, prevProgressStatus) + // clearBufferTimeout() + clearUpdateTimeout() + } + + const handleStop = () => { + clearUpdateTimeout() + setNowPlayTime(0) + setMaxplayTime(0) + // prevProgressStatus = 'none' + // handleSetTaskBarState(playProgress.progress, prevProgressStatus) + } + + const handleError = () => { + // if (!restorePlayTime) restorePlayTime = getCurrentTime() // 记录出错的播放时间 + // console.log('handleError') + // prevProgressStatus = 'error' + // handleSetTaskBarState(playProgress.progress, prevProgressStatus) + clearUpdateTimeout() + } + + + const handleSetPlayInfo = () => { + // restorePlayTime = playProgress.nowPlayTime + // void setCurrentTime(playerState.progress.nowPlayTime) + // setMaxplayTime(playProgress.maxPlayTime) + handlePause() + if (!playerState.playMusicInfo.isTempPlay) { + delaySavePlayInfo({ + time: playerState.progress.nowPlayTime, + maxTime: playerState.progress.maxPlayTime, + listId: playerState.playMusicInfo.listId as string, + index: playerState.playInfo.playIndex, + }) + } + } + + // watch(() => playerState.progress.nowPlayTime, (newValue, oldValue) => { + // if (settingState.setting['player.isSavePlayTime'] && !playMusicInfo.isTempPlay) { + // delaySavePlayInfo({ + // time: newValue, + // maxTime: playerState.progress.maxPlayTime, + // listId: playMusicInfo.listId as string, + // index: playInfo.playIndex, + // }) + // } + // }) + // watch(() => playerState.progress.maxPlayTime, maxPlayTime => { + // if (!playMusicInfo.isTempPlay) { + // delaySavePlayInfo({ + // time: playerState.progress.nowPlayTime, + // maxTime: maxPlayTime, + // listId: playMusicInfo.listId as string, + // index: playInfo.playIndex, + // }) + // } + // }) + + global.app_event.on('play', handlePlay) + global.app_event.on('pause', handlePause) + global.app_event.on('stop', handleStop) + global.app_event.on('error', handleError) + global.app_event.on('setProgress', setProgress) + // global.app_event.on(eventPlayerNames.restorePlay, handleRestorePlay) + // global.app_event.on('playerLoadeddata', handleLoadeddata) + // global.app_event.on('playerCanplay', handleCanplay) + // global.app_event.on('playerWaiting', handleWating) + // global.app_event.on('playerEmptied', handleEmpied) + global.app_event.on('musicToggled', handleSetPlayInfo) +} diff --git a/src/core/init/player/playStatus.ts b/src/core/init/player/playStatus.ts new file mode 100644 index 000000000..f88067b7e --- /dev/null +++ b/src/core/init/player/playStatus.ts @@ -0,0 +1,82 @@ +// import { LIST_ID_LOVE } from '@/config/constant' + +import { updateMetaData } from '@/plugins/player' +import playerState from '@/store/player/state' + +export default () => { + // const setVisibleDesktopLyric = useCommit('setVisibleDesktopLyric') + // const setLockDesktopLyric = useCommit('setLockDesktopLyric') + + const buttons = { + empty: true, + collect: false, + play: false, + prev: true, + next: true, + lrc: false, + lockLrc: false, + } + const setButtons = () => { + // setPlayerAction(buttons) + if (!playerState.playMusicInfo.musicInfo) return + void updateMetaData(playerState.musicInfo, playerState.isPlay) + } + // const updateCollectStatus = async() => { + // // let status = !!playMusicInfo.musicInfo && await checkListExistMusic(LIST_ID_LOVE, playerState.playMusicInfo.musicInfo.id) + // // if (buttons.collect == status) return false + // // buttons.collect = status + // return true + // } + + const handlePlay = () => { + // if (buttons.empty) buttons.empty = false + if (buttons.play) return + buttons.play = true + setButtons() + } + const handlePause = () => { + // if (buttons.empty) buttons.empty = false + if (!buttons.play) return + buttons.play = false + setButtons() + } + // const handleStop = () => { + // // if (playerState.playMusicInfo.musicInfo != null) return + // // if (buttons.collect) buttons.collect = false + // // buttons.empty = true + // setButtons() + // } + // const handleSetPlayInfo = () => { + // void updateCollectStatus().then(isExist => { + // if (isExist) setButtons() + // }) + // } + // const handleSetTaskbarThumbnailClip = (clip) => { + // setTaskbarThumbnailClip(clip) + // } + // const throttleListChange = throttle(async listIds => { + // if (!listIds.includes(loveList.id)) return + // if (await updateCollectStatus()) setButtons() + // }) + // const updateSetting = () => { + // const setting = store.getters.setting + // buttons.lrc = setting.desktopLyric.enable + // buttons.lockLrc = setting.desktopLyric.isLock + // setButtons() + // } + global.app_event.on('play', handlePlay) + global.app_event.on('pause', handlePause) + global.app_event.on('stop', handlePause) + // global.app_event.on('musicToggled', handleSetPlayInfo) + // window.app_event.on(eventTaskbarNames.setTaskbarThumbnailClip, handleSetTaskbarThumbnailClip) + // window.app_event.on('myListMusicUpdate', throttleListChange) + + return async() => { + // const setting = store.getters.setting + // buttons.lrc = setting.desktopLyric.enable + // buttons.lockLrc = setting.desktopLyric.isLock + // await updateCollectStatus() + // if (playMusicInfo.musicInfo != null) buttons.empty = false + setButtons() + } +} diff --git a/src/core/init/player/player.ts b/src/core/init/player/player.ts new file mode 100644 index 000000000..9fbc50568 --- /dev/null +++ b/src/core/init/player/player.ts @@ -0,0 +1,60 @@ +import { addPlayedList, clearPlayedList } from '@/core/player/playedList' +import { pause, playNext } from '@/core/player/player' +import { setStatusText, setIsPlay } from '@/core/player/playStatus' +// import { resetPlayerMusicInfo } from '@/core/player/playInfo' +import { setStop } from '@/plugins/player' +import { delayUpdateMusicInfo } from '@/plugins/player/playList' +import playerState from '@/store/player/state' + + +export default async(setting: LX.AppSetting) => { + const setPlayStatus = () => { + setIsPlay(true) + } + const setPauseStatus = () => { + setIsPlay(false) + if (global.lx.isPlayedStop) void pause() + } + + const handleEnded = () => { + // setTimeout(() => { + if (global.lx.isPlayedStop) { + setStatusText(global.i18n.t('player__end')) + return + } + // resetPlayerMusicInfo() + // global.app_event.stop() + setStatusText(global.i18n.t('player__end')) + void playNext(true) + // }) + } + + const setStopStatus = () => { + setIsPlay(false) + setStatusText('') + void setStop() + } + + const updatePic = () => { + if (playerState.playMusicInfo.musicInfo) { + delayUpdateMusicInfo(playerState.musicInfo) + } + } + + const handleConfigUpdated: typeof global.state_event.configUpdated = (keys, settings) => { + if (!keys.includes('player.togglePlayMethod')) return + const newValue = settings['player.togglePlayMethod'] + if (playerState.playedList.length) clearPlayedList() + const playMusicInfo = playerState.playMusicInfo + if (newValue == 'random' && playMusicInfo.musicInfo && !playMusicInfo.isTempPlay) addPlayedList({ ...(playMusicInfo as LX.Player.PlayMusicInfo) }) + } + + + global.app_event.on('play', setPlayStatus) + global.app_event.on('pause', setPauseStatus) + global.app_event.on('error', setPauseStatus) + global.app_event.on('stop', setStopStatus) + global.app_event.on('playerEnded', handleEnded) + global.app_event.on('picUpdated', updatePic) + global.state_event.on('configUpdated', handleConfigUpdated) +} diff --git a/src/core/init/player/playerEvent.ts b/src/core/init/player/playerEvent.ts new file mode 100644 index 000000000..e97a4787b --- /dev/null +++ b/src/core/init/player/playerEvent.ts @@ -0,0 +1,137 @@ +import { playNext, setMusicUrl } from '@/core/player/player' +import { setStatusText } from '@/core/player/playStatus' +import { getPosition, isEmpty, setStop } from '@/plugins/player' +import { isActive } from '@/utils/tools' +import BackgroundTimer from 'react-native-background-timer' +import playerState from '@/store/player/state' +import { setNowPlayTime } from '@/core/player/progress' + + +export default () => { + let retryNum = 0 + let prevTimeoutId: string | null = null + + let loadingTimeout: number | null = null + let delayNextTimeout: number | null = null + const startLoadingTimeout = () => { + // console.log('start load timeout') + clearLoadingTimeout() + loadingTimeout = BackgroundTimer.setTimeout(() => { + // if (global.lx.isPlayedStop) { + // prevTimeoutId = null + // setStatusText('') + // return + // } + + // 如果加载超时,则尝试刷新URL + if (prevTimeoutId == playerState.musicInfo.id) { + prevTimeoutId = null + void playNext(true) + } else { + prevTimeoutId = playerState.musicInfo.id + if (playerState.playMusicInfo.musicInfo) setMusicUrl(playerState.playMusicInfo.musicInfo, true) + } + }, 25000) + } + const clearLoadingTimeout = () => { + if (!loadingTimeout) return + // console.log('clear load timeout') + BackgroundTimer.clearTimeout(loadingTimeout) + loadingTimeout = null + } + + const clearDelayNextTimeout = () => { + // console.log(this.delayNextTimeout) + if (!delayNextTimeout) return + BackgroundTimer.clearTimeout(delayNextTimeout) + delayNextTimeout = null + } + const addDelayNextTimeout = () => { + clearDelayNextTimeout() + delayNextTimeout = BackgroundTimer.setTimeout(() => { + if (global.lx.isPlayedStop) { + setStatusText('') + return + } + void playNext(true) + }, 5000) + } + + const handleLoadstart = () => { + if (global.lx.isPlayedStop) return + startLoadingTimeout() + setStatusText(global.i18n.t('player__loading')) + } + + // const handleLoadeddata = () => { + // setStatusText(global.i18n.t('player__loading')) + // } + + // const handleCanplay = () => { + // setStatusText('') + // } + + const handlePlaying = () => { + setStatusText('') + clearLoadingTimeout() + } + + const handleEmpied = () => { + clearDelayNextTimeout() + clearLoadingTimeout() + } + + const handleWating = () => { + setStatusText(global.i18n.t('player__buffering')) + } + + const handleError = () => { + if (!playerState.musicInfo.id) return + clearLoadingTimeout() + if (global.lx.isPlayedStop) return + if (playerState.playMusicInfo.musicInfo && retryNum < 2) { // 若音频URL无效则尝试刷新2次URL + let musicInfo = playerState.playMusicInfo.musicInfo + getPosition().then((position) => { + if (position) setNowPlayTime(position) + }).finally(() => { + // console.log(this.retryNum) + if (playerState.playMusicInfo.musicInfo !== musicInfo) return + retryNum++ + setMusicUrl(playerState.playMusicInfo.musicInfo, true) + setStatusText(global.i18n.t('player__refresh_url')) + }) + return + } + if (!isEmpty()) void setStop() + + if (isActive()) { + setStatusText(global.i18n.t('player__error')) + setTimeout(addDelayNextTimeout) + } else { + console.warn('error skip to next') + void playNext(true) + } + } + + const handleSetPlayInfo = () => { + retryNum = 0 + prevTimeoutId = null + clearDelayNextTimeout() + clearLoadingTimeout() + } + + // const handlePlayedStop = () => { + // clearDelayNextTimeout() + // clearLoadingTimeout() + // } + + + global.app_event.on('playerLoadstart', handleLoadstart) + // global.app_event.on('playerLoadeddata', handleLoadeddata) + // global.app_event.on('playerCanplay', handleCanplay) + global.app_event.on('playerPlaying', handlePlaying) + global.app_event.on('playerWaiting', handleWating) + global.app_event.on('playerEmptied', handleEmpied) + global.app_event.on('playerError', handleError) + global.app_event.on('musicToggled', handleSetPlayInfo) +} diff --git a/src/core/init/player/watchList.ts b/src/core/init/player/watchList.ts new file mode 100644 index 000000000..b4c3d4b4b --- /dev/null +++ b/src/core/init/player/watchList.ts @@ -0,0 +1,42 @@ +import { playNext } from '@/core/player/player' +import { updatePlayIndex } from '@/core/player/playInfo' +import { throttleBackgroundTimer } from '@/utils/tools' +import playerState from '@/store/player/state' + +const changedListIds = new Set<string | null>() + +export default () => { + const throttleListChange = throttleBackgroundTimer(() => { + const isSkip = !changedListIds.has(playerState.playInfo.playerListId) && !changedListIds.has(playerState.playMusicInfo.listId) + changedListIds.clear() + if (isSkip) return + + const { playIndex } = updatePlayIndex() + if (playIndex < 0) { // 歌曲被移除 + // if (global.lx.isPlayedStop) { + // stop() + // setTimeout(() => { + // setPlayMusicInfo(null, null) + // }) + // } else + if (!playerState.playMusicInfo.isTempPlay) { + // console.log('current music removed') + void playNext(true) + } + } + }) + + const handleListChange = (listIds: string[]) => { + for (const id of listIds) { + changedListIds.add(id) + } + throttleListChange() + } + + const handleDownloadListChange = () => { + handleListChange(['download']) + } + + global.app_event.on('myListMusicUpdate', handleListChange) + global.app_event.on('downloadListUpdate', handleDownloadListChange) +} diff --git a/src/core/init/sync.ts b/src/core/init/sync.ts new file mode 100644 index 000000000..f44b390e6 --- /dev/null +++ b/src/core/init/sync.ts @@ -0,0 +1,17 @@ +import { connect, SYNC_CODE } from '@/plugins/sync' +import { updateSetting } from '@/core/common' + + +export default async(setting: LX.AppSetting) => { + if (!setting['sync.enable']) return + + connect().catch(err => { + switch (err.message) { + case SYNC_CODE.unknownServiceAddress: + case SYNC_CODE.missingAuthCode: + case SYNC_CODE.authFailed: + updateSetting({ 'sync.enable': false }) + break + } + }) +} diff --git a/src/core/init/syncSetting.ts b/src/core/init/syncSetting.ts new file mode 100644 index 000000000..cd3b39f17 --- /dev/null +++ b/src/core/init/syncSetting.ts @@ -0,0 +1,26 @@ +import musicSdk from '@/utils/musicSdk' +import commonActions from '@/store/common/action' +import settingState from '@/store/setting/state' + +const handleUpdateSourceNmaes = () => { + const prefix = settingState.setting['common.sourceNameType'] == 'real' ? 'source_' : 'source_alias_' + const sourceNames: Record<LX.OnlineSource | 'all', string> = { + kw: 'kw', + tx: 'tx', + kg: 'kg', + mg: 'mg', + wy: 'wy', + all: global.i18n.t(prefix + 'all' as any), + } + for (const { id } of musicSdk.sources) { + sourceNames[id as LX.OnlineSource] = global.i18n.t(prefix + id as any) + } + commonActions.setSourceNames(sourceNames) +} + +export default () => { + const handleConfigUpdated = (keys: Array<keyof LX.AppSetting>) => { + if (keys.includes('common.sourceNameType')) handleUpdateSourceNmaes() + } + global.state_event.on('configUpdated', handleConfigUpdated) +} diff --git a/src/core/init/theme.ts b/src/core/init/theme.ts new file mode 100644 index 000000000..8378237bd --- /dev/null +++ b/src/core/init/theme.ts @@ -0,0 +1,34 @@ + +import { getAppearance, getIsSupportedAutoTheme, onAppearanceChange } from '@/utils/tools' +import { setShouldUseDarkColors, applyTheme } from '@/core/theme' +import { getTheme } from '@/theme/themes/index' +import settingState from '@/store/setting/state' +// import { Dimensions, PixelRatio } from 'react-native' + + +export default async(setting: LX.AppSetting) => { + setShouldUseDarkColors(getAppearance() == 'dark') + applyTheme(await getTheme()) + + if (getIsSupportedAutoTheme()) { + onAppearanceChange(color => { + setShouldUseDarkColors((color ?? 'light') == 'dark') + if (settingState.setting['common.isAutoTheme']) void getTheme().then(applyTheme) + }) + } + + // onDimensionChange(({ window }) => { + // let screenW = window.width + // let screenH = window.height + // if (screenW > screenH) { + // const temp = screenW + // screenW = screenH + // screenH = temp + // } + // global.lx.windowInfo.screenW = screenW + // global.lx.windowInfo.screenH = screenH + // global.lx.windowInfo.screenPxW = PixelRatio.getPixelSizeForLayoutSize(screenW) + // global.lx.windowInfo.screenPxH = PixelRatio.getPixelSizeForLayoutSize(screenH) + // console.log('change', global.lx.windowInfo) + // }) +} diff --git a/src/core/leaderboard.ts b/src/core/leaderboard.ts new file mode 100644 index 000000000..d0fc739c3 --- /dev/null +++ b/src/core/leaderboard.ts @@ -0,0 +1,183 @@ +import leaderboardState, { type Board, type ListDetailInfo } from '@/store/leaderboard/state' +import leaderboardActions from '@/store/leaderboard/action' +import { deduplicationList, toNewMusicInfo } from '@/utils' +import musicSdk from '@/utils/musicSdk' + +/** + * 获取排行榜内单页歌曲 + * @param id 排行榜id {souce}__{bangId} + * @param isRefresh 是否跳过缓存 + * @returns + */ +export const setListDetailInfo = (id: string) => { + clearListDetail() + const [source, bangId] = id.split('__') as [LX.OnlineSource, string] + leaderboardActions.setListDetailInfo(source, bangId) +} +export const setListDetail = (result: ListDetailInfo, id: string, page: number) => { + return leaderboardActions.setListDetail(result, id, page) +} + +export const clearListDetail = () => { + leaderboardActions.clearListDetail() +} + +const setBoard = (board: Board, source: LX.OnlineSource) => { + leaderboardActions.setBoard(board, source) +} + +interface PageCache { data: ListDetailInfo, sourcePage: number } +type CacheValue = Map<string, PageCache | ListDetailInfo['list']> + +const cache = new Map<string, CacheValue>() +const LIST_LOAD_LIMIT = 30 + +export const getBoardsList = async(source: LX.OnlineSource) => { + // const source = (await getLeaderboardSetting()).source as LX.OnlineSource + if (leaderboardState.boards[source]) return leaderboardState.boards[source]!.list + const board = await (musicSdk[source]?.leaderboard.getBoards() as Promise<Board>) + setBoard(board, source) + return leaderboardState.boards[source]!.list +} + +/** + * 获取排行榜内单页分页歌曲(用于在本地控制每页大小) + * @param source 源 + * @param bangId 排行榜id + * @param page 页数 + * @returns + */ +const getListLimit = async(source: LX.OnlineSource, bangId: string, page: number): Promise<ListDetailInfo> => { + const listKey = `${source}__${bangId}` + const prevPageKey = `${source}__${bangId}__${page - 1}` + const tempListKey = `${source}__${bangId}__temp` + + let listCache = cache.get(listKey) as CacheValue + if (!listCache) cache.set(listKey, listCache = new Map()) + let sourcePage = 0 + { + const prevPageData = listCache.get(prevPageKey) as PageCache + if (prevPageData) sourcePage = prevPageData.sourcePage + } + + return musicSdk[source]?.leaderboard.getList(bangId, sourcePage + 1).then((result: ListDetailInfo) => { + if (listCache !== cache.get(listKey)) return + result.list = deduplicationList(result.list.map(m => toNewMusicInfo(m)) as LX.Music.MusicInfoOnline[]) + let p = page + const tempList = listCache.get(tempListKey) as ListDetailInfo['list'] + if (tempList) { + listCache.delete(tempListKey) + listCache.set(`${source}__${bangId}__${p}`, { + data: { + ...result, + list: [...tempList, ...result.list.splice(0, LIST_LOAD_LIMIT - tempList.length)], + page: p, + limit: LIST_LOAD_LIMIT, + }, + sourcePage, + }) + p++ + } + sourcePage++ + do { + if (result.list.length < LIST_LOAD_LIMIT && sourcePage < Math.ceil(result.total / result.limit)) { + listCache.set(tempListKey, result.list.splice(0, LIST_LOAD_LIMIT)) + break + } + listCache.set(`${source}__${bangId}__${p}`, { + data: { + ...result, + list: result.list.splice(0, LIST_LOAD_LIMIT), + page: p, + limit: LIST_LOAD_LIMIT, + }, + sourcePage, + }) + p++ + } while (result.list.length > 0) + return (listCache.get(`${source}__${bangId}__${page}`) as PageCache).data + }) ?? Promise.reject(new Error('source not found')) +} + +/** + * 获取排行榜内单页歌曲 + * @param id 排行榜id {souce}__{bangId} + * @param isRefresh 是否跳过缓存 + * @returns + */ +export const getListDetail = async(id: string, page: number, isRefresh = false): Promise<ListDetailInfo> => { + // console.log(tabId) + const [source, bangId] = id.split('__') as [LX.OnlineSource, string] + const listKey = `${source}__${bangId}` + const pageKey = `${source}__${bangId}__${page}` + + let listCache = cache.get(listKey) + if (!listCache || isRefresh) { + cache.set(listKey, listCache = new Map()) + } + + let pageCache = listCache.get(pageKey) as PageCache + if (pageCache) return pageCache.data + + return getListLimit(source, bangId, page) +} + +/** + * 获取排行榜内全部歌曲 + * @param id 排行榜id {souce}__{id} + * @param isRefresh 是否跳过缓存 + * @returns + */ +export const getListDetailAll = async(id: string, isRefresh = false): Promise<LX.Music.MusicInfoOnline[]> => { + const [source, bangId] = id.split('__') as [LX.OnlineSource, string] + // console.log(tabId) + const listKey = `${source}__${bangId}` + let listCache = cache.get(listKey) as CacheValue + if (!listCache || isRefresh) { + cache.set(listKey, listCache = new Map()) + } + + const loadData = async(page: number): Promise<ListDetailInfo> => { + const pageKey = `${source}__${bangId}__${page}` + let pageCache = listCache.get(pageKey) as PageCache + if (pageCache) return pageCache.data + return getListLimit(source, bangId, page) + } + return loadData(1).then(result => { + if (result.total <= result.limit) return result.list + + let maxPage = Math.ceil(result.total / result.limit) + const loadDetail = async(loadPage = 2): Promise<LX.Music.MusicInfoOnline[]> => { + return loadPage == maxPage + ? loadData(loadPage).then(result => result.list) + // eslint-disable-next-line @typescript-eslint/promise-function-async + : loadData(loadPage).then(result1 => loadDetail(++loadPage).then(result2 => [...result1.list, ...result2])) + } + return loadDetail().then(result2 => [...result.list, ...result2]) + }).then(list => deduplicationList(list)) +} + +/** + * 获取并设置排行榜内单页歌曲 + * @param id 排行榜id {souce}__{id} + * @param isRefresh 是否跳过缓存 + * @returns + */ +// export const getAndSetListDetail = async(id: string, page: number, isRefresh = false) => { +// // let [source, bangId] = tabId.split('__') +// // if (!bangId) return +// let key = `${id}__${page}` + +// if (!isRefresh && leaderboardState.listDetailInfo.key == key && leaderboardState.listDetailInfo.list.length) return + +// leaderboardState.listDetailInfo.key = key + +// return getListDetail(id, page, isRefresh).then((result: ListDetailInfo) => { +// if (key != leaderboardState.listDetailInfo.key) return +// setListDetail(result, id, page) +// }).catch((error: any) => { +// clearListDetail() +// console.log(error) +// throw error +// }) +// } diff --git a/src/core/list.ts b/src/core/list.ts new file mode 100644 index 000000000..26fa7ce65 --- /dev/null +++ b/src/core/list.ts @@ -0,0 +1,181 @@ +import { LIST_IDS } from '@/config/constant' +import listAction from '@/store/list/action' +import listState from '@/store/list/state' +import settingState from '@/store/setting/state' +import { fixNewMusicInfoQuality } from '@/utils' +import { saveListPrevSelectId } from '@/utils/data' + +/** + * 覆盖全部列表数据 + * @param data + */ +export const overwriteListFull = async(data: LX.List.ListActionDataOverwrite) => { + await global.list_event.list_data_overwrite(data) +} + + +/** + * 添加用户列表 + */ +export const createUserList = async(position: number, listInfos: LX.List.UserListInfo[]) => { + await global.list_event.list_create(position, listInfos) +} + +/** + * 移除用户列表及列表内歌曲 + */ +export const removeUserList = async(ids: string[]) => { + await global.list_event.list_remove(ids) +} + +/** + * 更新用户列表 + */ +export const updateUserList = async(listInfos: LX.List.UserListInfo[]) => { + await global.list_event.list_update(listInfos) +} + +/** + * 批量移动用户列表位置 + */ +export const updateUserListPosition = async(position: number, ids: string[]) => { + await global.list_event.list_update_position(position, ids) +} + + +/** + * 批量添加歌曲到列表 + */ +export const addListMusics = async(id: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType) => { + await global.list_event.list_music_add(id, musicInfos, addMusicLocationType) +} + +/** + * 跨列表批量移动歌曲 + */ +export const moveListMusics = async(fromId: string, toId: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType) => { + await global.list_event.list_music_move(fromId, toId, musicInfos, addMusicLocationType) +} + +/** + * 批量删除列表内歌曲 + */ +export const removeListMusics = async(listId: string, ids: string[]) => { + await global.list_event.list_music_remove(listId, ids) +} + +/** + * 批量更新列表内歌曲 + */ +export const updateListMusics = async(infos: Array<{ id: string, musicInfo: LX.Music.MusicInfo }>) => { + await global.list_event.list_music_update(infos) +} + +/** + * 批量移动列表内歌曲的位置 + */ +export const updateListMusicPosition = async(listId: string, position: number, ids: string[]) => { + await global.list_event.list_music_update_position(listId, position, ids) +} + +/** + * 覆盖列表内的歌曲 + */ +export const overwriteListMusics = async(listId: string, musicInfos: LX.Music.MusicInfo[]) => { + await global.list_event.list_music_overwrite(listId, musicInfos) +} + +/** + * 覆盖列表内的歌曲 + */ +export const clearListMusics = async(ids: string[]) => { + await global.list_event.list_music_clear(ids) +} + +/** + * 覆盖单个列表 + * @param listInfo + * @param musics + */ +export const overwriteList = async(listInfoFull: LX.List.MyDefaultListInfoFull | LX.List.MyLoveListInfoFull | LX.List.UserListInfoFull) => { + let userListInfo + switch (listInfoFull.id) { + case LIST_IDS.DEFAULT: + case LIST_IDS.LOVE: + break + + default: + userListInfo = listInfoFull as LX.List.UserListInfo + await updateUserList([ + { + name: userListInfo.name, + id: userListInfo.id, + source: userListInfo.source, + sourceListId: userListInfo.sourceListId, + locationUpdateTime: userListInfo.locationUpdateTime, + }, + ]) + break + } + await overwriteListMusics(listInfoFull.id, listInfoFull.list.map(m => fixNewMusicInfoQuality(m))) +} +/** + * 覆盖单个列表 + * @param listInfo + * @param musics + */ +export const createList = async({ name, id = `userlist_${Date.now()}`, list = [], source, sourceListId, position = -1 }: { + name?: string + id?: string + list?: LX.Music.MusicInfo[] + source?: LX.OnlineSource + sourceListId?: string + position?: number +}) => { + await createUserList(position < 0 ? listState.userList.length : position, [ + { + id, + name: name ?? 'list', + source, + sourceListId, + locationUpdateTime: position < 0 ? null : Date.now(), + }, + ]) + if (list) await addListMusics(id, list, settingState.setting['list.addMusicLocationType']) +} + +/** + * 设置当前激活的歌曲列表 + * @param id + */ +export const setActiveList = (id: string) => { + if (listState.activeListId == id) return + listAction.setActiveList(id) + saveListPrevSelectId(id) +} + +/** + * 设置歌曲列表 + */ +export const setUserList = (lists: LX.List.UserListInfo[]) => { + listAction.setUserLists(lists) +} + +/** + * 设置临时列表内歌曲 + * @param id + * @param list + */ +export const setTempList = async(id: string, list: LX.Music.MusicInfoOnline[]) => { + await overwriteListMusics(LIST_IDS.TEMP, list) + listAction.setTempListMeta({ id }) +} + + +export const setFetchingListStatus = (id: string, status: boolean) => { + listAction.setFetchingListStatus(id, status) +} + + +export { getUserLists, getListMusics } from '@/utils/listManage' + diff --git a/src/core/lyric.ts b/src/core/lyric.ts new file mode 100644 index 000000000..2bf23bbf0 --- /dev/null +++ b/src/core/lyric.ts @@ -0,0 +1,97 @@ +import { + play as lrcPlay, + setLyric as lrcSetLyric, + pause as lrcPause, + toggleTranslation as lrcToggleTranslation, + toggleRoma as lrcToggleRoma, + init as lrcInit, +} from '@/plugins/lyric' +import { + playDesktopLyric, + setDesktopLyric, + pauseDesktopLyric, + toggleDesktopLyricTranslation, + toggleDesktopLyricRoma, +} from '@/core/desktopLyric' +import { getPosition } from '@/plugins/player' +import playerState from '@/store/player/state' +import settingState from '@/store/setting/state' + +/** + * init lyric + */ +export const init = async() => { + return lrcInit() +} + +/** + * set lyric + * @param lyric lyric str + * @param translation lyric translation + */ +const handleSetLyric = (lyric: string, translation = '', romalrc = '') => { + void setDesktopLyric(lyric, translation, romalrc) + lrcSetLyric(lyric, translation, romalrc) +} + +/** + * play lyric + * @param time play time + */ +export const handlePlay = (time: number) => { + lrcPlay(time) + void playDesktopLyric(time) +} + +/** + * pause lyric + */ +export const pause = () => { + lrcPause() + void pauseDesktopLyric() +} + +/** + * stop lyric + */ +export const stop = () => { + handleSetLyric('') +} + +/** + * toggle show translation + * @param isShowTranslation is show translation + */ +export const toggleTranslation = (isShowTranslation: boolean) => { + lrcToggleTranslation(isShowTranslation) + void toggleDesktopLyricTranslation(isShowTranslation) +} + +/** + * toggle show roma lyric + * @param isShowLyricRoma is show roma lyric + */ +export const toggleRoma = (isShowLyricRoma: boolean) => { + lrcToggleRoma(isShowLyricRoma) + void toggleDesktopLyricRoma(isShowLyricRoma) +} + +export const play = () => { + void getPosition().then((position) => { + handlePlay(position * 1000) + }) +} + + +export const setLyric = () => { + if (!playerState.musicInfo.id) return + if (playerState.musicInfo.lrc) { + let tlrc = '' + let rlrc = '' + if (settingState.setting['player.isShowLyricTranslation'] && playerState.musicInfo.tlrc) tlrc = playerState.musicInfo.tlrc + if (settingState.setting['player.isShowLyricRoma'] && playerState.musicInfo.rlrc) rlrc = playerState.musicInfo.rlrc + handleSetLyric(playerState.musicInfo.lrc, tlrc, rlrc) + } + + if (playerState.isPlay) play() +} diff --git a/src/core/music/download.ts b/src/core/music/download.ts new file mode 100644 index 000000000..067f78d32 --- /dev/null +++ b/src/core/music/download.ts @@ -0,0 +1,72 @@ +// import { store } from '@/store' +// import { getDownloadFilePath } from '@renderer/utils/music' + +import { + getMusicUrl as getOnlineMusicUrl, + getPicUrl as getOnlinePicUrl, + getLyricInfo as getOnlineLyricInfo, +} from './online' +import { buildLyricInfo, getCachedLyricInfo } from './utils' + +export const getMusicUrl = async({ musicInfo, isRefresh, onToggleSource = () => {} }: { + musicInfo: LX.Download.ListItem + isRefresh: boolean + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<string> => { + // if (!isRefresh) { + // const path = await getDownloadFilePath(musicInfo, appSetting['download.savePath']) + // if (path) return path + // } + + return await getOnlineMusicUrl({ musicInfo: musicInfo.metadata.musicInfo, isRefresh, onToggleSource }) +} + +export const getPicUrl = async({ musicInfo, isRefresh, listId, onToggleSource = () => {} }: { + musicInfo: LX.Download.ListItem + isRefresh: boolean + listId?: string | null + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<string> => { + if (!isRefresh) { + // const path = await getDownloadFilePath(musicInfo, appSetting['download.savePath']) + // if (path) { + // const pic = await global.lx.worker.main.getMusicFilePic(path) + // if (pic) return pic + // } + + const onlineMusicInfo = musicInfo.metadata.musicInfo + if (onlineMusicInfo.meta.picUrl) return onlineMusicInfo.meta.picUrl + } + + return await getOnlinePicUrl({ musicInfo: musicInfo.metadata.musicInfo, isRefresh, onToggleSource }).then((url) => { + // TODO: when listId required save url (update downloadInfo) + + return url + }) +} + +export const getLyricInfo = async({ musicInfo, isRefresh, onToggleSource = () => {} }: { + musicInfo: LX.Download.ListItem + isRefresh: boolean + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<LX.Player.LyricInfo> => { + if (!isRefresh) { + const lyricInfo = await getCachedLyricInfo(musicInfo.metadata.musicInfo) + if (lyricInfo) return await buildLyricInfo(lyricInfo) + } + + return getOnlineLyricInfo({ + musicInfo: musicInfo.metadata.musicInfo, + isRefresh, + onToggleSource, + }).catch(async() => { + // 尝试读取文件内歌词 + // const path = await getDownloadFilePath(musicInfo, appSetting['download.savePath']) + // if (path) { + // const rawlrcInfo = await window.lx.worker.main.getMusicFileLyric(path) + // if (rawlrcInfo) return buildLyricInfo(rawlrcInfo) + // } + + throw new Error('failed') + }) +} diff --git a/src/core/music/index.ts b/src/core/music/index.ts new file mode 100644 index 000000000..45b79b55f --- /dev/null +++ b/src/core/music/index.ts @@ -0,0 +1,78 @@ +// if (targetSong.key) { // 如果是已下载的歌曲 +// const filePath = path.join(appSetting['download.savePath'], targetSong.metadata.fileName) +// // console.log(filePath) + +import { + getMusicUrl as getOnlineMusicUrl, + getPicUrl as getOnlinePicUrl, + getLyricInfo as getOnlineLyricInfo, +} from './online' +import { + getMusicUrl as getDownloadMusicUrl, + getPicUrl as getDownloadPicUrl, + getLyricInfo as getDownloadLyricInfo, +} from './download' +import { + getMusicUrl as getLocalMusicUrl, + getPicUrl as getLocalPicUrl, + getLyricInfo as getLocalLyricInfo, +} from './local' + + +export const getMusicUrl = async({ + musicInfo, + quality, + isRefresh = false, + onToggleSource, +}: { + musicInfo: LX.Music.MusicInfo | LX.Download.ListItem + isRefresh?: boolean + quality?: LX.Quality + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<string> => { + if ('progress' in musicInfo) { + return await getDownloadMusicUrl({ musicInfo, isRefresh, onToggleSource }) + } else if (musicInfo.source == 'local') { + return await getLocalMusicUrl({ musicInfo, isRefresh, onToggleSource }) + } else { + return await getOnlineMusicUrl({ musicInfo, isRefresh, quality, onToggleSource }) + } +} + +export const getPicPath = async({ + musicInfo, + isRefresh = false, + listId, + onToggleSource, +}: { + musicInfo: LX.Music.MusicInfo | LX.Download.ListItem + listId?: string | null + isRefresh?: boolean + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<string> => { + if ('progress' in musicInfo) { + return await getDownloadPicUrl({ musicInfo, isRefresh, listId, onToggleSource }) + } else if (musicInfo.source == 'local') { + return await getLocalPicUrl({ musicInfo, isRefresh, listId, onToggleSource }) + } else { + return await getOnlinePicUrl({ musicInfo, isRefresh, listId, onToggleSource }) + } +} + +export const getLyricInfo = async({ + musicInfo, + isRefresh = false, + onToggleSource, +}: { + musicInfo: LX.Music.MusicInfo | LX.Download.ListItem + isRefresh?: boolean + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<LX.Player.LyricInfo> => { + if ('progress' in musicInfo) { + return await getDownloadLyricInfo({ musicInfo, isRefresh, onToggleSource }) + } else if (musicInfo.source == 'local') { + return await getLocalLyricInfo({ musicInfo, isRefresh, onToggleSource }) + } else { + return await getOnlineLyricInfo({ musicInfo, isRefresh, onToggleSource }) + } +} diff --git a/src/core/music/local.ts b/src/core/music/local.ts new file mode 100644 index 000000000..a628ce14c --- /dev/null +++ b/src/core/music/local.ts @@ -0,0 +1,90 @@ + +import { saveLyric, saveMusicUrl } from '@/utils/data' +import { updateListMusics } from '@/core/list' +import { + buildLyricInfo, + getCachedLyricInfo, + getOnlineOtherSourceLyricInfo, + getOnlineOtherSourceMusicUrl, + getOnlineOtherSourcePicUrl, + getOtherSource, +} from './utils' + + +export const getMusicUrl = async({ musicInfo, isRefresh, onToggleSource = () => {} }: { + musicInfo: LX.Music.MusicInfoLocal + isRefresh: boolean + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<string> => { + // if (!isRefresh) { + // const path = await getLocalFilePath(musicInfo) + // if (path) return encodePath(path) + // } + onToggleSource() + const otherSource = await getOtherSource(musicInfo) + if (!otherSource.length) throw new Error('source not found') + return await getOnlineOtherSourceMusicUrl({ musicInfos: [...otherSource], onToggleSource, isRefresh }).then(({ url, quality: targetQuality, musicInfo: targetMusicInfo, isFromCache }) => { + // saveLyric(musicInfo, data.lyricInfo) + if (!isFromCache) void saveMusicUrl(targetMusicInfo, targetQuality, url) + + // TODO: save url ? + return url + }) +} + +export const getPicUrl = async({ musicInfo, listId, isRefresh, onToggleSource = () => {} }: { + musicInfo: LX.Music.MusicInfoLocal + listId?: string | null + isRefresh: boolean + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<string> => { + if (!isRefresh) { + // const pic = await window.lx.worker.main.getMusicFilePic(musicInfo.meta.filePath) + // if (pic) return pic + + if (musicInfo.meta.picUrl) return musicInfo.meta.picUrl + } + + onToggleSource() + const otherSource = await getOtherSource(musicInfo) + if (!otherSource.length) throw new Error('source not found') + return await getOnlineOtherSourcePicUrl({ musicInfos: [...otherSource], onToggleSource, isRefresh }).then(({ url, musicInfo: targetMusicInfo, isFromCache }) => { + if (listId) { + // musicInfo.meta.picUrl = url + void updateListMusics([{ id: listId, musicInfo }]) + } + + return url + }) +} + +export const getLyricInfo = async({ musicInfo, isRefresh, onToggleSource = () => {} }: { + musicInfo: LX.Music.MusicInfoLocal + isRefresh: boolean + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<LX.Player.LyricInfo> => { + if (!isRefresh) { + const lyricInfo = await getCachedLyricInfo(musicInfo) + if (lyricInfo) { + // 存在已编辑、原始歌词 + if (lyricInfo.rawlrcInfo.lyric) return await buildLyricInfo(lyricInfo) + } + + // 尝试读取文件内歌词 + // const rawlrcInfo = await window.lx.worker.main.getMusicFileLyric(musicInfo.meta.filePath) + // if (rawlrcInfo) return buildLyricInfo(lyricInfo ? { ...lyricInfo, rawlrcInfo } : rawlrcInfo) + } + + onToggleSource() + const otherSource = await getOtherSource(musicInfo) + if (!otherSource.length) throw new Error('source not found') + // eslint-disable-next-line @typescript-eslint/promise-function-async + return await getOnlineOtherSourceLyricInfo({ musicInfos: [...otherSource], onToggleSource, isRefresh }).then(({ lyricInfo, musicInfo: targetMusicInfo, isFromCache }) => { + void saveLyric(musicInfo, lyricInfo) + + if (isFromCache) return buildLyricInfo(lyricInfo) + void saveLyric(targetMusicInfo, lyricInfo) + + return buildLyricInfo(lyricInfo) + }) +} diff --git a/src/core/music/online.ts b/src/core/music/online.ts new file mode 100644 index 000000000..5b82d64b0 --- /dev/null +++ b/src/core/music/online.ts @@ -0,0 +1,104 @@ +import { + saveLyric, + saveMusicUrl, + getMusicUrl as getStoreMusicUrl, +} from '@/utils/data' +import { updateListMusics } from '@/core/list' +import settingState from '@/store/setting/state' + +import { + buildLyricInfo, + getPlayQuality, + handleGetOnlineLyricInfo, + handleGetOnlineMusicUrl, + handleGetOnlinePicUrl, + getCachedLyricInfo, +} from './utils' + +/* export const setMusicUrl = ({ musicInfo, type, url }: { + musicInfo: LX.Music.MusicInfo + type: LX.Quality + url: string +}) => { + saveMusicUrl(musicInfo, type, url) +} + +export const setPic = (datas: { + listId: string + musicInfo: LX.Music.MusicInfo + url: string +}) => { + datas.musicInfo.img = datas.url + updateMusicInfo({ + listId: datas.listId, + id: datas.musicInfo.songmid, + data: { img: datas.url }, + musicInfo: datas.musicInfo, + }) +} + */ + + +export const getMusicUrl = async({ musicInfo, quality, isRefresh, allowToggleSource = true, onToggleSource = () => {} }: { + musicInfo: LX.Music.MusicInfoOnline + quality?: LX.Quality + isRefresh: boolean + allowToggleSource?: boolean + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<string> => { + // if (!musicInfo._types[type]) { + // // 兼容旧版酷我源搜索列表过滤128k音质的bug + // if (!(musicInfo.source == 'kw' && type == '128k')) throw new Error('该歌曲没有可播放的音频') + + // // return Promise.reject(new Error('该歌曲没有可播放的音频')) + // } + const targetQuality = quality ?? getPlayQuality(settingState.setting['player.highQuality'], musicInfo) + const cachedUrl = await getStoreMusicUrl(musicInfo, targetQuality) + if (cachedUrl && !isRefresh) return cachedUrl + + return await handleGetOnlineMusicUrl({ musicInfo, quality, onToggleSource, isRefresh, allowToggleSource }).then(({ url, quality: targetQuality, musicInfo: targetMusicInfo, isFromCache }) => { + if (targetMusicInfo.id != musicInfo.id && !isFromCache) void saveMusicUrl(targetMusicInfo, targetQuality, url) + void saveMusicUrl(musicInfo, targetQuality, url) + return url + }) +} + +export const getPicUrl = async({ musicInfo, listId, isRefresh, allowToggleSource = true, onToggleSource = () => {} }: { + musicInfo: LX.Music.MusicInfoOnline + listId?: string | null + isRefresh: boolean + allowToggleSource?: boolean + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<string> => { + if (musicInfo.meta.picUrl && !isRefresh) return musicInfo.meta.picUrl + return await handleGetOnlinePicUrl({ musicInfo, onToggleSource, isRefresh, allowToggleSource }).then(({ url, musicInfo: targetMusicInfo, isFromCache }) => { + // picRequest = null + if (listId) { + // musicInfo.meta.picUrl = url + void updateListMusics([{ id: listId, musicInfo }]) + } + // savePic({ musicInfo, url, listId }) + return url + }) +} +export const getLyricInfo = async({ musicInfo, isRefresh, allowToggleSource = true, onToggleSource = () => {} }: { + musicInfo: LX.Music.MusicInfoOnline + isRefresh: boolean + allowToggleSource?: boolean + onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<LX.Player.LyricInfo> => { + if (!isRefresh) { + const lyricInfo = await getCachedLyricInfo(musicInfo) + if (lyricInfo) return await buildLyricInfo(lyricInfo) + } + + // lrcRequest = music[musicInfo.source].getLyric(musicInfo) + return await handleGetOnlineLyricInfo({ musicInfo, onToggleSource, isRefresh, allowToggleSource }).then(async({ lyricInfo, musicInfo: targetMusicInfo, isFromCache }) => { + // lrcRequest = null + if (isFromCache) return await buildLyricInfo(lyricInfo) + if (targetMusicInfo.id == musicInfo.id) void saveLyric(musicInfo, lyricInfo) + else void saveLyric(targetMusicInfo, lyricInfo) + + return await buildLyricInfo(lyricInfo) + }) +} diff --git a/src/core/music/utils.ts b/src/core/music/utils.ts new file mode 100644 index 000000000..fe65ed297 --- /dev/null +++ b/src/core/music/utils.ts @@ -0,0 +1,417 @@ +import musicSdk, { findMusic } from '@/utils/musicSdk' +import { + getOtherSource as getOtherSourceFromStore, + saveOtherSource as saveOtherSourceFromStore, + getMusicUrl as getStoreMusicUrl, + getPlayerLyric as getStoreLyric, +} from '@/utils/data' +import { langS2T, toNewMusicInfo, toOldMusicInfo } from '@/utils' +import { assertApiSupport } from '@/utils/tools' +import settingState from '@/store/setting/state' + + +const getOtherSourcePromises = new Map() +export const existTimeExp = /\[\d{1,2}:.*\d{1,4}\]/ + +export const getOtherSource = async(musicInfo: LX.Music.MusicInfo | LX.Download.ListItem, isRefresh = false): Promise<LX.Music.MusicInfoOnline[]> => { + if (!isRefresh) { + const cachedInfo = await getOtherSourceFromStore(musicInfo.id) + if (cachedInfo.length) return cachedInfo + } + let key: string + let searchMusicInfo: { + name: string + singer: string + source: string + albumName: string + interval: string + } + if ('progress' in musicInfo) { + key = `local_${musicInfo.id}` + searchMusicInfo = { + name: musicInfo.metadata.musicInfo.name, + singer: musicInfo.metadata.musicInfo.singer, + source: musicInfo.metadata.musicInfo.source, + albumName: musicInfo.metadata.musicInfo.meta.albumName, + interval: musicInfo.metadata.musicInfo.interval ?? '', + } + } else { + key = `${musicInfo.source}_${musicInfo.id}` + searchMusicInfo = { + name: musicInfo.name, + singer: musicInfo.singer, + source: musicInfo.source, + albumName: musicInfo.meta.albumName, + interval: musicInfo.interval ?? '', + } + } + if (getOtherSourcePromises.has(key)) return getOtherSourcePromises.get(key) + + const promise = findMusic(searchMusicInfo).then((otherSource) => { + const sources: LX.Music.MusicInfoOnline[] = otherSource.map(toNewMusicInfo) as LX.Music.MusicInfoOnline[] + if (sources.length) void saveOtherSourceFromStore(musicInfo.id, sources) + return sources + }).finally(() => { + if (getOtherSourcePromises.has(key)) getOtherSourcePromises.delete(key) + }) + getOtherSourcePromises.set(key, promise) + return promise +} + + +export const buildLyricInfo = async(lyricInfo: MakeOptional<LX.Player.LyricInfo, 'rawlrcInfo'>): Promise<LX.Player.LyricInfo> => { + if (!settingState.setting['player.isS2t']) { + // @ts-expect-error + if (lyricInfo.rawlrcInfo) return lyricInfo + return { ...lyricInfo, rawlrcInfo: { ...lyricInfo } } + } + + if (settingState.setting['player.isS2t']) { + const tasks = [ + lyricInfo.lyric ? langS2T(lyricInfo.lyric) : Promise.resolve(''), + lyricInfo.tlyric ? langS2T(lyricInfo.tlyric) : Promise.resolve(''), + lyricInfo.rlyric ? langS2T(lyricInfo.rlyric) : Promise.resolve(''), + lyricInfo.lxlyric ? langS2T(lyricInfo.lxlyric) : Promise.resolve(''), + ] + if (lyricInfo.rawlrcInfo) { + tasks.push(lyricInfo.lyric ? langS2T(lyricInfo.lyric) : Promise.resolve('')) + tasks.push(lyricInfo.tlyric ? langS2T(lyricInfo.tlyric) : Promise.resolve('')) + tasks.push(lyricInfo.rlyric ? langS2T(lyricInfo.rlyric) : Promise.resolve('')) + tasks.push(lyricInfo.lxlyric ? langS2T(lyricInfo.lxlyric) : Promise.resolve('')) + } + return await Promise.all(tasks).then(([lyric, tlyric, rlyric, lxlyric, lyric_raw, tlyric_raw, rlyric_raw, lxlyric_raw]) => { + const rawlrcInfo = lyric_raw ? { + lyric: lyric_raw, + tlyric: tlyric_raw, + rlyric: rlyric_raw, + lxlyric: lxlyric_raw, + } : { + lyric, + tlyric, + rlyric, + lxlyric, + } + return { + lyric, + tlyric, + rlyric, + lxlyric, + rawlrcInfo, + } + }) + } + + // @ts-expect-error + return lyricInfo.rawlrcInfo ? lyricInfo : { ...lyricInfo, rawlrcInfo: { ...lyricInfo } } +} + +export const getCachedLyricInfo = async(musicInfo: LX.Music.MusicInfo): Promise<LX.Player.LyricInfo | null> => { + let lrcInfo = await getStoreLyric(musicInfo) + // lrcInfo = {} + if (existTimeExp.test(lrcInfo.lyric) && lrcInfo.tlyric != null) { + // if (musicInfo.lrc.startsWith('\ufeff[id:$00000000]')) { + // let str = musicInfo.lrc.replace('\ufeff[id:$00000000]\n', '') + // commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc }) + // } else if (musicInfo.lrc.startsWith('[id:$00000000]')) { + // let str = musicInfo.lrc.replace('[id:$00000000]\n', '') + // commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc }) + // } + + // if (lrcInfo.lxlyric == null) { + // switch (musicInfo.source) { + // case 'kg': + // case 'kw': + // case 'mg': + // break + // default: + // return lrcInfo + // } + // } else + if (lrcInfo.rlyric == null) { + if (!['wy', 'kg'].includes(musicInfo.source)) return lrcInfo + } else return lrcInfo + } + return null +} + +export const getPlayQuality = (highQuality: boolean, musicInfo: LX.Music.MusicInfoOnline): LX.Quality => { + let type: LX.Quality = '128k' + let list = global.lx.qualityList[musicInfo.source] + if (highQuality && musicInfo.meta._qualitys['320k'] && list && list.includes('320k')) type = '320k' + return type +} + +export const getOnlineOtherSourceMusicUrl = async({ musicInfos, quality, onToggleSource, isRefresh, retryedSource = [] }: { + musicInfos: LX.Music.MusicInfoOnline[] + quality?: LX.Quality + onToggleSource: (musicInfo?: LX.Music.MusicInfoOnline) => void + isRefresh: boolean + retryedSource?: LX.OnlineSource[] +}): Promise<{ + url: string + musicInfo: LX.Music.MusicInfoOnline + quality: LX.Quality + isFromCache: boolean +}> => { + let musicInfo: LX.Music.MusicInfoOnline | null = null + let itemQuality: LX.Quality | null = null + // eslint-disable-next-line no-cond-assign + while (musicInfo = (musicInfos.shift() as LX.Music.MusicInfoOnline)) { + if (retryedSource.includes(musicInfo.source)) continue + retryedSource.push(musicInfo.source) + if (!assertApiSupport(musicInfo.source)) continue + itemQuality = quality ?? getPlayQuality(settingState.setting['player.highQuality'], musicInfo) + if (!musicInfo.meta._qualitys[itemQuality]) continue + + console.log('try toggle to: ', musicInfo.source, musicInfo.name, musicInfo.singer, musicInfo.interval) + onToggleSource(musicInfo) + break + } + if (!musicInfo || !itemQuality) throw new Error(global.i18n.t('toggle_source_failed')) + + const cachedUrl = await getStoreMusicUrl(musicInfo, itemQuality) + if (cachedUrl && !isRefresh) return { url: cachedUrl, musicInfo, quality: itemQuality, isFromCache: true } + + let reqPromise + try { + reqPromise = musicSdk[musicInfo.source].getMusicUrl(toOldMusicInfo(musicInfo), itemQuality).promise + } catch (err: any) { + reqPromise = Promise.reject(err) + } + retryedSource.includes(musicInfo.source) + // eslint-disable-next-line @typescript-eslint/promise-function-async + return reqPromise.then(({ url, type }: { url: string, type: LX.Quality }) => { + return { musicInfo, url, quality: type, isFromCache: false } + // eslint-disable-next-line @typescript-eslint/promise-function-async + }).catch((err: any) => { + console.log(err) + return getOnlineOtherSourceMusicUrl({ musicInfos, quality, onToggleSource, isRefresh, retryedSource }) + }) +} + +/** + * 获取在线音乐URL + */ +export const handleGetOnlineMusicUrl = async({ musicInfo, quality, onToggleSource, isRefresh, allowToggleSource }: { + musicInfo: LX.Music.MusicInfoOnline + quality?: LX.Quality + isRefresh: boolean + allowToggleSource: boolean + onToggleSource: (musicInfo?: LX.Music.MusicInfoOnline) => void +}): Promise<{ + url: string + musicInfo: LX.Music.MusicInfoOnline + quality: LX.Quality + isFromCache: boolean +}> => { + // console.log(musicInfo.source) + const targetQuality = quality ?? getPlayQuality(settingState.setting['player.highQuality'], musicInfo) + + let reqPromise + try { + reqPromise = musicSdk[musicInfo.source].getMusicUrl(toOldMusicInfo(musicInfo), targetQuality).promise + } catch (err: any) { + reqPromise = Promise.reject(err) + } + return reqPromise.then(({ url, type }: { url: string, type: LX.Quality }) => { + return { musicInfo, url, quality: type, isFromCache: false } + }).catch(async(err: any) => { + console.log(err) + if (!allowToggleSource) throw err + onToggleSource() + // eslint-disable-next-line @typescript-eslint/promise-function-async + return await getOtherSource(musicInfo).then(otherSource => { + // console.log('find otherSource', otherSource.length) + if (otherSource.length) { + return getOnlineOtherSourceMusicUrl({ + musicInfos: [...otherSource], + onToggleSource, + quality, + isRefresh, + retryedSource: [musicInfo.source], + }) + } + throw err + }) + }) +} + + +export const getOnlineOtherSourcePicUrl = async({ musicInfos, onToggleSource, isRefresh, retryedSource = [] }: { + musicInfos: LX.Music.MusicInfoOnline[] + onToggleSource: (musicInfo?: LX.Music.MusicInfoOnline) => void + isRefresh: boolean + retryedSource?: LX.OnlineSource[] +}): Promise<{ + url: string + musicInfo: LX.Music.MusicInfoOnline + isFromCache: boolean +}> => { + let musicInfo: LX.Music.MusicInfoOnline | null = null + // eslint-disable-next-line no-cond-assign + while (musicInfo = (musicInfos.shift() as LX.Music.MusicInfoOnline)) { + if (retryedSource.includes(musicInfo.source)) continue + retryedSource.push(musicInfo.source) + // if (!assertApiSupport(musicInfo.source)) continue + console.log('try toggle to: ', musicInfo.source, musicInfo.name, musicInfo.singer, musicInfo.interval) + onToggleSource(musicInfo) + break + } + if (!musicInfo) throw new Error(global.i18n.t('toggle_source_failed')) + + if (musicInfo.meta.picUrl && !isRefresh) return { musicInfo, url: musicInfo.meta.picUrl, isFromCache: true } + + let reqPromise + try { + reqPromise = musicSdk[musicInfo.source].getPic(toOldMusicInfo(musicInfo)).promise + } catch (err: any) { + reqPromise = Promise.reject(err) + } + retryedSource.includes(musicInfo.source) + return reqPromise.then((url: string) => { + return { musicInfo, url, isFromCache: false } + // eslint-disable-next-line @typescript-eslint/promise-function-async + }).catch((err: any) => { + console.log(err) + return getOnlineOtherSourcePicUrl({ musicInfos, onToggleSource, isRefresh, retryedSource }) + }) +} + +/** + * 获取在线歌曲封面 + */ +export const handleGetOnlinePicUrl = async({ musicInfo, isRefresh, onToggleSource, allowToggleSource }: { + musicInfo: LX.Music.MusicInfoOnline + onToggleSource: (musicInfo?: LX.Music.MusicInfoOnline) => void + isRefresh: boolean + allowToggleSource: boolean +}): Promise<{ + url: string + musicInfo: LX.Music.MusicInfoOnline + isFromCache: boolean +}> => { + // console.log(musicInfo.source) + let reqPromise + try { + reqPromise = musicSdk[musicInfo.source].getPic(toOldMusicInfo(musicInfo)).promise + } catch (err) { + reqPromise = Promise.reject(err) + } + return reqPromise.then((url: string) => { + return { musicInfo, url, isFromCache: false } + }).catch(async(err: any) => { + console.log(err) + if (!allowToggleSource) throw err + onToggleSource() + // eslint-disable-next-line @typescript-eslint/promise-function-async + return await getOtherSource(musicInfo).then(otherSource => { + // console.log('find otherSource', otherSource.length) + if (otherSource.length) { + return getOnlineOtherSourcePicUrl({ + musicInfos: [...otherSource], + onToggleSource, + isRefresh, + retryedSource: [musicInfo.source], + }) + } + throw err + }) + }) +} + + +export const getOnlineOtherSourceLyricInfo = async({ musicInfos, onToggleSource, isRefresh, retryedSource = [] }: { + musicInfos: LX.Music.MusicInfoOnline[] + onToggleSource: (musicInfo?: LX.Music.MusicInfoOnline) => void + isRefresh: boolean + retryedSource?: LX.OnlineSource[] +}): Promise<{ + lyricInfo: LX.Music.LyricInfo | LX.Player.LyricInfo + musicInfo: LX.Music.MusicInfoOnline + isFromCache: boolean +}> => { + let musicInfo: LX.Music.MusicInfoOnline | null = null + // eslint-disable-next-line no-cond-assign + while (musicInfo = (musicInfos.shift() as LX.Music.MusicInfoOnline)) { + if (retryedSource.includes(musicInfo.source)) continue + retryedSource.push(musicInfo.source) + // if (!assertApiSupport(musicInfo.source)) continue + console.log('try toggle to: ', musicInfo.source, musicInfo.name, musicInfo.singer, musicInfo.interval) + onToggleSource(musicInfo) + break + } + if (!musicInfo) throw new Error(global.i18n.t('toggle_source_failed')) + + if (!isRefresh) { + const lyricInfo = await getCachedLyricInfo(musicInfo) + if (lyricInfo) return { musicInfo, lyricInfo, isFromCache: true } + } + + let reqPromise + try { + // TODO: remove any type + reqPromise = (musicSdk[musicInfo.source].getLyric(toOldMusicInfo(musicInfo)) as any).promise + } catch (err: any) { + reqPromise = Promise.reject(err) + } + retryedSource.includes(musicInfo.source) + return reqPromise.then((lyricInfo: LX.Music.LyricInfo) => { + return existTimeExp.test(lyricInfo.lyric) ? { + lyricInfo, + musicInfo, + isFromCache: false, + } : Promise.reject(new Error('failed')) + // eslint-disable-next-line @typescript-eslint/promise-function-async + }).catch((err: any) => { + console.log(err) + return getOnlineOtherSourceLyricInfo({ musicInfos, onToggleSource, isRefresh, retryedSource }) + }) +} + +/** + * 获取在线歌词信息 + */ +export const handleGetOnlineLyricInfo = async({ musicInfo, onToggleSource, isRefresh, allowToggleSource }: { + musicInfo: LX.Music.MusicInfoOnline + onToggleSource: (musicInfo?: LX.Music.MusicInfoOnline) => void + isRefresh: boolean + allowToggleSource: boolean +}): Promise<{ + musicInfo: LX.Music.MusicInfoOnline + lyricInfo: LX.Music.LyricInfo | LX.Player.LyricInfo + isFromCache: boolean +}> => { + // console.log(musicInfo.source) + let reqPromise + try { + // TODO: remove any type + reqPromise = (musicSdk[musicInfo.source].getLyric(toOldMusicInfo(musicInfo)) as any).promise + } catch (err) { + reqPromise = Promise.reject(err) + } + return reqPromise.then((lyricInfo: LX.Music.LyricInfo) => { + return existTimeExp.test(lyricInfo.lyric) ? { + musicInfo, + lyricInfo, + isFromCache: false, + } : Promise.reject(new Error('failed')) + }).catch(async(err: any) => { + console.log(err) + if (!allowToggleSource) throw err + + onToggleSource() + // eslint-disable-next-line @typescript-eslint/promise-function-async + return await getOtherSource(musicInfo).then(otherSource => { + // console.log('find otherSource', otherSource.length) + if (otherSource.length) { + return getOnlineOtherSourceLyricInfo({ + musicInfos: [...otherSource], + onToggleSource, + isRefresh, + retryedSource: [musicInfo.source], + }) + } + throw err + }) + }) +} diff --git a/src/core/player/playInfo.ts b/src/core/player/playInfo.ts new file mode 100644 index 000000000..66a3f7080 --- /dev/null +++ b/src/core/player/playInfo.ts @@ -0,0 +1,134 @@ +import playerActions from '@/store/player/action' +import playerState from '@/store/player/state' + +import { getListMusicSync } from '@/utils/listManage' +import { setProgress } from '@/core/player/progress' +import { LIST_IDS } from '@/config/constant' + + +export const setMusicInfo = (musicInfo: Partial<LX.Player.MusicInfo>) => { + playerActions.setMusicInfo(musicInfo) +} + +export const setPlayListId = (listId: string | null) => { + playerActions.setPlayListId(listId) +} + + +/** + * 更新播放位置 + * @returns 播放位置 + */ +export const updatePlayIndex = () => { + const indexInfo = getPlayIndex(playerState.playMusicInfo.listId, playerState.playMusicInfo.musicInfo, playerState.playMusicInfo.isTempPlay) + // console.log('indexInfo', indexInfo) + playerActions.updatePlayIndex(indexInfo.playIndex, indexInfo.playerPlayIndex) + return indexInfo +} + + +export const getPlayIndex = (listId: string | null, musicInfo: LX.Download.ListItem | LX.Music.MusicInfo | null, isTempPlay: boolean): { + playIndex: number + playerPlayIndex: number +} => { + const { playInfo } = playerState + const playerList = getListMusicSync(playInfo.playerListId) + + // if (listIndex < 0) throw new Error('music info not found') + // playInfo.playIndex = listIndex + + let playIndex = -1 + let playerPlayIndex = -1 + if (playerList.length) { + playerPlayIndex = Math.min(playInfo.playerPlayIndex, playerList.length - 1) + } + + const list = getListMusicSync(listId) + if (list.length && musicInfo) { + const currentId = musicInfo.id + playIndex = list.findIndex(m => m.id == currentId) + if (!isTempPlay) { + if (playIndex < 0) { + playerPlayIndex = playerPlayIndex < 1 ? (list.length - 1) : (playerPlayIndex - 1) + } else { + playerPlayIndex = playIndex + } + } + } + + return { + playIndex, + playerPlayIndex, + } +} + +export const resetPlayerMusicInfo = () => { + setMusicInfo({ + id: null, + pic: null, + lrc: null, + tlrc: null, + rlrc: null, + lxlrc: null, + rawlrc: null, + name: '', + singer: '', + album: '', + }) +} + +const setPlayerMusicInfo = (musicInfo: LX.Music.MusicInfo | LX.Download.ListItem | null) => { + if (musicInfo) { + setMusicInfo('progress' in musicInfo ? { + id: musicInfo.id, + pic: musicInfo.metadata.musicInfo.meta.picUrl, + name: musicInfo.metadata.musicInfo.name, + singer: musicInfo.metadata.musicInfo.singer, + album: musicInfo.metadata.musicInfo.meta.albumName, + lrc: null, + tlrc: null, + rlrc: null, + lxlrc: null, + rawlrc: null, + } : { + id: musicInfo.id, + pic: musicInfo.meta.picUrl, + name: musicInfo.name, + singer: musicInfo.singer, + album: musicInfo.meta.albumName, + lrc: null, + tlrc: null, + rlrc: null, + lxlrc: null, + rawlrc: null, + }) + } else resetPlayerMusicInfo() +} + +/** + * 设置当前播放歌曲的信息 + * @param listId 歌曲所属的列表id + * @param musicInfo 歌曲信息 + * @param isTempPlay 是否临时播放 + */ +export const setPlayMusicInfo = (listId: string | null, musicInfo: LX.Download.ListItem | LX.Music.MusicInfo | null, isTempPlay: boolean = false) => { + playerActions.setPlayMusicInfo(listId, musicInfo, isTempPlay) + setPlayerMusicInfo(musicInfo) + + setProgress(0, 0) + + if (musicInfo == null) { + playerActions.updatePlayIndex(-1, -1) + setPlayListId(null) + } else { + const { playIndex, playerPlayIndex } = getPlayIndex(listId, musicInfo, isTempPlay) + + playerActions.updatePlayIndex(playIndex, playerPlayIndex) + global.app_event.musicToggled() + } +} + +export const getList = (listId: string | null): LX.Music.MusicInfo[] | LX.Download.ListItem[] => { + // return listId == LIST_ID_DOWNLOAD ? downloadList : getListMusicSync(listId) + return listId == LIST_IDS.DOWNLOAD ? [] : getListMusicSync(listId) +} diff --git a/src/core/player/playStatus.ts b/src/core/player/playStatus.ts new file mode 100644 index 000000000..e8a686517 --- /dev/null +++ b/src/core/player/playStatus.ts @@ -0,0 +1,14 @@ +import playerActions from '@/store/player/action' +import playerState from '@/store/player/state' + + +export const setIsPlay = (val: boolean) => { + if (playerState.isPlay == val) return + playerActions.setIsPlay(val) +} + + +export const setStatusText = (val: string) => { + if (playerState.statusText == val) return + playerActions.setStatusText(val) +} diff --git a/src/core/player/playedList.ts b/src/core/player/playedList.ts new file mode 100644 index 000000000..3c0416140 --- /dev/null +++ b/src/core/player/playedList.ts @@ -0,0 +1,23 @@ +import playerActions from '@/store/player/action' + + +/** + * 将歌曲添加到已播放列表 + * @param playMusicInfo playMusicInfo对象 + */ +export const addPlayedList = (playMusicInfo: LX.Player.PlayMusicInfo) => { + playerActions.addPlayedList(playMusicInfo) +} +/** + * 将歌曲从已播放列表移除 + * @param index 歌曲位置 + */ +export const removePlayedList = (index: number) => { + playerActions.removePlayedList(index) +} +/** + * 清空已播放列表 + */ +export const clearPlayedList = () => { + playerActions.clearPlayedList() +} diff --git a/src/core/player/player.ts b/src/core/player/player.ts new file mode 100644 index 000000000..af66d15e8 --- /dev/null +++ b/src/core/player/player.ts @@ -0,0 +1,460 @@ +import { isInitialized, initial as playerInitial, isEmpty, setPause, setPlay, setResource, setStop } from '@/plugins/player' +import { + setStatusText, +} from '@/core/player/playStatus' +import playerState from '@/store/player/state' +import settingState from '@/store/setting/state' +import { + getList, + setPlayMusicInfo, + setMusicInfo, + setPlayListId, +} from '@/core/player/playInfo' +import { + clearPlayedList, + addPlayedList, + removePlayedList, +} from '@/core/player/playedList' +import { + clearTempPlayeList, + removeTempPlayList, +} from '@/core/player/tempPlayList' +import { getMusicUrl, getPicPath, getLyricInfo } from '@/core/music' +import { requestMsg } from '@/utils/message' +import { getRandom } from '@/utils/common' +import { filterList } from './utils' +import BackgroundTimer from 'react-native-background-timer' +import { checkNotificationPermission } from '@/utils/tools' + +// import { checkMusicFileAvailable } from '@renderer/utils/music' + +const createDelayNextTimeout = (delay: number) => { + let timeout: number | null + const clearDelayNextTimeout = () => { + // console.log(this.timeout) + if (timeout) { + BackgroundTimer.clearTimeout(timeout) + timeout = null + } + } + + const addDelayNextTimeout = () => { + clearDelayNextTimeout() + timeout = BackgroundTimer.setTimeout(() => { + timeout = null + if (global.lx.isPlayedStop) return + console.log('delay next timeout timeout', delay) + void playNext(true) + }, delay) + } + + return { + clearDelayNextTimeout, + addDelayNextTimeout, + } +} +const { addDelayNextTimeout, clearDelayNextTimeout } = createDelayNextTimeout(5000) +const { addDelayNextTimeout: addLoadTimeout, clearDelayNextTimeout: clearLoadTimeout } = createDelayNextTimeout(100000) + +/** + * 检查音乐信息是否已更改 + */ +const diffCurrentMusicInfo = (curMusicInfo: LX.Music.MusicInfo | LX.Download.ListItem): boolean => { + return curMusicInfo !== playerState.playMusicInfo.musicInfo || playerState.isPlay +} + +const getMusicPlayUrl = async(musicInfo: LX.Music.MusicInfo | LX.Download.ListItem, isRefresh = false, isRetryed = false): Promise<string | null> => { + // this.musicInfo.url = await getMusicPlayUrl(targetSong, type) + setStatusText(global.i18n.t('player__geting_url')) + + // const type = getPlayType(settingState.setting['player.highQuality'], musicInfo) + + return getMusicUrl({ + musicInfo, + isRefresh, + onToggleSource(mInfo) { + if (diffCurrentMusicInfo(musicInfo)) return + setStatusText(global.i18n.t('toggle_source_try')) + }, + }).then(url => { + if (global.lx.isPlayedStop || diffCurrentMusicInfo(musicInfo)) return null + + return url + }).catch(err => { + // console.log('err', err.message) + if (global.lx.isPlayedStop || + diffCurrentMusicInfo(musicInfo) || + err.message == requestMsg.cancelRequest) return null + + if (!isRetryed) return getMusicPlayUrl(musicInfo, isRefresh, true) + + throw err + }) +} + +export const setMusicUrl = (musicInfo: LX.Music.MusicInfo | LX.Download.ListItem, isRefresh?: boolean) => { + addLoadTimeout() + global.lx.gettingUrlId = musicInfo.id + void getMusicPlayUrl(musicInfo, isRefresh).then((url) => { + if (!url) return + setResource(musicInfo, url, playerState.progress.nowPlayTime) + }).catch((err: any) => { + console.log(err) + setStatusText(err.message) + global.app_event.error() + addDelayNextTimeout() + }).finally(() => { + if (musicInfo === playerState.playMusicInfo.musicInfo) { + global.lx.gettingUrlId = '' + clearLoadTimeout() + } + }) +} + +// 恢复上次播放的状态 +const handleRestorePlay = async(restorePlayInfo: LX.Player.SavedPlayInfo) => { + const musicInfo = playerState.playMusicInfo.musicInfo + if (!musicInfo) return + + setTimeout(() => { + global.app_event.setProgress(settingState.setting['player.isSavePlayTime'] ? restorePlayInfo.time : 0, restorePlayInfo.maxTime) + }) + + const playMusicInfo = playerState.playMusicInfo + + void getPicPath({ musicInfo, listId: playMusicInfo.listId }).then((url: string) => { + if (musicInfo.id != playMusicInfo.musicInfo?.id) return + setMusicInfo({ pic: url }) + global.app_event.picUpdated() + }) + + void getLyricInfo({ musicInfo }).then((lyricInfo) => { + if (musicInfo.id != playMusicInfo.musicInfo?.id) return + setMusicInfo({ + lrc: lyricInfo.lyric, + tlrc: lyricInfo.tlyric, + lxlrc: lyricInfo.lxlyric, + rlrc: lyricInfo.rlyric, + rawlrc: lyricInfo.rawlrcInfo.lyric, + }) + global.app_event.lyricUpdated() + }).catch((err) => { + console.log(err) + if (musicInfo.id != playMusicInfo.musicInfo?.id) return + setStatusText(global.i18n.t('lyric__load_error')) + }) + + if (settingState.setting['player.togglePlayMethod'] == 'random' && !playMusicInfo.isTempPlay) addPlayedList(playMusicInfo as LX.Player.PlayMusicInfo) +} + + +// 处理音乐播放 +const handlePlay = async() => { + if (!isInitialized()) { + await checkNotificationPermission() + await playerInitial({ + cacheSize: settingState.setting['player.cacheSize'] ? parseInt(settingState.setting['player.cacheSize']) : 0, + isHandleAudioFocus: settingState.setting['player.isHandleAudioFocus'], + }) + } + + global.lx.isPlayedStop &&= false + + if (global.lx.restorePlayInfo) { + void handleRestorePlay(global.lx.restorePlayInfo) + global.lx.restorePlayInfo = null + return + } + + const playMusicInfo = playerState.playMusicInfo + const musicInfo = playMusicInfo.musicInfo + + if (!musicInfo || global.lx.gettingUrlId == musicInfo.id) return + global.lx.gettingUrlId &&= '' + + await setStop() + global.app_event.pause() + + clearDelayNextTimeout() + clearLoadTimeout() + + + if (settingState.setting['player.togglePlayMethod'] == 'random' && !playMusicInfo.isTempPlay) addPlayedList(playMusicInfo as LX.Player.PlayMusicInfo) + + setMusicUrl(musicInfo) + + void getPicPath({ musicInfo, listId: playMusicInfo.listId }).then((url: string) => { + if (musicInfo.id != playMusicInfo.musicInfo?.id) return + setMusicInfo({ pic: url }) + global.app_event.picUpdated() + }) + + void getLyricInfo({ musicInfo }).then((lyricInfo) => { + if (musicInfo.id != playMusicInfo.musicInfo?.id) return + setMusicInfo({ + lrc: lyricInfo.lyric, + tlrc: lyricInfo.tlyric, + lxlrc: lyricInfo.lxlyric, + rlrc: lyricInfo.rlyric, + rawlrc: lyricInfo.rawlrcInfo.lyric, + }) + global.app_event.lyricUpdated() + }).catch((err) => { + console.log(err) + if (musicInfo.id != playMusicInfo.musicInfo?.id) return + setStatusText(global.i18n.t('lyric__load_error')) + }) +} + +/** + * 播放列表内歌曲 + * @param listId 列表id + * @param index 播放的歌曲位置 + */ +export const playList = async(listId: string, index: number) => { + setPlayListId(listId) + setPlayMusicInfo(listId, getList(listId)[index]) + clearPlayedList() + clearTempPlayeList() + await handlePlay() +} + +const handleToggleStop = async() => { + await stop() + setTimeout(() => { + setPlayMusicInfo(null, null) + }) +} + +/** + * 下一曲 + * @param isAutoToggle 是否自动切换 + * @returns + */ +export const playNext = async(isAutoToggle = false): Promise<void> => { + if (playerState.tempPlayList.length) { // 如果稍后播放列表存在歌曲则直接播放改列表的歌曲 + const playMusicInfo = playerState.tempPlayList[0] + removeTempPlayList(0) + setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay) + await handlePlay() + return + } + + const playMusicInfo = playerState.playMusicInfo + const playInfo = playerState.playInfo + if (playMusicInfo.musicInfo == null) return handleToggleStop() + + // console.log(playInfo.playerListId) + const currentListId = playInfo.playerListId + if (!currentListId) return handleToggleStop() + const currentList = getList(currentListId) + + const playedList = playerState.playedList + + if (playedList.length) { // 移除已播放列表内不存在原列表的歌曲 + let currentId: string + if (playMusicInfo.isTempPlay) { + const musicInfo = currentList[playInfo.playerPlayIndex] + if (musicInfo) currentId = musicInfo.id + } else { + currentId = playMusicInfo.musicInfo.id + } + // 从已播放列表移除播放列表已删除的歌曲 + let index + for (index = playedList.findIndex(m => m.musicInfo.id === currentId) + 1; index < playedList.length; index++) { + const playMusicInfo = playedList[index] + const currentId = playMusicInfo.musicInfo.id + if (playMusicInfo.listId == currentListId && !currentList.some(m => m.id === currentId)) { + removePlayedList(index) + continue + } + break + } + + if (index < playedList.length) { + const playMusicInfo = playedList[index] + setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay) + await handlePlay() + return + } + } + // const isCheckFile = findNum > 2 // 针对下载列表,如果超过两次都碰到无效歌曲,则过滤整个列表内的无效歌曲 + let { filteredList, playerIndex } = filterList({ // 过滤已播放歌曲 + listId: currentListId, + list: currentList, + playedList, + playerMusicInfo: currentList[playInfo.playerPlayIndex], + }) + + if (!filteredList.length) return handleToggleStop() + // let currentIndex: number = filteredList.indexOf(currentList[playInfo.playerPlayIndex]) + if (playerIndex == -1 && filteredList.length) playerIndex = 0 + let nextIndex = playerIndex + + let togglePlayMethod = settingState.setting['player.togglePlayMethod'] + if (!isAutoToggle) { + switch (togglePlayMethod) { + case 'list': + case 'singleLoop': + case 'none': + togglePlayMethod = 'listLoop' + } + } + switch (togglePlayMethod) { + case 'listLoop': + nextIndex = playerIndex === filteredList.length - 1 ? 0 : playerIndex + 1 + break + case 'random': + nextIndex = getRandom(0, filteredList.length) + break + case 'list': + nextIndex = playerIndex === filteredList.length - 1 ? -1 : playerIndex + 1 + break + case 'singleLoop': + break + default: + nextIndex = -1 + return + } + if (nextIndex < 0) return + + const nextPlayMusicInfo = { + musicInfo: filteredList[nextIndex], + listId: currentListId, + isTempPlay: false, + } + + setPlayMusicInfo(nextPlayMusicInfo.listId, nextPlayMusicInfo.musicInfo) + await handlePlay() +} + +/** + * 上一曲 + */ +export const playPrev = async(isAutoToggle = false): Promise<void> => { + const playMusicInfo = playerState.playMusicInfo + if (playMusicInfo.musicInfo == null) return handleToggleStop() + const playInfo = playerState.playInfo + + const currentListId = playInfo.playerListId + if (!currentListId) return handleToggleStop() + const currentList = getList(currentListId) + + const playedList = playerState.playedList + if (playedList.length) { + let currentId: string + if (playMusicInfo.isTempPlay) { + const musicInfo = currentList[playInfo.playerPlayIndex] + if (musicInfo) currentId = musicInfo.id + } else { + currentId = playMusicInfo.musicInfo.id + } + // 从已播放列表移除播放列表已删除的歌曲 + let index + for (index = playedList.findIndex(m => m.musicInfo.id === currentId) - 1; index > -1; index--) { + const playMusicInfo = playedList[index] + const currentId = playMusicInfo.musicInfo.id + if (playMusicInfo.listId == currentListId && !currentList.some(m => m.id === currentId)) { + removePlayedList(index) + continue + } + break + } + + if (index > -1) { + const playMusicInfo = playedList[index] + setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay) + await handlePlay() + return + } + } + + // const isCheckFile = findNum > 2 + let { filteredList, playerIndex } = filterList({ // 过滤已播放歌曲 + listId: currentListId, + list: currentList, + playedList, + playerMusicInfo: currentList[playInfo.playerPlayIndex], + }) + if (!filteredList.length) return handleToggleStop() + + // let currentIndex = filteredList.indexOf(currentList[playInfo.playerPlayIndex]) + if (playerIndex == -1 && filteredList.length) playerIndex = 0 + let nextIndex = playerIndex + if (!playMusicInfo.isTempPlay) { + let togglePlayMethod = settingState.setting['player.togglePlayMethod'] + if (!isAutoToggle) { + switch (togglePlayMethod) { + case 'list': + case 'singleLoop': + case 'none': + togglePlayMethod = 'listLoop' + } + } + switch (togglePlayMethod) { + case 'random': + nextIndex = getRandom(0, filteredList.length) + break + case 'listLoop': + case 'list': + nextIndex = playerIndex === 0 ? filteredList.length - 1 : playerIndex - 1 + break + case 'singleLoop': + break + default: + nextIndex = -1 + return + } + if (nextIndex < 0) return + } + + const nextPlayMusicInfo = { + musicInfo: filteredList[nextIndex], + listId: currentListId, + isTempPlay: false, + } + + setPlayMusicInfo(nextPlayMusicInfo.listId, nextPlayMusicInfo.musicInfo) + await handlePlay() +} + +/** + * 恢复播放 + */ +export const play = () => { + if (playerState.playMusicInfo.musicInfo == null) return + if (isEmpty()) { + if (playerState.playMusicInfo.musicInfo.id != global.lx.gettingUrlId) setMusicUrl(playerState.playMusicInfo.musicInfo) + return + } + void setPlay() +} + +/** + * 暂停播放 + */ +export const pause = async() => { + await setPause() +} + +/** + * 停止播放 + */ +export const stop = async() => { + await setStop() + setTimeout(() => { + global.app_event.stop() + }) +} + +/** + * 播放、暂停播放切换 + */ +export const togglePlay = () => { + global.lx.isPlayedStop &&= false + if (playerState.isPlay) { + void pause() + } else { + play() + } +} diff --git a/src/core/player/progress.ts b/src/core/player/progress.ts new file mode 100644 index 000000000..30b248510 --- /dev/null +++ b/src/core/player/progress.ts @@ -0,0 +1,14 @@ +import playerActions from '@/store/player/action' + +export const setNowPlayTime = (time: number) => { + playerActions.setNowPlayTime(time) +} + +export const setMaxplayTime = (time: number) => { + playerActions.setMaxplayTime(time) +} + +export const setProgress = (currentTime: number, totalTime: number) => { + playerActions.setProgress(currentTime, totalTime) +} + diff --git a/src/core/player/tempPlayList.ts b/src/core/player/tempPlayList.ts new file mode 100644 index 000000000..002b34cd1 --- /dev/null +++ b/src/core/player/tempPlayList.ts @@ -0,0 +1,26 @@ +import playerActions from '@/store/player/action' +import playerState from '@/store/player/state' +import { playNext } from './player' + + +/** + * 添加歌曲到稍后播放列表 + * @param list 歌曲列表 + */ +export const addTempPlayList = (list: LX.Player.TempPlayListItem[]) => { + playerActions.addTempPlayList(list) + if (!playerState.playMusicInfo.musicInfo) void playNext() +} +/** + * 从稍后播放列表移除歌曲 + * @param index 歌曲位置 + */ +export const removeTempPlayList = (index: number) => { + playerActions.removeTempPlayList(index) +} +/** + * 清空稍后播放列表 + */ +export const clearTempPlayeList = () => { + playerActions.clearTempPlayeList() +} diff --git a/src/utils/timeoutExit.js b/src/core/player/timeoutExit.ts similarity index 57% rename from src/utils/timeoutExit.js rename to src/core/player/timeoutExit.ts index e66665e39..1a11b0ebd 100644 --- a/src/utils/timeoutExit.js +++ b/src/core/player/timeoutExit.ts @@ -1,18 +1,18 @@ import { useEffect, useState } from 'react' import BackgroundTimer from 'react-native-background-timer' -import { getStore } from '@/store' -import { STATUS } from '@/store/modules/player' -import { exitApp } from '@/utils/common' +import { exitApp } from '@/core/common' +import playerState from '@/store/player/state' +import settingState from '@/store/setting/state' + +type Hook = (time: number, isPlayedStop: boolean) => void const timeoutTools = { - timeout: null, + timeout: null as number | null, time: -1, - timeHooks: [], + timeHooks: [] as Hook[], exit() { - const store = getStore() - const state = store.getState() - if (state.common.setting.player.timeoutExitPlayed && state.player.status == STATUS.playing) { - global.isPlayedExit = true + if (settingState.setting['player.timeoutExitPlayed'] && playerState.isPlay) { + global.lx.isPlayedStop = true this.callHooks() } else { exitApp() @@ -20,10 +20,7 @@ const timeoutTools = { }, callHooks() { for (const hook of this.timeHooks) { - hook({ - time: this.time, - isPlayedExit: global.isPlayedExit, - }) + hook(this.time, global.lx.isPlayedStop) } }, clearTimeout() { @@ -33,7 +30,7 @@ const timeoutTools = { this.time = -1 this.callHooks() }, - start(time) { + start(time: number) { this.clearTimeout() this.time = time this.timeout = BackgroundTimer.setInterval(() => { @@ -46,20 +43,17 @@ const timeoutTools = { } }, 1000) }, - addTimeHook(hook) { + addTimeHook(hook: Hook) { this.timeHooks.push(hook) - hook({ - time: this.time, - isPlayedExit: global.isPlayedExit, - }) + hook(this.time, global.lx.isPlayedStop) }, - removeTimeHook(hook) { + removeTimeHook(hook: Hook) { this.timeHooks.splice(this.timeHooks.indexOf(hook), 1) }, } -export const startTimeoutExit = time => { +export const startTimeoutExit = (time: number) => { timeoutTools.start(time) } export const stopTimeoutExit = () => { @@ -71,10 +65,10 @@ export const getTimeoutExitTime = () => { } export const useTimeoutExitTimeInfo = () => { - const [info, setInfo] = useState({ time: 0, isPlayedExit: false }) + const [info, setInfo] = useState({ time: 0, isPlayedStop: false }) useEffect(() => { - const hook = ({ time, isPlayedExit }) => { - setInfo({ time, isPlayedExit }) + const hook: Hook = (time, isPlayedStop) => { + setInfo({ time, isPlayedStop }) } timeoutTools.addTimeHook(hook) return () => { timeoutTools.removeTimeHook(hook) } @@ -83,7 +77,16 @@ export const useTimeoutExitTimeInfo = () => { return info } +export const onTimeUpdate = (handler: Hook) => { + timeoutTools.addTimeHook(handler) + + return () => { + timeoutTools.removeTimeHook(handler) + } +} + + export const cancelTimeoutExit = () => { - global.isPlayedExit = false + global.lx.isPlayedStop = false timeoutTools.callHooks() } diff --git a/src/core/player/utils.ts b/src/core/player/utils.ts new file mode 100644 index 000000000..e232da42d --- /dev/null +++ b/src/core/player/utils.ts @@ -0,0 +1,81 @@ +import { clearPlayedList } from './playedList' + +/** + * 过滤列表中已播放的歌曲 + */ +export const filterMusicList = ({ playedList, listId, list, playerMusicInfo }: { + /** + * 已播放列表 + */ + playedList: LX.Player.PlayMusicInfo[] | readonly LX.Player.PlayMusicInfo[] + /** + * 列表id + */ + listId: string + /** + * 播放列表 + */ + list: Array<LX.Music.MusicInfo | LX.Download.ListItem> + /** + * 下载目录 + */ + // savePath: string + /** + * 播放器内当前歌曲(`playInfo.playerPlayIndex`指向的歌曲) + */ + playerMusicInfo?: LX.Music.MusicInfo | LX.Download.ListItem +}) => { + let playerIndex = -1 + + let canPlayList: Array<LX.Music.MusicInfo | LX.Download.ListItem> = [] + const filteredPlayedList = playedList.filter(pmInfo => pmInfo.listId == listId && !pmInfo.isTempPlay).map(({ musicInfo }) => musicInfo) + + const filteredList: Array<LX.Music.MusicInfo | LX.Download.ListItem> = list.filter(s => { + // if (!assertApiSupport(s.source)) return false + if ('progress' in s && !s.isComplate) return false + + canPlayList.push(s) + + let index = filteredPlayedList.findIndex(m => m.id == s.id) + if (index > -1) { + filteredPlayedList.splice(index, 1) + return false + } + return true + }) + if (playerMusicInfo) { + playerIndex = (filteredList.length ? filteredList : canPlayList).findIndex(m => m.id == playerMusicInfo.id) + } + return { + filteredList, + canPlayList, + playerIndex, + } +} + +/** + * 过滤列表中已播放的歌曲 + */ +export const filterList = ({ playedList, listId, list, playerMusicInfo }: { + playedList: LX.Player.PlayMusicInfo[] | readonly LX.Player.PlayMusicInfo[] + listId: string + list: Array<LX.Music.MusicInfo | LX.Download.ListItem> + playerMusicInfo?: LX.Music.MusicInfo | LX.Download.ListItem +}) => { + // if (this.list.listName === null) return + // console.log(isCheckFile) + let { filteredList, canPlayList, playerIndex } = filterMusicList({ + listId, + list, + playedList, + // savePath: global.lx.setting['download.savePath'], + playerMusicInfo, + }) + + if (!filteredList.length && playedList.length) { + clearPlayedList() + return { filteredList: canPlayList, playerIndex } + } + return { filteredList, playerIndex } +} + diff --git a/src/core/search/music.ts b/src/core/search/music.ts new file mode 100644 index 000000000..25dbe40b1 --- /dev/null +++ b/src/core/search/music.ts @@ -0,0 +1,55 @@ +import searchMusicState, { type ListInfo, type Source } from '@/store/search/music/state' +import searchMusicActions, { type SearchResult } from '@/store/search/music/action' +import musicSdk from '@/utils/musicSdk' + +export const setSource: typeof searchMusicActions['setSource'] = (source) => { + searchMusicActions.setSource(source) +} +export const setSearchText: typeof searchMusicActions['setSearchText'] = (text) => { + searchMusicActions.setSearchText(text) +} +export const setListInfo: typeof searchMusicActions.setListInfo = (result, id, page) => { + return searchMusicActions.setListInfo(result, id, page) +} + +export const clearListInfo: typeof searchMusicActions.clearListInfo = (source) => { + searchMusicActions.clearListInfo(source) +} + + +export const search = async(text: string, page: number, sourceId: Source): Promise<LX.Music.MusicInfoOnline[]> => { + const listInfo = searchMusicState.listInfos[sourceId] as ListInfo + if (!text) return [] + const key = `${page}__${text}` + if (sourceId == 'all') { + listInfo.key = key + let task = [] + for (const source of searchMusicState.sources) { + if (source == 'all') continue + task.push(((musicSdk[source]?.musicSearch.search(text, page, searchMusicState.listInfos.all.limit) as Promise<SearchResult>) ?? Promise.reject(new Error('source not found: ' + source))).catch((error: any) => { + console.log(error) + return { + allPage: 1, + limit: 30, + list: [], + source, + total: 0, + } + })) + } + return Promise.all(task).then((results: SearchResult[]) => { + if (key != listInfo.key) return [] + setSearchText(text) + setSource(sourceId) + return setListInfo(results, page, text) + }) + } else { + if (listInfo?.key == key && listInfo?.list.length) return listInfo?.list + listInfo.key = key + return (musicSdk[sourceId]?.musicSearch.search(text, page, listInfo.limit).then((data: SearchResult) => { + if (key != listInfo.key) return [] + return setListInfo(data, page, text) + }) ?? Promise.reject(new Error('source not found: ' + sourceId))) + } +} + diff --git a/src/core/search/search.ts b/src/core/search/search.ts new file mode 100644 index 000000000..ecc9ebfe1 --- /dev/null +++ b/src/core/search/search.ts @@ -0,0 +1,39 @@ +import searchState from '@/store/search/state' +import searchActions from '@/store/search/action' +import { getSearchHistory as getSearchHistoryFromStore, saveSearchHistory } from '@/utils/data' +import settingState from '@/store/setting/state' + + +export const setSearchType: typeof searchActions['setSearchType'] = (type) => { + searchActions.setSearchType(type) +} +export const setSearchText: typeof searchActions['setSearchText'] = (text) => { + searchActions.setSearchText(text) +} +export const setTipListInfo: typeof searchActions['setTipListInfo'] = (text, source) => { + searchActions.setTipListInfo(text, source) +} +export const setTipList: typeof searchActions['setTipList'] = (list) => { + searchActions.setTipList(list) +} + +export const getSearchHistory = async() => { + if (!searchState.historyList.length) searchActions.setHistoryWord(await getSearchHistoryFromStore()) + return searchState.historyList +} +export const addHistoryWord = async(word: string) => { + if (!settingState.setting['search.isShowHistorySearch'] || !word) return + if (!searchState.historyList.length) searchActions.setHistoryWord(await getSearchHistoryFromStore()) + const list = searchActions.addHistoryWord(word) + if (!list) return + void saveSearchHistory(list) +} +export const removeHistoryWord = (index: number) => { + const list = searchActions.removeHistoryWord(index) + void saveSearchHistory(list) +} +export const clearHistoryList = () => { + const list = searchActions.clearHistoryList() + void saveSearchHistory(list) +} + diff --git a/src/core/search/songlist.ts b/src/core/search/songlist.ts new file mode 100644 index 000000000..9322c9958 --- /dev/null +++ b/src/core/search/songlist.ts @@ -0,0 +1,54 @@ +import searchSonglistState, { type SearchListInfo, type Source, type ListInfoItem } from '@/store/search/songlist/state' +import searchSonglistActions, { type SearchResult } from '@/store/search/songlist/action' +import musicSdk from '@/utils/musicSdk' + +export const setSource: typeof searchSonglistActions['setSource'] = (source) => { + searchSonglistActions.setSource(source) +} +export const setSearchText: typeof searchSonglistActions['setSearchText'] = (text) => { + searchSonglistActions.setSearchText(text) +} +const setListInfo: typeof searchSonglistActions.setListInfo = (result, page, text) => { + return searchSonglistActions.setListInfo(result, page, text) +} + +export const clearListInfo: typeof searchSonglistActions.clearListInfo = (source) => { + searchSonglistActions.clearListInfo(source) +} + + +export const search = async(text: string, page: number, sourceId: Source): Promise<ListInfoItem[]> => { + const listInfo = searchSonglistState.listInfos[sourceId] as SearchListInfo + // if (!text) return [] + const key = `${page}__${sourceId}__${text}` + if (listInfo.key == key && listInfo.list.length) return listInfo.list + if (sourceId == 'all') { + listInfo.key = key + let task = [] + for (const source of searchSonglistState.sources) { + if (source == 'all' || (page > 1 && page > (searchSonglistState.maxPages[source] as number))) continue + task.push(((musicSdk[source]?.songList.search(text, page, searchSonglistState.listInfos.all.limit) as Promise<SearchResult>) ?? Promise.reject(new Error('source not found: ' + source))).catch((error: any) => { + console.log(error) + return { + list: [], + total: 0, + limit: searchSonglistState.listInfos.all.limit, + source, + } + })) + } + return await Promise.all(task).then((results: SearchResult[]) => { + if (key != listInfo.key) return [] + setSearchText(text) + setSource(sourceId) + return setListInfo(results, page, text) + }) + } else { + if (listInfo?.key == key && listInfo?.list.length) return listInfo?.list + listInfo.key = key + return ((musicSdk[sourceId]?.songList.search(text, page, listInfo.limit) as Promise<SearchResult>).then((data: SearchResult) => { + if (key != listInfo.key) return [] + return setListInfo(data, page, text) + }) ?? Promise.reject(new Error('source not found: ' + sourceId))) + } +} diff --git a/src/core/songlist.ts b/src/core/songlist.ts new file mode 100644 index 000000000..057ef74c6 --- /dev/null +++ b/src/core/songlist.ts @@ -0,0 +1,231 @@ +import songlistState, { type TagInfo, type ListDetailInfo, type ListInfo, type SortInfo, type ListInfoItem } from '@/store/songlist/state' +import songlistActions from '@/store/songlist/action' +import { deduplicationList, toNewMusicInfo } from '@/utils' +import musicSdk from '@/utils/musicSdk' + + +interface DetailPageCache { data: ListDetailInfo, sourcePage: number } +type LimitDetailCache = Map<string, DetailPageCache | ListDetailInfo['list']> +type CacheValue = LimitDetailCache | ListInfo + +const cache = new Map<string, CacheValue>() +const LIST_LOAD_LIMIT = 30 + + +/** + * 设置要打开的歌单详情信息 + * @param source + * @returns + */ +export const setSelectListInfo = (info: ListInfoItem) => { + songlistActions.clearListDetail() + songlistActions.setSelectListInfo(info) +} + +/** + * 获取排序列表 + * @param source + * @returns + */ +export const getSortList = (source: LX.OnlineSource) => { + return songlistState.sortList[source] as SortInfo[] +} + +/** + * 获取标签列表 + * @param source + * @returns + */ +export const getTags = async<T extends LX.OnlineSource>(source: T) => { + if (songlistState.tags[source]) return songlistState.tags[source] as TagInfo<T> + const info = await (musicSdk[source]?.songList.getTags() as Promise<TagInfo<T>>) + songlistActions.setTags(info, source) + return info +} + +/** + * 设置列表加载加载前的基本信息(用于加载失败后的重新加载) + * @param source + * @param tagId + * @param sortId + */ +export const setListInfo: typeof songlistActions.setListInfo = (source, tagId, sortId) => { + clearList() + songlistActions.setListInfo(source, tagId, sortId) +} +/** + * 设置列表信息 + * @param result + * @param tagId + * @param sortId + * @param page + * @returns + */ +export const setList: typeof songlistActions.setList = (result, tagId, sortId, page) => { + return songlistActions.setList(result, tagId, sortId, page) +} + +export const clearList = () => { + songlistActions.clearList() +} + +/** + * 获取歌单列表 + * @param source 歌单源 + * @param tabId 类型id + * @param sortId 排序 + * @param page 页数 + * @param isRefresh 是否跳过缓存 + * @returns + */ +export const getList = async(source: LX.OnlineSource, tabId: string, sortId: string, page: number, isRefresh = false): Promise<ListInfo> => { + let pageKey = `slist__${source}__${sortId}__${tabId}__${page}` + + let listCache = cache.get(pageKey) as ListInfo + if (listCache) { + if (isRefresh) cache.delete(pageKey) + else return listCache + } + + return musicSdk[source]?.songList.getList(sortId, tabId, page).then((result: ListInfo) => { + cache.set(pageKey, result) + return result + // if (pageKey != listInfo.key) return + // setList(result, tabId, sortId, page) + }) +} + + +/** + * 获取歌单详情内单页分页歌曲(用于在本地控制每页大小) + * @param source 源 + * @param id 歌单id + * @param page 页数 + * @returns + */ +const getListDetailLimit = async(source: LX.OnlineSource, id: string, page: number): Promise<ListDetailInfo> => { + const listKey = `sdetail__${source}__${id}` + const prevPageKey = `sdetail__${source}__${id}__${page - 1}` + const tempListKey = `sdetail__${source}__${id}__temp` + + let listCache = cache.get(listKey) as LimitDetailCache + if (!listCache) cache.set(listKey, listCache = new Map()) + let sourcePage = 0 + { + const prevPageData = listCache.get(prevPageKey) as DetailPageCache + if (prevPageData) sourcePage = prevPageData.sourcePage + } + + return musicSdk[source]?.songList.getListDetail(id, sourcePage + 1).then((result: ListDetailInfo) => { + if (listCache !== cache.get(listKey)) return + result.list = deduplicationList(result.list.map(m => toNewMusicInfo(m)) as LX.Music.MusicInfoOnline[]) + let p = page + const tempList = listCache.get(tempListKey) as ListDetailInfo['list'] + if (tempList) { + listCache.delete(tempListKey) + listCache.set(`sdetail__${source}__${id}__${p}`, { + data: { + ...result, + list: [...tempList, ...result.list.splice(0, LIST_LOAD_LIMIT - tempList.length)], + page: p, + limit: LIST_LOAD_LIMIT, + }, + sourcePage, + }) + p++ + } + sourcePage++ + do { + if (result.list.length < LIST_LOAD_LIMIT && sourcePage < Math.ceil(result.total / result.limit)) { + listCache.set(tempListKey, result.list.splice(0, LIST_LOAD_LIMIT)) + break + } + listCache.set(`sdetail__${source}__${id}__${p}`, { + data: { + ...result, + list: result.list.splice(0, LIST_LOAD_LIMIT), + page: p, + limit: LIST_LOAD_LIMIT, + }, + sourcePage, + }) + p++ + } while (result.list.length > 0) + return (listCache.get(`sdetail__${source}__${id}__${page}`) as DetailPageCache).data + }) ?? Promise.reject(new Error('source not found')) +} + +/** + * 设置列表加载加载前的基本信息(用于加载失败后的重新加载) + * @param source + * @param tagId + * @param sortId + */ +export const setListDetailInfo: typeof songlistActions.setListDetailInfo = (source, id) => { + clearListDetail() + songlistActions.setListDetailInfo(source, id) +} +export const setListDetail: typeof songlistActions.setListDetail = (result, id, page) => { + return songlistActions.setListDetail(result, id, page) +} + +export const clearListDetail = () => { + songlistActions.clearListDetail() +} + +/** + * 获取歌单内单页歌曲 + * @param id 歌单id + * @param source 歌单源 + * @param isRefresh 是否跳过缓存 + * @returns + */ +export const getListDetail = async(id: string, source: LX.OnlineSource, page: number, isRefresh = false): Promise<ListDetailInfo> => { + const listKey = `sdetail__${source}__${id}` + const pageKey = `sdetail__${source}__${id}__${page}` + + let listCache = cache.get(listKey) as LimitDetailCache + if (!listCache || isRefresh) { + cache.set(listKey, listCache = new Map()) + } + + let pageCache = listCache.get(pageKey) as DetailPageCache + if (pageCache) return pageCache.data + + return getListDetailLimit(source, id, page) +} + +/** + * 获取歌单内全部歌曲 + * @param id 歌单id + * @param source 歌单源 + * @param isRefresh 是否跳过缓存 + * @returns + */ +export const getListDetailAll = async(source: LX.OnlineSource, id: string, isRefresh = false): Promise<LX.Music.MusicInfoOnline[]> => { + // console.log(tabId) + const listKey = `sdetail__${source}__${id}` + let listCache = cache.get(listKey) as LimitDetailCache + if (!listCache || isRefresh) { + cache.set(listKey, listCache = new Map()) + } + + const loadData = async(page: number): Promise<ListDetailInfo> => { + const pageKey = `sdetail__${source}__${id}__${page}` + let pageCache = listCache.get(pageKey) as DetailPageCache + if (pageCache) return pageCache.data + return getListDetailLimit(source, id, page) + } + return loadData(1).then(result => { + if (result.total <= result.limit) return result.list + + let maxPage = Math.ceil(result.total / result.limit) + const loadDetail = async(loadPage = 2): Promise<LX.Music.MusicInfoOnline[]> => { + return loadPage == maxPage + ? loadData(loadPage).then(result => result.list) + // eslint-disable-next-line @typescript-eslint/promise-function-async + : loadData(loadPage).then(result1 => loadDetail(++loadPage).then(result2 => [...result1.list, ...result2])) + } + return loadDetail().then(result2 => [...result.list, ...result2]) + }).then(list => deduplicationList(list)) +} diff --git a/src/core/sync.ts b/src/core/sync.ts new file mode 100644 index 000000000..78a342b98 --- /dev/null +++ b/src/core/sync.ts @@ -0,0 +1,10 @@ +import syncActions from '@/store/sync/action' + + +export const setSyncStatus = (status: LX.Sync.Status) => { + syncActions.setStatus(status) +} + +export const setSyncMessage = (message: LX.Sync.Status['message']) => { + syncActions.setMessage(message) +} diff --git a/src/core/syncSourceList.ts b/src/core/syncSourceList.ts new file mode 100644 index 000000000..e95ab3b05 --- /dev/null +++ b/src/core/syncSourceList.ts @@ -0,0 +1,32 @@ +// import { dateFormat } from '@/utils/common' +import { setListUpdateTime } from '@/utils/data' +import { overwriteListMusics, setFetchingListStatus } from './list' +import { getListDetailAll } from '@/core/songlist' +import { getListDetailAll as getBoardListAll } from '@/core/leaderboard' + +const fetchList = async(id: string, source: LX.OnlineSource, sourceListId: string) => { + setFetchingListStatus(id, true) + + let promise + if (/^board__/.test(sourceListId)) { + const id = sourceListId.replace(/^board__/, '') + promise = id ? getBoardListAll(id, true) : Promise.reject(new Error('id not defined: ' + sourceListId)) + } else { + promise = getListDetailAll(source, sourceListId, true) + } + return promise.finally(() => { + setFetchingListStatus(id, false) + }) +} + +export default async(targetListInfo: LX.List.UserListInfo) => { + // console.log(targetListInfo) + if (!targetListInfo.source || !targetListInfo.sourceListId) return + const list = await fetchList(targetListInfo.id, targetListInfo.source, targetListInfo.sourceListId) + // console.log(list) + void overwriteListMusics(targetListInfo.id, list) + const now = Date.now() + void setListUpdateTime(targetListInfo.id, now) + // TODO + // setUpdateTime(targetListInfo.id, dateFormat(now)) +} diff --git a/src/core/theme.ts b/src/core/theme.ts new file mode 100644 index 000000000..bb6de5844 --- /dev/null +++ b/src/core/theme.ts @@ -0,0 +1,20 @@ +import themeActions from '@/store/theme/action' +import { getTheme } from '@/theme/themes' +import { updateSetting } from './common' +import themeState from '@/store/theme/state' + +export const setShouldUseDarkColors = (shouldUseDarkColors: boolean) => { + themeActions.setShouldUseDarkColors(shouldUseDarkColors) +} + +export const applyTheme = (theme: LX.Theme) => { + themeActions.setTheme(theme) +} + +export const setTheme = (id: string) => { + updateSetting({ 'theme.id': id }) + void getTheme().then(theme => { + if (theme.id == themeState.theme.id) return + applyTheme(theme) + }) +} diff --git a/src/core/version.ts b/src/core/version.ts new file mode 100644 index 000000000..a8b7cf5fc --- /dev/null +++ b/src/core/version.ts @@ -0,0 +1,84 @@ +import { compareVer } from '@/utils' +import { downloadNewVersion, getVersionInfo } from '@/utils/version' +import versionActions from '@/store/version/action' +import versionState, { type InitState } from '@/store/version/state' +import { getIgnoreVersion, saveIgnoreVersion } from '@/utils/data' +import { showVersionModal } from '@/navigation' +import { Navigation } from 'react-native-navigation' + +export const showModal = () => { + if (versionState.showModal) return + versionActions.setVisibleModal(true) + showVersionModal() +} + +export const hideModal = (componentId: string) => { + if (!versionState.showModal) return + versionActions.setVisibleModal(false) + void Navigation.dismissOverlay(componentId) +} + +export const checkUpdate = async() => { + versionActions.setVersionInfo({ status: 'checking' }) + let versionInfo: InitState['versionInfo'] = { ...versionState.versionInfo } + try { + const { version, desc, history } = await getVersionInfo() + versionInfo.newVersion = { + version, + desc, + history, + } + } catch (err) { + versionInfo.newVersion = { + version: '0.0.0', + desc: '', + history: [], + } + } + // const versionInfo = { + // version: '1.9.0', + // desc: '- 更新xxx\n- 修复xxx123的萨达修复xxx123的萨达修复xxx123的萨达修复xxx123的萨达修复xxx123的萨达', + // history: [{ version: '1.8.0', desc: '- 更新xxx22\n- 修复xxx22' }, { version: '1.7.0', desc: '- 更新xxx22\n- 修复xxx22' }], + // } + if (versionInfo.version == '0.0.0') { + versionInfo.isUnknown = true + versionInfo.status = 'error' + } else { + versionInfo.status = 'idle' + } + versionInfo.isUnknown = false + if (compareVer(versionInfo.version, versionInfo.newVersion.version) != -1) { + versionInfo.isLatest = true + } + + versionActions.setVersionInfo(versionInfo) + + if (!versionInfo.isLatest) { + if (versionInfo.newVersion.version != await getIgnoreVersion()) { + showModal() + } + } + // console.log(compareVer(process.versions.app, versionInfo.version)) + // console.log(process.versions.app, versionInfo.version) +} + +export const downloadUpdate = () => { + versionActions.setVersionInfo({ status: 'downloading' }) + versionActions.setProgress({ total: 0, current: 0 }) + + downloadNewVersion(versionState.versionInfo.newVersion!.version, (total: number, current: number) => { + // console.log(total, current) + versionActions.setProgress({ total, current }) + }).then(() => { + versionActions.setVersionInfo({ status: 'downloaded' }) + }).catch(() => { + versionActions.setVersionInfo({ status: 'error' }) + // console.log(err) + }) +} + + +export const setIgnoreVersion = (version: InitState['ignoreVersion']) => { + versionActions.setIgnoreVersion(version) + saveIgnoreVersion(version) +} diff --git a/src/event/Event.ts b/src/event/Event.ts new file mode 100644 index 000000000..85abbdcfb --- /dev/null +++ b/src/event/Event.ts @@ -0,0 +1,57 @@ +// import mitt from 'mitt' +// import type { Emitter } from 'mitt' + +export default class Event { + listeners: Map<string, Array<(...args: any[]) => any>> + constructor() { + this.listeners = new Map() + } + + on(eventName: string, listener: (...args: any[]) => any) { + let targetListeners = this.listeners.get(eventName) + if (!targetListeners) this.listeners.set(eventName, targetListeners = []) + targetListeners.push(listener) + } + + off(eventName: string, listener: (...args: any[]) => any) { + let targetListeners = this.listeners.get(eventName) + if (!targetListeners) return + const index = targetListeners.indexOf(listener) + if (index < 0) return + targetListeners.splice(index, 1) + } + + emit(eventName: string, ...args: any[]) { + setImmediate(() => { + let targetListeners = this.listeners.get(eventName) + if (!targetListeners) return + for (const listener of targetListeners) { + listener(...args) + } + }) + } + + offAll(eventName: string) { + let targetListeners = this.listeners.get(eventName) + if (!targetListeners) return + this.listeners.delete(eventName) + } +} + +// export class App_EVENT { +// listeners: Map<string, Array<() => void>> +// constructor() { +// this.listeners = new Map() +// } + +// on(eventName: string, listener: () => void) { +// let targetListeners = this.listeners.get(eventName) +// if (targetListeners) this.listeners.set(eventName, targetListeners = []) +// targetListeners!.push(listener) +// } + +// off(eventName: string, listener: () => void) { + +// } +// } + diff --git a/src/event/appEvent.ts b/src/event/appEvent.ts new file mode 100644 index 000000000..2df6d8090 --- /dev/null +++ b/src/event/appEvent.ts @@ -0,0 +1,214 @@ +import { setNavActiveId } from '@/core/common' +import Event from './Event' +import commonState from '@/store/common/state' +import { type Source as SonglistSource } from '@/store/songlist/state' +import { type SearchType } from '@/store/search/state' + + +// { +// // sync: { +// // send_action_list: 'send_action_list', +// // handle_action_list: 'handle_action_list', +// // send_sync_list: 'send_sync_list', +// // handle_sync_list: 'handle_sync_list', +// // }, +// } + +export class AppEvent extends Event { + // configUpdate() { + // this.emit('configUpdate') + // } + + focus() { + this.emit('focus') + } + + /** + * 我的列表更新 + */ + mylistUpdated(lists: Array<LX.List.MyDefaultListInfo | LX.List.MyLoveListInfo | LX.List.UserListInfo>) { + this.emit('mylistUpdated', lists) + } + + /** + * 我的列表切换 + */ + mylistToggled(id: string) { + this.emit('listToggled', id) + } + + /** + * 音乐信息切换 + */ + musicToggled() { + this.emit('musicToggled') + } + + /** + * 手动改变进度 + * @param progress 进度 + */ + setProgress(progress: number, maxPlayTime?: number) { + this.emit('setProgress', progress, maxPlayTime) + } + + /** + * 设置音量大小 + * @param volume 音量大小 + */ + setVolume(volume: number) { + this.emit('setVolume', volume) + } + + /** + * 设置是否静音 + * @param isMute 是否静音 + */ + setVolumeIsMute(isMute: boolean) { + this.emit('setVolumeIsMute', isMute) + } + + // 播放器事件 + play() { + this.emit('play') + } + + pause() { + this.emit('pause') + } + + stop() { + this.emit('stop') + } + + error() { + this.emit('error') + } + + // 播放器原始事件 + playerPlaying() { + this.emit('playerPlaying') + } + + playerPause() { + this.emit('playerPause') + } + + // playerStop() { + // this.emit('playerStop') + // } + + playerEnded() { + this.emit('playerEnded') + } + + playerError() { + this.emit('playerError') + } + + // playerLoadeddata() { + // this.emit('playerLoadeddata') + // } + + playerLoadstart() { + this.emit('playerLoadstart') + } + + // playerCanplay() { + // this.emit('playerCanplay') + // } + + playerEmptied() { + this.emit('playerEmptied') + } + + playerWaiting() { + this.emit('playerWaiting') + } + + + // 更新图片事件 + picUpdated() { + this.emit('picUpdated') + } + + // 更新歌词事件 + lyricUpdated() { + this.emit('lyricUpdated') + } + + // 更新歌词偏移 + lyricOffsetUpdate() { + this.emit('lyricOffsetUpdate') + } + + // 我的列表内歌曲改变事件 + myListMusicUpdate(ids: string[]) { + if (!ids.length) return + this.emit('myListMusicUpdate', ids) + } + + // 下载列表改变事件 + downloadListUpdate() { + this.emit('downloadListUpdate') + } + + // 列表里的音乐信息改变事件 + musicInfoUpdate(musicInfo: LX.Music.MusicInfo) { + this.emit('musicInfoUpdate', musicInfo) + } + + changeMenuVisible(visible: boolean) { + this.emit('changeMenuVisible', visible) + } + + /** + * 搜索类型改变事件 + * @param type + */ + searchTypeChanged(type: SearchType) { + this.emit('searchTypeChanged', type) + } + + jumpListPosition() { + if (commonState.navActiveId == 'nav_love') { + this.emit('jumpListPosition') + } else { + global.lx.jumpMyListPosition = true + setNavActiveId('nav_love') + setTimeout(() => { + this.emit('jumpListPosition') + }, 200) + } + } + + changeLoveListVisible(visible: boolean) { + this.emit('changeLoveListVisible', visible) + } + + showSonglistTagList(source: SonglistSource, activeId: string) { + this.emit('showSonglistTagList', source, activeId) + } + + hideSonglistTagList() { + this.emit('hideSonglistTagList') + } + + songlistTagInfoChange(name: string, id: string) { + this.emit('songlistTagInfoChange', name, id) + } +} + + +type EventMethods = Omit<EventType, keyof Event> + + +declare class EventType extends AppEvent { + on<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): any + off<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): any +} + +export type AppEventTypes = Omit<EventType, keyof Omit<Event, 'on' | 'off'>> +export const createAppEventHub = (): AppEventTypes => { + return new AppEvent() +} diff --git a/src/event/listEvent.ts b/src/event/listEvent.ts new file mode 100644 index 000000000..27d466859 --- /dev/null +++ b/src/event/listEvent.ts @@ -0,0 +1,237 @@ +import Event from './Event' + +import { saveUserList, removeListMusics, saveListMusics } from '@/utils/data' +import { + userLists, + userListCreate, + userListsUpdate, + userListsRemove, + userListsUpdatePosition, + listDataOverwrite, + listMusicOverwrite, + listMusicAdd, + listMusicMove, + listMusicRemove, + listMusicUpdateInfo, + listMusicUpdatePosition, + listMusicClear, + allMusicList, +} from '@/utils/listManage' +import { LIST_IDS } from '@/config/constant' +import { setActiveList, setUserList } from '@/core/list' +import listState from '@/store/list/state' + +const updateUserList = async(userLists: LX.List.UserListInfo[]) => { + await saveUserList(userLists) + setUserList(userLists) +} + +const checkListExist = (changedIds: string[]) => { + const index = changedIds.indexOf(listState.activeListId) + if (index < 0) return + setActiveList(LIST_IDS.DEFAULT) +} + +export const checkUpdateList = async(changedIds: string[]) => { + if (!changedIds.length) return + await saveListMusics(changedIds.map(id => ({ id, musics: allMusicList.get(id) as LX.List.ListMusics }))) + global.app_event.myListMusicUpdate(changedIds) +} + + +// { +// // sync: { +// // send_action_list: 'send_action_list', +// // handle_action_list: 'handle_action_list', +// // send_sync_list: 'send_sync_list', +// // handle_sync_list: 'handle_sync_list', +// // }, +// } + +export class ListEvent extends Event { + /** + * 现有歌曲列表更改时触发的事件 + * @param ids + */ + // list_music_changed(ids: string[]) { + // this.emit('list_music_changed', ids) + // } + + /** + * 覆盖整个列表数据 + * @param listData 列表数据 + * @param isRemote 是否属于远程操作 + */ + async list_data_overwrite(listData: MakeOptional<LX.List.ListDataFull, 'tempList'>, isRemote: boolean = false) { + const oldIds = userLists.map(l => l.id) + const changedIds = listDataOverwrite(listData) + await updateUserList(userLists) + // await checkUpdateList(changedIds) + const removedList = oldIds.filter(id => !allMusicList.has(id)) + if (removedList.length) await removeListMusics(removedList) + const allListIds = [LIST_IDS.DEFAULT, LIST_IDS.LOVE, ...userLists.map(l => l.id)] + if (changedIds.includes(LIST_IDS.TEMP)) allListIds.push(LIST_IDS.TEMP) + await saveListMusics([...allListIds.map(id => ({ id, musics: allMusicList.get(id) as LX.List.ListMusics }))]) + + global.app_event.myListMusicUpdate(changedIds) + this.emit('list_data_overwrite', listData, isRemote) + checkListExist(changedIds) + } + + /** + * 批量创建列表 + * @param position 列表位置 + * @param lists 列表信息 + * @param isRemote 是否属于远程操作 + */ + async list_create(position: number, lists: LX.List.UserListInfo[], isRemote: boolean = false) { + // const changedIds: string[] = [] + for (const list of lists) { + userListCreate({ ...list, position }) + // changedIds.push(list.id) + } + await updateUserList(userLists) + this.emit('list_create', position, lists, isRemote) + } + + /** + * 批量删除列表及列表内歌曲 + * @param ids 列表ids + * @param isRemote 是否属于远程操作 + */ + async list_remove(ids: string[], isRemote: boolean = false) { + const changedIds = userListsRemove(ids) + await updateUserList(userLists) + await removeListMusics(ids) + this.emit('list_remove', ids, isRemote) + global.app_event.myListMusicUpdate(changedIds) + + checkListExist(changedIds) + } + + /** + * 批量更新列表信息 + * @param lists 列表信息 + * @param isRemote 是否属于远程操作 + */ + async list_update(lists: LX.List.UserListInfo[], isRemote: boolean = false) { + userListsUpdate(lists) + await updateUserList(userLists) + this.emit('list_update', lists, isRemote) + } + + /** + * 批量更新列表位置 + * @param position 列表位置 + * @param ids 列表ids + * @param isRemote 是否属于远程操作 + */ + async list_update_position(position: number, ids: string[], isRemote: boolean = false) { + userListsUpdatePosition(position, ids) + await updateUserList(userLists) + this.emit('list_update_position', position, ids, isRemote) + } + + /** + * 覆盖列表内歌曲 + * @param listId 列表id + * @param musicInfos 音乐信息 + * @param isRemote 是否属于远程操作 + */ + async list_music_overwrite(listId: string, musicInfos: LX.Music.MusicInfo[], isRemote: boolean = false) { + const changedIds = await listMusicOverwrite(listId, musicInfos) + await checkUpdateList(changedIds) + this.emit('list_music_overwrite', listId, musicInfos, isRemote) + } + + /** + * 批量添加歌曲到列表 + * @param listId 列表id + * @param musicInfos 添加的歌曲信息 + * @param addMusicLocationType 添加在到列表的位置 + * @param isRemote 是否属于远程操作 + */ + async list_music_add(listId: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) { + const changedIds = await listMusicAdd(listId, musicInfos, addMusicLocationType) + await checkUpdateList(changedIds) + this.emit('list_music_add', listId, musicInfos, addMusicLocationType, isRemote) + } + + /** + * 批量移动歌曲 + * @param fromId 源列表id + * @param toId 目标列表id + * @param musicInfos 移动的歌曲信息 + * @param addMusicLocationType 添加在到列表的位置 + * @param isRemote 是否属于远程操作 + */ + async list_music_move(fromId: string, toId: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) { + const changedIds = await listMusicMove(fromId, toId, musicInfos, addMusicLocationType) + await checkUpdateList(changedIds) + this.emit('list_music_move', fromId, toId, musicInfos, addMusicLocationType, isRemote) + } + + /** + * 批量移除歌曲 + * @param listId + * @param listId 列表Id + * @param ids 要删除歌曲的id + * @param isRemote 是否属于远程操作 + */ + async list_music_remove(listId: string, ids: string[], isRemote: boolean = false) { + const changedIds = await listMusicRemove(listId, ids) + // console.log(changedIds) + await checkUpdateList(changedIds) + this.emit('list_music_remove', listId, ids, isRemote) + } + + /** + * 批量更新歌曲信息 + * @param musicInfos 歌曲&列表信息 + * @param isRemote 是否属于远程操作 + */ + async list_music_update(musicInfos: LX.List.ListActionMusicUpdate, isRemote: boolean = false) { + const changedIds = await listMusicUpdateInfo(musicInfos) + await checkUpdateList(changedIds) + this.emit('list_music_update', musicInfos, isRemote) + } + + /** + * 清空列表内的歌曲 + * @param ids 列表Id + * @param isRemote 是否属于远程操作 + */ + async list_music_clear(ids: string[], isRemote: boolean = false) { + const changedIds = await listMusicClear(ids) + await checkUpdateList(changedIds) + this.emit('list_music_clear', ids, isRemote) + } + + /** + * 批量更新歌曲位置 + * @param listId 列表ID + * @param position 新位置 + * @param ids 歌曲id + * @param isRemote 是否属于远程操作 + */ + async list_music_update_position(listId: string, position: number, ids: string[], isRemote: boolean = false) { + const changedIds = await listMusicUpdatePosition(listId, position, ids) + await checkUpdateList(changedIds) + this.emit('list_music_update_position', listId, position, ids, isRemote) + } +} + + +type EventMethods = Omit<EventType, keyof Event> + + +declare class EventType extends ListEvent { + on<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): any + off<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): any +} + +export type ListEventTypes = Omit<EventType, keyof Omit<Event, 'on' | 'off'>> +export const createListEventHub = (): ListEventTypes => { + return new ListEvent() +} + diff --git a/src/event/stateEvent.ts b/src/event/stateEvent.ts new file mode 100644 index 000000000..8721c7d17 --- /dev/null +++ b/src/event/stateEvent.ts @@ -0,0 +1,125 @@ +import Event from './Event' +import type { InitState as CommonState } from '@/store/common/state' +import type { InitState as ListState } from '@/store/list/state' +import type { InitState as PlayerState } from '@/store/player/state' +import type { InitState as VersionState } from '@/store/version/state' + + +// { +// // sync: { +// // send_action_list: 'send_action_list', +// // handle_action_list: 'handle_action_list', +// // send_sync_list: 'send_sync_list', +// // handle_sync_list: 'handle_sync_list', +// // }, +// } + +export class StateEvent extends Event { + configUpdated(keys: Array<keyof LX.AppSetting>, setting: Partial<LX.AppSetting>) { + this.emit('configUpdated', keys, setting) + } + + fontSizeUpdated(size: number) { + this.emit('fontSizeUpdated', size) + } + + apiSourceUpdated(source: LX.AppSetting['common.apiSource']) { + this.emit('apiSourceUpdated', source) + } + + themeUpdated(theme: LX.ActiveTheme) { + this.emit('themeUpdated', theme) + } + + playerMusicInfoChanged(musicInfo: PlayerState['musicInfo']) { + this.emit('playerMusicInfoChanged', musicInfo) + } + + playMusicInfoChanged(playMusicInfo: PlayerState['playMusicInfo']) { + this.emit('playMusicInfoChanged', playMusicInfo) + } + + playInfoChanged(playInfo: PlayerState['playInfo']) { + this.emit('playInfoChanged', playInfo) + } + + playStateTextChanged(text: PlayerState['statusText']) { + this.emit('playStateTextChanged', text) + } + + playStateChanged(state: PlayerState['isPlay']) { + this.emit('playStateChanged', state) + } + + playProgressChanged(progress: PlayerState['progress']) { + this.emit('playProgressChanged', progress) + } + + playPlayedListChanged(playedList: PlayerState['playedList']) { + this.emit('playPlayedListChanged', playedList) + } + + playTempPlayListChanged(tempPlayList: PlayerState['tempPlayList']) { + this.emit('playTempPlayListChanged', tempPlayList) + } + + /** + * 我的列表更新 + */ + mylistUpdated(lists: Array<LX.List.MyDefaultListInfo | LX.List.MyLoveListInfo | LX.List.UserListInfo>) { + this.emit('mylistUpdated', lists) + } + + /** + * 我的列表切换 + */ + mylistToggled(id: string) { + this.emit('mylistToggled', id) + } + + fetchingListStatusUpdated(fetchingListStatus: ListState['fetchingListStatus']) { + this.emit('fetchingListStatusUpdated', fetchingListStatus) + } + + syncStatusUpdated(status: LX.Sync.Status) { + this.emit('syncStatusUpdated', status) + } + + versionInfoUpdated(info: VersionState['versionInfo']) { + this.emit('versionInfoUpdated', info) + } + + versionInfoIgnoreVersionUpdated(version: VersionState['ignoreVersion']) { + this.emit('versionInfoIgnoreVersionUpdated', version) + } + + versionDownloadProgressUpdated(progress: VersionState['progress']) { + this.emit('versionDownloadProgressUpdated', progress) + } + + componentIdsUpdated(ids: CommonState['componentIds']) { + this.emit('componentIdsUpdated', ids) + } + + navActiveIdUpdated(index: CommonState['navActiveId']) { + this.emit('navActiveIdUpdated', index) + } + + sourceNamesUpdated(names: CommonState['sourceNames']) { + this.emit('sourceNamesUpdated', names) + } +} + + +type EventMethods = Omit<EventType, keyof Event> + + +declare class EventType extends StateEvent { + on<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): any + off<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): any +} + +export type StateEventTypes = Omit<EventType, keyof Omit<Event, 'on' | 'off'>> +export const createStateEventHub = (): StateEventTypes => { + return new StateEvent() +} diff --git a/src/lang/en_us.json b/src/lang/en_us.json index 4a2513064..2e407857c 100644 --- a/src/lang/en_us.json +++ b/src/lang/en_us.json @@ -13,11 +13,13 @@ "collect_songlist": "Collection Songlist", "collect_success": "Collection success", "collect_toplist": "Collection Toplist", + "comment_not support": "This song does not support getting comments", "comment_refresh": "This is already {{name}}'s comment", "comment_tab_hot": "Hot {{total}}", "comment_tab_new": "New {{total}}", "comment_title": "{{name}}-{{singer}}'s comment", "confirm": "Confirm", + "confirm_button_text": "Yes", "confirm_tip": "Just to double check, do you really want to do this?", "copy_name": "Share song", "copy_name_tip": "Copied", @@ -32,19 +34,23 @@ "dialog_confirm": "OK", "disagree": "Disagree", "disagree_tip": "Cancelled...", + "duplicate_list_tip": "You have previously favorited the list [{{name}}], do you want to update the songs?", "input_error": "Don't input indiscriminately 😡", "list_add_btn_title": "Add the song(s) to {{name}}", + "list_add_tip_exists": "This song already exists in the list, don't click me again~😡", "list_add_title_first_add": "Add", "list_add_title_first_move": "Move", "list_add_title_last": "to...", "list_create": "Create a new list", "list_create_input_placeholder": "What name do you think of...", + "list_edit_action_tip_add_failed": "add failed", "list_edit_action_tip_add_success": "Added successfully", "list_edit_action_tip_exist": "This song already exists in this list", + "list_edit_action_tip_move_failed": "failed to move", "list_edit_action_tip_move_success": "Moved successfully", "list_edit_action_tip_remove_success": "Removed successfully", "list_end": "In The End", - "list_error": "Loading failed 😥", + "list_error": "Loading failed😥, click to try to reload", "list_export": "Export", "list_export_part_desc": "Choose where to save the list file", "list_import": "Import", @@ -63,24 +69,35 @@ "list_multi_add_title_first_move": "Move the selected one", "list_multi_add_title_last": "First song to...", "list_remove": "Remove", + "list_remove_music_multi_tip": "Do you really want to remove the selected {{num}} songs?", + "list_remove_tip": "Do you really want to remove {{name}}?", "list_remove_tip_button": "Yes, that's right", "list_rename": "Rename", "list_rename_title": "Rename List", "list_select_all": "Select All", "list_select_cancel": "Cancel", + "list_select_local_file": "add local songs", "list_select_range": "range", "list_select_single": "Single Select", "list_select_unall": "Reverse Selection", "list_sync": "Update", "list_sync_confirm_tip": "This will replace the songs in {{name}} with the songs in the online list, are you sure you want to update?", - "list_update_error": "Update failed", - "list_update_success": "Update completed", + "list_temp": "Temp list", + "list_update_error": "{{name}} failed to update", + "list_update_success": "{{name}} updated successfully", "load_failed": "Ah, loading failed 😥", "loading": "Loading...", + "lyric__load_error": "Failed to get lyrics", "move_to": "Move to...", "name": "Name: {{name}}", - "nav_my_list": "My list", + "nav_exit": "Exit application", + "nav_love": "Collection", + "nav_search": "Search", + "nav_setting": "Setting", + "nav_songlist": "Song list", + "nav_top": "Leaderboard", "never_show": "Never show again", + "no_item": "The list is empty...", "notifications_check_tip": "You have not allowed LX Music to display notifications, or the Music Service in the LX Music notification settings has been disabled, which will prevent you from using the notification bar to pause, switch songs, etc. Do you want to enable it?", "notifications_check_title": "Notification permission reminder", "ok": "OK", @@ -97,10 +114,21 @@ "play_prev": "Previous song", "play_single": "Disable song switching", "play_single_loop": "Single loop playback", + "player__buffering": "buffering...", + "player__end": "finished playing", + "player__error": "Audio loading error, switch to next track after 5 seconds", + "player__geting_url": "Acquiring the song link...", + "player__loading": "Music loading...", + "player__refresh_url": "The URL has expired, refreshing the URL...", "player_setting_lrc_font_size": "Lyric font size setting", "quality_high_quality": "HQ", "quality_lossless": "SQ", "quality_lossless_24bit": "Hires", + "search__welcome": "Search what I want~~😉", + "search_history_search": "History search", + "search_hot_search": "popular searches", + "search_type_music": "Music", + "search_type_songlist": "Song list", "setting_about": "About LX Music", "setting_backup": "Backup and Recovery", "setting_backup_all": "All data (list data and setting data)", @@ -118,6 +146,7 @@ "setting_backup_part_export_setting_desc": "Save the list to...", "setting_backup_part_import_list": "Import List", "setting_backup_part_import_list_desc": "Select the list of backup files", + "setting_backup_part_import_list_tip_error": "List import failed 😕", "setting_backup_part_import_list_tip_runing": "🚀I am trying to import...\nIf the list is too big, it may take some time⏳", "setting_backup_part_import_list_tip_success": "Import successful 🎉", "setting_backup_part_import_list_tip_unzip": "📦File parsing...\nIf the file is too large, it may take some time⏳", @@ -126,6 +155,17 @@ "setting_basic": "General", "setting_basic_animation": "Random pop-up animation", "setting_basic_auto_hide_play_bar": "Auto hide playbar when keyboard pops up", + "setting_basic_drawer_layout_position": "Navigation, favorite list pop-up direction", + "setting_basic_drawer_layout_position_left": "Left side", + "setting_basic_drawer_layout_position_right": "Right side", + "setting_basic_font_size": "Font size setting [effective after restart]", + "setting_basic_font_size_100": "standard", + "setting_basic_font_size_110": "Big", + "setting_basic_font_size_120": "bigger", + "setting_basic_font_size_130": "Very big", + "setting_basic_font_size_80": "smaller", + "setting_basic_font_size_90": "Small", + "setting_basic_font_size_preview": "LX Music Font Size Preview", "setting_basic_lang": "Language", "setting_basic_share_type": "Share", "setting_basic_share_type_clipboard": "copy to clipboard", @@ -171,6 +211,7 @@ "setting_other_cache": "Cache management (including the cache of songs, lyrics, error logs, etc., it is not recommended to clean up if there is no problem related to song playback)", "setting_other_cache_clear_btn": "Clear Cache", "setting_other_cache_clear_success_tip": "Cache clearing completed", + "setting_other_cache_getting": "Statistics cached...", "setting_other_cache_size": "Currently used cache size: ", "setting_other_log": "Error log (log when abnormal operation occurs)", "setting_other_log_btn_clean": "Clear", @@ -192,8 +233,13 @@ "setting_play_show_notification_image": "Show song picture in notification bar", "setting_play_show_roma": "Show lyrics roman (if available)", "setting_play_show_translation": "Show lyrics translation (if available)", + "setting_player_save_play_time": "Remember playback progress", + "setting_search": "Search settings", + "setting_search_show_history_search": "show search history", + "setting_search_show_hot_search": "show popular searches", "setting_sync": "Synchronization [It is recommended to back up the playlist before using it for the first time]", "setting_sync_address": "Local IP address: {{address}}", + "setting_sync_code_blocked_ip": "The IP of the current device has been blocked by the server!", "setting_sync_code_fail": "Invalid connection code", "setting_sync_code_input_tip": "Please enter the connection code", "setting_sync_code_label": "You need to enter the connection code for the first connection", @@ -219,6 +265,8 @@ "songlist_open_input_tip": "1. Cross-source opening of the playlist is not supported. Please confirm whether the playlist to be opened corresponds to the current playlist source\n2. If you encounter a playlist link that cannot be opened, feedback is welcome\n3, Kugou source Open with playlist ID is not supported, but Kugou code is supported", "songlist_recommend": "Recommend", "songlist_rise": "Rise", + "songlist_tag_default": "Default", + "songlist_tag_hot": "Hot", "songlist_tags": "Playlist category", "source_alias_all": "Aggregated", "source_alias_bd": "BD Music", @@ -243,8 +291,11 @@ "theme_black": "Black", "theme_blue": "Blue", "theme_blue2": "Purple Blue", + "theme_blue_plus": "Blue Plus", + "theme_china_ink": "China Ink", "theme_green": "Green", "theme_grey": "Grey", + "theme_happy_new_year": "New Year", "theme_mid_autumn": "Mid-Autumn", "theme_ming": "Ming", "theme_naruto": "Naruto", @@ -252,21 +303,24 @@ "theme_pink": "Pink", "theme_purple": "Purple", "theme_red": "Red", - "theme_yellow": "Yellow", "timeout_exit_btn_cancel": "Cancel timing", "timeout_exit_btn_update": "Update timing", "timeout_exit_btn_wait_cancel": "Cancel exit", "timeout_exit_btn_wait_tip": "Timeout expired, waiting to exit...", + "timeout_exit_input_tip": "Enter countdown minutes", "timeout_exit_label_isPlayed": "Wait for the song to finish playing and then stop playing", "timeout_exit_min": "Minutes", "timeout_exit_tip_cancel": "Timeout stop playing has been cancelled", "timeout_exit_tip_max": "You can only set up to {{num}} minutes", "timeout_exit_tip_off": "Set timer to stop playing", "timeout_exit_tip_on": "Stop playing after {{time}}", + "toggle_source_failed": "Failed to change the source, please try to manually search for the song in other sources to play", + "toggle_source_try": "Try switching to another source...", "version_btn_close": "Close", "version_btn_downloading": "I am trying to download...{{total}}/{{current}} ({{progress}}%)", "version_btn_failed": "Retry", "version_btn_ignore": "Ignore", + "version_btn_ignore_cancel": "Cancel ignore", "version_btn_min": "Background download", "version_btn_new": "Update", "version_btn_unknown": "Project Homepage", diff --git a/src/lang/i18n.ts b/src/lang/i18n.ts new file mode 100644 index 000000000..5b0047e6c --- /dev/null +++ b/src/lang/i18n.ts @@ -0,0 +1,98 @@ +import { useState, useEffect, useCallback } from 'react' +import type { Messages, Message } from './index' +import { messages } from './index' + + +type TranslateValues = Record<string, string | number | boolean> + +type Langs = keyof Messages + +type Hook = (locale: Langs) => void + +export declare interface I18n { + locale: Langs + fallbackLocale: Langs + availableLocales: Langs[] + messages: Messages + message: Message + setLanguage: (locale: Langs) => void + fillMessage: (message: string, val: TranslateValues) => string + getMessage: (key: keyof Message, val?: TranslateValues) => string + t: (key: keyof Message, val?: TranslateValues) => string +} + +let locale: Langs = 'zh_cn' + +let i18n: I18n + + +const hookTools = { + hooks: [] as Hook[], + add(hook: Hook) { + this.hooks.push(hook) + }, + remove(hook: Hook) { + this.hooks.splice(this.hooks.indexOf(hook), 1) + }, + update(locale: Parameters<Hook>[0]) { + for (const hook of this.hooks) hook(locale) + }, +} + +const useI18n = () => { + const [locale, updateLocale] = useState(i18n.locale) + // console.log('hook run') + useEffect(() => { + const hook: Hook = (locale) => { + updateLocale(locale) + } + hookTools.add(hook) + return () => { hookTools.remove(hook) } + }, []) + + return useCallback((key: keyof Message, val?: TranslateValues): string => { + return i18n.getMessage(key, val) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [locale]) +} + +const setLanguage = (lang: Langs) => { + i18n.setLanguage(lang) +} + +const createI18n = (_locale: Langs = locale): I18n => { + locale = _locale + + return i18n = { + locale, + fallbackLocale: 'zh_cn', + availableLocales: Object.keys(messages) as Langs[], + messages, + message: messages[locale], + setLanguage(_locale: Langs) { + this.locale = _locale + this.message = messages[_locale] + hookTools.update(_locale) + }, + fillMessage(message: string, vals: TranslateValues): string { + for (const [key, val] of Object.entries(vals)) { + message = message.replace(new RegExp('{{' + key + '}}', 'g'), String(val)) + } + return message + }, + getMessage(key: keyof Message, val?: TranslateValues): string { + let targetMessage = this.message[key] ?? this.messages[this.fallbackLocale][key] ?? '' + return val ? this.fillMessage(targetMessage, val) : targetMessage + }, + t(key: keyof Message, val?: TranslateValues): string { + return this.getMessage(key, val) + }, + } +} + + +export { + setLanguage, + useI18n, + createI18n, +} diff --git a/src/lang/index.js b/src/lang/index.js deleted file mode 100644 index 8700adc8d..000000000 --- a/src/lang/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import zh_cn from './zh_cn.json' -import en_us from './en_us.json' - -export default [ - { - id: 'zh_cn', - name: '简体中文', - translation: zh_cn, - }, - { - id: 'en_us', - name: 'English', - translation: en_us, - }, -] diff --git a/src/lang/index.ts b/src/lang/index.ts new file mode 100644 index 000000000..6cd88df68 --- /dev/null +++ b/src/lang/index.ts @@ -0,0 +1,54 @@ +import zh_cn from './zh_cn.json' +import en_us from './en_us.json' + +type Message = Record<keyof typeof zh_cn, string> +| Record<keyof typeof en_us, string> + + +const langs = [ + { + name: '简体中文', + locale: 'zh_cn', + // alternate: 'zh-hans', + country: 'cn', + fallback: true, + message: zh_cn, + }, + { + name: 'English', + locale: 'en_us', + country: 'us', + message: en_us, + }, +] as const + +const langList: Array<{ + name: string + locale: (typeof langs)[number]['locale'] + // alternate?: string +}> = [] +type Messages = Record<(typeof langs)[number]['locale'], Message> + +// @ts-expect-error +const messages: Messages = {} + +langs.forEach(item => { + langList.push({ + name: item.name, + locale: item.locale, + // alternate: item.alternate, + }) + messages[item.locale] = item.message +}) + +export { + langList, + messages, +} + +export type { + Messages, + Message, +} + +export * from './i18n' diff --git a/src/lang/zh_cn.json b/src/lang/zh_cn.json index 124f92d82..89edaf4fd 100644 --- a/src/lang/zh_cn.json +++ b/src/lang/zh_cn.json @@ -13,11 +13,13 @@ "collect_songlist": "收藏歌单", "collect_success": "收藏成功", "collect_toplist": "收藏排行榜", + "comment_not support": "该歌曲不支持获取评论", "comment_refresh": "这已经是 {{name}} 的评论啦", "comment_tab_hot": "热门 {{total}}", "comment_tab_new": "最新 {{total}}", "comment_title": "{{name}} - {{singer}} 的评论", "confirm": "确认", + "confirm_button_text": "是的", "confirm_tip": "再确认一下,你真的要这样做吗?", "copy_name": "分享歌曲", "copy_name_tip": "已复制", @@ -32,19 +34,23 @@ "dialog_confirm": "好的", "disagree": "我就不", "disagree_tip": "那算了... 🙄", + "duplicate_list_tip": "你之前已收藏过该列表 [{{name}}],是否需要更新里面的歌曲?", "input_error": "不要乱输好吧😡", "list_add_btn_title": "把该歌曲添加到 {{name}}", + "list_add_tip_exists": "列表已经存在这首歌啦,不要再点我啦~😡", "list_add_title_first_add": "添加", "list_add_title_first_move": "移动", "list_add_title_last": "到...", "list_create": "新建列表", "list_create_input_placeholder": "你想起啥名...", + "list_edit_action_tip_add_failed": "添加失败", "list_edit_action_tip_add_success": "添加成功", "list_edit_action_tip_exist": "该列表已经有这首歌啦", + "list_edit_action_tip_move_failed": "移动失败", "list_edit_action_tip_move_success": "移动成功", "list_edit_action_tip_remove_success": "移除成功", "list_end": "到底啦~", - "list_error": "加载失败😥", + "list_error": "加载失败😥,点击尝试重新加载", "list_export": "导出", "list_export_part_desc": "选择列表文件保存位置", "list_import": "导入", @@ -63,25 +69,35 @@ "list_multi_add_title_first_move": "移动已选的", "list_multi_add_title_last": "首歌曲到...", "list_remove": "移除", + "list_remove_music_multi_tip": "你真的想要移除所选的 {{num}} 首歌曲吗?", "list_remove_tip": "你真的想要移除 {{name}} 吗?", "list_remove_tip_button": "是的 没错", "list_rename": "重命名", "list_rename_title": "重命名列表", "list_select_all": "全选", "list_select_cancel": "取消", + "list_select_local_file": "添加本地歌曲", "list_select_range": "区间", "list_select_single": "单选", "list_select_unall": "反选", "list_sync": "更新", "list_sync_confirm_tip": "这将会把 {{name}} 内的歌曲替换成在线列表的歌曲,你确认要更新吗?", - "list_update_error": "更新失败", - "list_update_success": "更新成功", + "list_temp": "临时列表", + "list_update_error": "{{name}} 更新失败", + "list_update_success": "{{name}} 更新成功", "load_failed": "啊 加载失败了 😥", "loading": "加载中...", + "lyric__load_error": "歌词获取失败", "move_to": "移动到...", "name": "歌曲名:{{name}}", - "nav_my_list": "我的列表", + "nav_exit": "退出应用", + "nav_love": "我的收藏", + "nav_search": "搜索", + "nav_setting": "设置", + "nav_songlist": "歌单", + "nav_top": "排行榜", "never_show": "不再提醒", + "no_item": "列表竟然是空的...", "notifications_check_tip": "你没有允许LX Music显示通知,或LX Music通知设置里的Music Service通知被禁用,这将无法使用通知栏进行暂停、切歌等操作,是否去开启?", "notifications_check_title": "通知权限提醒", "ok": "我知道了", @@ -98,10 +114,21 @@ "play_prev": "上一曲", "play_single": "禁用歌曲切换", "play_single_loop": "单曲循环播放", + "player__buffering": "缓冲中...", + "player__end": "播放完毕", + "player__error": "音频加载出错,5 秒后切换下一首", + "player__geting_url": "歌曲链接获取中...", + "player__loading": "音乐加载中...", + "player__refresh_url": "URL过期,正在刷新URL...", "player_setting_lrc_font_size": "歌词字体大小设置", - "quality_high_quality": "高品质", - "quality_lossless": "无损", + "quality_high_quality": "HQ", + "quality_lossless": "SQ", "quality_lossless_24bit": "Hires", + "search__welcome": "搜我所想~~😉", + "search_history_search": "历史搜索", + "search_hot_search": "热门搜索", + "search_type_music": "歌曲", + "search_type_songlist": "歌单", "setting_about": "关于洛雪音乐", "setting_backup": "备份与恢复", "setting_backup_all": "所有数据(列表数据与设置数据)", @@ -119,6 +146,7 @@ "setting_backup_part_export_setting_desc": "选择设置保存位置", "setting_backup_part_import_list": "导入列表", "setting_backup_part_import_list_desc": "选择列表备份文件", + "setting_backup_part_import_list_tip_error": "列表导入失败😕", "setting_backup_part_import_list_tip_runing": "🚀正在努力导入中...\n若列表太大可能需要一些时间⏳", "setting_backup_part_import_list_tip_success": "导入成功🎉", "setting_backup_part_import_list_tip_unzip": "📦文件解析中...\n若文件太大可能需要一些时间⏳", @@ -127,6 +155,17 @@ "setting_basic": "基本设置", "setting_basic_animation": "弹出层随机动画", "setting_basic_auto_hide_play_bar": "弹出键盘时自动隐藏播放栏", + "setting_basic_drawer_layout_position": "导航、收藏列表弹出方向", + "setting_basic_drawer_layout_position_left": "左侧", + "setting_basic_drawer_layout_position_right": "右侧", + "setting_basic_font_size": "字体大小设置 [重启后生效]", + "setting_basic_font_size_100": "标准", + "setting_basic_font_size_110": "大", + "setting_basic_font_size_120": "较大", + "setting_basic_font_size_130": "非常大", + "setting_basic_font_size_80": "较小", + "setting_basic_font_size_90": "小", + "setting_basic_font_size_preview": "LX Music 字体大小预览", "setting_basic_lang": "语言", "setting_basic_share_type": "分享方式", "setting_basic_share_type_clipboard": "复制到剪贴板", @@ -172,6 +211,7 @@ "setting_other_cache": "缓存管理(包括歌曲、歌词、错误日志等缓存,没有歌曲播放相关的问题不建议清理)", "setting_other_cache_clear_btn": "清理缓存", "setting_other_cache_clear_success_tip": "缓存清理完成", + "setting_other_cache_getting": "统计缓存中...", "setting_other_cache_size": "当前已用缓存大小:", "setting_other_log": "错误日志(运行发生异常时的日志)", "setting_other_log_btn_clean": "清空", @@ -193,8 +233,13 @@ "setting_play_show_notification_image": "在通知栏显示歌曲图片", "setting_play_show_roma": "显示歌词罗马音(如果可用)", "setting_play_show_translation": "显示歌词翻译(如果可用)", + "setting_player_save_play_time": "记住播放进度", + "setting_search": "搜索设置", + "setting_search_show_history_search": "显示历史搜索记录", + "setting_search_show_hot_search": "显示热门搜索", "setting_sync": "同步 [首次使用前建议先备份一次歌单]", "setting_sync_address": "本机IP地址:{{address}}", + "setting_sync_code_blocked_ip": "当前设备的IP已被服务端封禁!", "setting_sync_code_fail": "连接码无效", "setting_sync_code_input_tip": "请输入连接码", "setting_sync_code_label": "首次连接需要输入连接码", @@ -221,6 +266,8 @@ "songlist_open_input_tip": "1、不支持跨源打开歌单,请确认要打开的歌单与当前歌单源是否对应\n2、若遇到无法打开的歌单链接,欢迎反馈\n3、酷狗源不支持用歌单ID打开,但支持酷狗码打开", "songlist_recommend": "推荐", "songlist_rise": "飙升", + "songlist_tag_default": "默认", + "songlist_tag_hot": "热门", "songlist_tags": "歌单类别", "source_alias_all": "聚合大会", "source_alias_bd": "小杜音乐", @@ -245,8 +292,11 @@ "theme_black": "黑灯瞎火", "theme_blue": "蓝田生玉", "theme_blue2": "清热版蓝", + "theme_blue_plus": "蛋雅深蓝", + "theme_china_ink": "近墨者黑", "theme_green": "绿意盎然", "theme_grey": "灰常美丽", + "theme_happy_new_year": "新年快乐", "theme_mid_autumn": "月里嫦娥", "theme_ming": "青出于黑", "theme_naruto": "木叶之村", @@ -254,21 +304,24 @@ "theme_pink": "粉装玉琢", "theme_purple": "重斤球紫", "theme_red": "热情似火", - "theme_yellow": "信口雌黄", "timeout_exit_btn_cancel": "取消定时", "timeout_exit_btn_update": "更新定时", "timeout_exit_btn_wait_cancel": "取消退出", "timeout_exit_btn_wait_tip": "计时已结束,正在等待退出...", + "timeout_exit_input_tip": "输入倒计时分钟数", "timeout_exit_label_isPlayed": "等待歌曲播放完毕再停止播放", "timeout_exit_min": "分钟", "timeout_exit_tip_cancel": "已取消定时停止播放", "timeout_exit_tip_max": "最多只能设置{{num}}分钟哦", "timeout_exit_tip_off": "设置定时停止播放", "timeout_exit_tip_on": "{{time}} 后停止播放", + "toggle_source_failed": "换源失败,请尝试手动在其他源搜索该歌曲播放", + "toggle_source_try": "尝试切换到其他源...", "version_btn_close": "关闭", "version_btn_downloading": "正在努力下载中...{{total}}/{{current}} ({{progress}}%)", "version_btn_failed": "重试", "version_btn_ignore": "忽略", + "version_btn_ignore_cancel": "取消忽略", "version_btn_min": "后台下载", "version_btn_new": "更新", "version_btn_unknown": "项目首页", diff --git a/src/navigation/components/ModalContent.tsx b/src/navigation/components/ModalContent.tsx new file mode 100644 index 000000000..da30617a7 --- /dev/null +++ b/src/navigation/components/ModalContent.tsx @@ -0,0 +1,56 @@ +import React from 'react' +import { View } from 'react-native' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +// import { useDimensions } from '@/utils/hooks' +const HEADER_HEIGHT = 20 + +interface Props { + children: React.ReactNode +} + + +export default ({ children }: Props) => { + const theme = useTheme() + + return ( + <View style={{ ...styles.centeredView, backgroundColor: 'rgba(50,50,50,.3)' }}> + <View style={{ ...styles.modalView, backgroundColor: theme['c-content-background'] }}> + <View style={{ ...styles.header, backgroundColor: theme['c-primary-light-100-alpha-100'] }}></View> + {children} + </View> + </View> + ) +} + + +const styles = createStyle({ + centeredView: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + modalView: { + maxWidth: '90%', + minWidth: '60%', + maxHeight: '78%', + // backgroundColor: 'white', + borderRadius: 4, + // shadowColor: '#000', + // shadowOffset: { + // width: 0, + // height: 2, + // }, + // shadowOpacity: 0.25, + // shadowRadius: 4, + elevation: 3, + }, + header: { + flexGrow: 0, + flexShrink: 0, + flexDirection: 'row', + borderTopLeftRadius: 4, + borderTopRightRadius: 4, + height: HEADER_HEIGHT, + }, +}) diff --git a/src/navigation/components/PactModal.js b/src/navigation/components/PactModal.js deleted file mode 100644 index beeab4a14..000000000 --- a/src/navigation/components/PactModal.js +++ /dev/null @@ -1,209 +0,0 @@ -import React, { useMemo, useState, useEffect } from 'react' -import { StyleSheet, View, Text, ScrollView, Alert } from 'react-native' -import { Navigation } from 'react-native-navigation' - -import Button from '@/components/common/Button' -import { useGetter, useDispatch } from '@/store' -import { openUrl } from '@/utils/tools' -import { exitApp } from '@/utils/common' - -const VersionModal = ({ componentId }) => { - const theme = useGetter('common', 'theme') - const isAgreePact = useGetter('common', 'isAgreePact') - const setAgreePact = useDispatch('common', 'setAgreePact') - const checkVersion = useDispatch('common', 'checkVersion') - const [time, setTime] = useState(20) - - const handleRejct = () => { - exitApp() - // Navigation.dismissOverlay(componentId) - } - - const handleConfirm = () => { - let _isAgreePact = isAgreePact - if (!isAgreePact) setAgreePact(true) - Navigation.dismissOverlay(componentId) - setTimeout(() => { - Alert.alert( - '', - Buffer.from('e69cace8bdafe4bbb6e5ae8ce585a8e5858de8b4b9e4b894e5bc80e6ba90efbc8ce5a682e69e9ce4bda0e698afe88ab1e992b1e8b4ade4b9b0e79a84efbc8ce8afb7e79bb4e68ea5e7bb99e5b7aee8af84efbc810a0a5468697320736f667477617265206973206672656520616e64206f70656e20736f757263652e', 'hex').toString(), - [{ - text: Buffer.from('e5a5bde79a8420284f4b29', 'hex').toString(), - onPress: () => { - if (!_isAgreePact) checkVersion() - }, - }], - ) - }, 2e3) - } - - const openHomePage = () => { - openUrl('https://github.com/lyswhut/lx-music-mobile#readme') - } - const openLicensePage = () => { - openUrl('http://www.apache.org/licenses/LICENSE-2.0') - } - - const textStyle = StyleSheet.compose(styles.text, { - color: theme.normal, - marginBottom: 10, - }) - const textLinkStyle = StyleSheet.compose(styles.text, { - textDecorationLine: 'underline', - color: theme.secondary, - fontSize: 15, - }) - - const confirmBtn = useMemo(() => { - if (isAgreePact) return { disabled: false, text: '关闭' } - return time ? { disabled: true, text: `同意(${time})` } : { disabled: false, text: '同意' } - }, [isAgreePact, time]) - - useEffect(() => { - if (isAgreePact) return - const timeoutTools = { - timeout: null, - start() { - this.timeout = setTimeout(() => { - setTime(time => { - time-- - if (time > 0) this.start() - return time - }) - }, 1000) - }, - clear() { - clearTimeout(this.timeout) - }, - } - timeoutTools.start() - return () => timeoutTools.clear() - }, []) - - return ( - <View style={{ ...styles.centeredView }}> - <View style={{ ...styles.modalView, backgroundColor: theme.primary }}> - <View style={{ ...styles.header, backgroundColor: theme.secondary }}></View> - <View style={styles.main}> - <Text style={{ ...styles.title, color: theme.normal }}>许可协议</Text> - <ScrollView style={styles.content} keyboardShouldPersistTaps={'always'}> - <Text selectable style={textStyle} >本项目(软件)基于 <Text onPress={openLicensePage} style={textLinkStyle}>Apache License 2.0</Text> 许可证发行,在使用本软件前,你(使用者)需签署本协议才可继续使用,以下协议是对于 Apache License 2.0 的补充,如有冲突,以以下协议为准。</Text> - <Text selectable style={textStyle} >词语约定:本协议中的“本软件”指洛雪音乐移动版项目;“使用者”指签署本协议的使用者;“官方音乐平台”指对本软件内置的包括酷我、酷狗、咪咕等音乐源的官方平台统称;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。</Text> - <Text selectable style={textStyle} ><Text style={styles.bold}>1.</Text> 本软件的数据来源原理是从各官方音乐平台的公开服务器中拉取数据,经过对数据简单地筛选与合并后进行展示,因此本软件不对数据的准确性负责。</Text> - <Text selectable style={textStyle} ><Text style={styles.bold}>2.</Text> 使用本软件的过程中可能会产生版权数据,对于这些版权数据,本软件不拥有它们的所有权,为了避免造成侵权,使用者务必在 <Text style={styles.bold}>24小时内</Text> 清除使用本软件的过程中所产生的版权数据。</Text> - <Text selectable style={textStyle} ><Text style={styles.bold}>3.</Text> 本软件内的官方音乐平台别名为本软件内对官方音乐平台的一个称呼,不包含恶意,如果官方音乐平台觉得不妥,可联系本软件更改或移除。</Text> - <Text selectable style={textStyle} ><Text style={styles.bold}>4.</Text> 本软件内使用的部分包括但不限于字体、图片等资源来源于互联网,如果出现侵权可联系本软件移除。</Text> - <Text selectable style={textStyle} ><Text style={styles.bold}>5.</Text> 由于使用本软件产生的包括由于本协议或由于使用或无法使用本软件而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。</Text> - <Text selectable style={textStyle} ><Text style={styles.bold}>6.</Text> 本项目完全免费,且开源发布于 <Text onPress={openHomePage} style={textLinkStyle}>GitHub</Text> 面向全世界人用作对技术的学习交流,本软件不对项目内的技术可能存在违反当地法律法规的行为作保证,<Text style={styles.bold}>禁止在违反当地法律法规的情况下使用本软件</Text>,对于使用者在明知或不知当地法律法规不允许的情况下使用本软件所造成的任何违法违规行为由使用者承担,本软件不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。</Text> - <Text selectable style={textStyle} ><Text style={styles.bold}>*</Text> 若协议更新,恕不另行通知,可到开源地址查看。</Text> - <Text selectable style={textStyle} ><Text style={styles.bold}>*</Text> 本软件的初衷是帮助官方音乐平台简化数据后代为展示,帮助使用者根据歌曲名、艺术家等关键字快速地定位所需内容所在的音乐平台。</Text> - <Text selectable style={textStyle} ><Text style={styles.bold}>*</Text> 音乐平台不易,建议到对应音乐平台支持正版资源。</Text> - { - isAgreePact - ? null - : ( - <Text selectable style={{ ...styles.text, ...styles.bold, color: theme.normal }} >若你(使用者)接受以上协议,请点击下面的“接受”按钮签署本协议,若不接受,请点击“不接受”后退出软件并清除本软件的所有数据。</Text> - ) - } - </ScrollView> - </View> - <View style={styles.btns}> - { - isAgreePact - ? null - : ( - <Button style={{ ...styles.btn, backgroundColor: theme.secondary45 }} onPress={handleRejct}> - <Text style={{ fontSize: 14, color: theme.secondary_5 }}>不同意</Text> - </Button> - ) - } - <Button disabled={confirmBtn.disabled} style={{ ...styles.btn, backgroundColor: theme.secondary45 }} onPress={handleConfirm}> - <Text style={{ fontSize: 14, color: theme.secondary_5 }}>{confirmBtn.text}</Text> - </Button> - </View> - </View> - </View> - ) -} - -const styles = StyleSheet.create({ - centeredView: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: 'rgba(50,50,50,.3)', - }, - modalView: { - maxWidth: '90%', - minWidth: '75%', - // minHeight: '36%', - maxHeight: '78%', - backgroundColor: 'white', - borderRadius: 4, - // shadowColor: '#000', - // shadowOffset: { - // width: 0, - // height: 2, - // }, - // shadowOpacity: 0.25, - // shadowRadius: 4, - elevation: 3, - }, - header: { - flexGrow: 0, - flexShrink: 0, - flexDirection: 'row', - borderTopLeftRadius: 4, - borderTopRightRadius: 4, - height: 20, - }, - - main: { - // flexGrow: 0, - flexShrink: 1, - marginTop: 15, - marginBottom: 20, - }, - content: { - flexGrow: 0, - marginLeft: 5, - marginRight: 5, - paddingLeft: 10, - paddingRight: 10, - }, - title: { - fontSize: 18, - textAlign: 'center', - marginBottom: 15, - }, - part: { - marginBottom: 10, - }, - text: { - fontSize: 14, - textAlignVertical: 'bottom', - }, - bold: { - fontWeight: 'bold', - }, - btns: { - flexDirection: 'row', - justifyContent: 'center', - paddingBottom: 15, - paddingLeft: 15, - // paddingRight: 15, - }, - btn: { - flex: 1, - paddingTop: 10, - paddingBottom: 10, - paddingLeft: 10, - paddingRight: 10, - alignItems: 'center', - borderRadius: 4, - marginRight: 15, - }, -}) - -export default VersionModal - diff --git a/src/navigation/components/PactModal.tsx b/src/navigation/components/PactModal.tsx new file mode 100644 index 000000000..a915d7b9c --- /dev/null +++ b/src/navigation/components/PactModal.tsx @@ -0,0 +1,208 @@ +import React, { useMemo, useState, useEffect } from 'react' +import { View, ScrollView, Alert } from 'react-native' +import { Navigation } from 'react-native-navigation' + +import Button from '@/components/common/Button' +import { createStyle, openUrl } from '@/utils/tools' +import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' +import Text from '@/components/common/Text' +import ModalContent from './ModalContent' +import { exitApp } from '@/utils/nativeModules/utils' +import { updateSetting } from '@/core/common' +import { checkUpdate } from '@/core/version' + +const Content = () => { + const theme = useTheme() + + const openHomePage = () => { + void openUrl('https://github.com/lyswhut/lx-music-mobile#readme') + } + const openLicensePage = () => { + void openUrl('http://www.apache.org/licenses/LICENSE-2.0') + } + + const textLinkStyle = { + ...styles.text, + textDecorationLine: 'underline', + color: theme['c-primary-font'], + // fontSize: 15, + } as const + + return ( + <View style={styles.main}> + <Text style={styles.title} size={18} >许可协议</Text> + <ScrollView style={styles.content} keyboardShouldPersistTaps={'always'}> + <Text selectable style={styles.text} >本项目(软件)基于 <Text onPress={openLicensePage} style={textLinkStyle}>Apache License 2.0</Text> 许可证发行,在使用本软件前,你(使用者)需签署本协议才可继续使用,以下协议是对于 Apache License 2.0 的补充,如有冲突,以以下协议为准。</Text> + <Text selectable style={styles.text} >词语约定:本协议中的“本软件”指洛雪音乐移动版项目;“使用者”指签署本协议的使用者;“官方音乐平台”指对本软件内置的包括酷我、酷狗、咪咕等音乐源的官方平台统称;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。</Text> + <Text selectable style={styles.text} ><Text style={styles.bold}>1.</Text> 本软件的数据来源原理是从各官方音乐平台的公开服务器中拉取数据,经过对数据简单地筛选与合并后进行展示,因此本软件不对数据的准确性负责。</Text> + <Text selectable style={styles.text} ><Text style={styles.bold}>2.</Text> 使用本软件的过程中可能会产生版权数据,对于这些版权数据,本软件不拥有它们的所有权,为了避免造成侵权,使用者务必在 <Text style={styles.bold}>24小时内</Text> 清除使用本软件的过程中所产生的版权数据。</Text> + <Text selectable style={styles.text} ><Text style={styles.bold}>3.</Text> 本软件内的官方音乐平台别名为本软件内对官方音乐平台的一个称呼,不包含恶意,如果官方音乐平台觉得不妥,可联系本软件更改或移除。</Text> + <Text selectable style={styles.text} ><Text style={styles.bold}>4.</Text> 本软件内使用的部分包括但不限于字体、图片等资源来源于互联网,如果出现侵权可联系本软件移除。</Text> + <Text selectable style={styles.text} ><Text style={styles.bold}>5.</Text> 由于使用本软件产生的包括由于本协议或由于使用或无法使用本软件而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。</Text> + <Text selectable style={styles.text} ><Text style={styles.bold}>6.</Text> 本项目完全免费,且开源发布于 <Text onPress={openHomePage} style={textLinkStyle}>GitHub</Text> 面向全世界人用作对技术的学习交流,本软件不对项目内的技术可能存在违反当地法律法规的行为作保证,<Text style={styles.bold}>禁止在违反当地法律法规的情况下使用本软件</Text>,对于使用者在明知或不知当地法律法规不允许的情况下使用本软件所造成的任何违法违规行为由使用者承担,本软件不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。</Text> + <Text selectable style={styles.text} ><Text style={styles.bold}>*</Text> 若协议更新,恕不另行通知,可到开源地址查看。</Text> + <Text selectable style={styles.text} ><Text style={styles.bold}>*</Text> 本软件的初衷是帮助官方音乐平台简化数据后代为展示,帮助使用者根据歌曲名、艺术家等关键字快速地定位所需内容所在的音乐平台。</Text> + <Text selectable style={styles.text} ><Text style={styles.bold}>*</Text> 音乐平台不易,建议到对应音乐平台支持正版资源。</Text> + </ScrollView> + </View> + ) +} + +const Footer = ({ componentId }: { componentId: string }) => { + const theme = useTheme() + const isAgreePact = useSettingValue('common.isAgreePact') + // const checkUpdate = useDispatch('common', 'checkUpdate') + const [time, setTime] = useState(20) + + const handleRejct = () => { + exitApp() + // Navigation.dismissOverlay(componentId) + } + + const handleConfirm = () => { + let _isAgreePact = isAgreePact + if (!isAgreePact) updateSetting({ 'common.isAgreePact': true }) + void Navigation.dismissOverlay(componentId) + if (!_isAgreePact) { + setTimeout(() => { + Alert.alert( + '', + Buffer.from('e69cace8bdafe4bbb6e5ae8ce585a8e5858de8b4b9e4b894e5bc80e6ba90efbc8ce5a682e69e9ce4bda0e698afe88ab1e992b1e8b4ade4b9b0e79a84efbc8ce8afb7e79bb4e68ea5e7bb99e5b7aee8af84efbc810a0a5468697320736f667477617265206973206672656520616e64206f70656e20736f757263652e', 'hex').toString(), + [{ + text: Buffer.from('e5a5bde79a8420284f4b29', 'hex').toString(), + onPress: () => { + void checkUpdate() + }, + }], + ) + }, 2e3) + } + } + + + const confirmBtn = useMemo(() => { + if (isAgreePact) return { disabled: false, text: '关闭' } + return time ? { disabled: true, text: `同意(${time})` } : { disabled: false, text: '同意' } + }, [isAgreePact, time]) + + useEffect(() => { + if (isAgreePact) return + const timeoutTools = { + timeout: null as NodeJS.Timeout | null, + start() { + this.timeout = setTimeout(() => { + setTime(time => { + time-- + if (time > 0) this.start() + return time + }) + }, 1000) + }, + clear() { + if (!this.timeout) return + clearTimeout(this.timeout) + }, + } + timeoutTools.start() + return () => { + timeoutTools.clear() + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + return ( + <> + { + isAgreePact + ? null + : ( + <Text selectable style={styles.tip} size={13}>若你(使用者)接受以上协议,请点击下面的“接受”按钮签署本协议,若不接受,请点击“不接受”后退出软件并清除本软件的所有数据。</Text> + ) + } + <View style={styles.btns}> + { + isAgreePact + ? null + : ( + <Button style={{ ...styles.btn, backgroundColor: theme['c-button-background'] }} onPress={handleRejct}> + <Text color={theme['c-button-font']}>不同意</Text> + </Button> + ) + } + <Button disabled={confirmBtn.disabled} style={{ ...styles.btn, backgroundColor: theme['c-button-background'] }} onPress={handleConfirm}> + <Text color={theme['c-button-font']}>{confirmBtn.text}</Text> + </Button> + </View> + </> + ) +} + +const PactModal = ({ componentId }: { componentId: string }) => { + return ( + <ModalContent> + <Content /> + <Footer componentId={componentId} /> + </ModalContent> + ) +} + +const styles = createStyle({ + main: { + // flexGrow: 0, + flexShrink: 1, + marginTop: 15, + marginBottom: 10, + }, + content: { + flexGrow: 0, + marginLeft: 5, + marginRight: 5, + paddingLeft: 10, + paddingRight: 10, + }, + title: { + textAlign: 'center', + marginBottom: 15, + }, + part: { + marginBottom: 10, + }, + text: { + fontSize: 14, + textAlignVertical: 'bottom', + marginBottom: 5, + }, + bold: { + fontSize: 14, + textAlignVertical: 'bottom', + fontWeight: 'bold', + }, + tip: { + textAlignVertical: 'bottom', + fontWeight: 'bold', + paddingLeft: 15, + paddingRight: 15, + paddingBottom: 15, + }, + btns: { + flexDirection: 'row', + justifyContent: 'center', + paddingBottom: 15, + paddingLeft: 15, + // paddingRight: 15, + }, + btn: { + flex: 1, + paddingTop: 10, + paddingBottom: 10, + paddingLeft: 10, + paddingRight: 10, + alignItems: 'center', + borderRadius: 4, + marginRight: 15, + }, +}) + +export default PactModal + diff --git a/src/navigation/components/VersionModal.js b/src/navigation/components/VersionModal.js deleted file mode 100644 index 02d34a1fa..000000000 --- a/src/navigation/components/VersionModal.js +++ /dev/null @@ -1,312 +0,0 @@ -import React, { useMemo, useState, useEffect } from 'react' -import { StyleSheet, View, Text, ScrollView } from 'react-native' -import { Navigation } from 'react-native-navigation' - -import { compareVer, sizeFormate } from '@/utils' - -import Button from '@/components/common/Button' -import { useTranslation } from '@/plugins/i18n' -import { useGetter, useDispatch } from '@/store' -import { VERSION_STATUS } from '@/config/constant' -import { downloadNewVersion, updateApp } from '@/utils/version' -import { openUrl } from '@/utils/tools' - -const VersionItem = ({ version, desc }) => { - const theme = useGetter('common', 'theme') - return ( - <View style={{ marginBottom: 10 }}> - <Text style={{ ...styles.label, color: theme.normal, marginBottom: 2 }}>v{version}</Text> - <Text selectable style={{ ...styles.desc, color: theme.normal }}>{desc}</Text> - </View> - ) -} - -const currentVer = process.versions.app -const VersionModal = ({ componentId }) => { - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - const versionInfo = useGetter('common', 'versionInfo') - const setVersionInfo = useDispatch('common', 'setVersionInfo') - const setIgnoreVersion = useDispatch('common', 'setIgnoreVersion') - const [ignoreBtn, setIgnoreBtn] = useState({ text: t('version_btn_ignore'), show: true, disabled: false }) - const [closeBtnText, setCloseBtnText] = useState(t('version_btn_close')) - const [confirmBtn, setConfirmBtn] = useState({ text: t('version_btn_confirm'), show: true, disabled: false }) - const [title, setTitle] = useState('') - const [tip, setTip] = useState('') - - const history = useMemo(() => { - if (!versionInfo.history) return [] - let arr = [] - for (const ver of versionInfo.history) { - if (compareVer(currentVer, ver.version) < 0) arr.push(ver) - } - return arr - }, [versionInfo]) - - const handleCancel = () => { - setVersionInfo({ showModal: false }) - Navigation.dismissOverlay(componentId) - } - - const handleIgnore = () => { - setIgnoreVersion(versionInfo.version) - handleCancel() - } - - const handleDownload = () => { - setVersionInfo({ - status: VERSION_STATUS.downloading, - downloadProgress: { - total: 0, - current: 0, - }, - }) - downloadNewVersion(versionInfo.version, (total, current) => { - // console.log(total, current) - setVersionInfo({ - status: VERSION_STATUS.downloading, - downloadProgress: { - total, - current, - }, - }) - }).then(() => { - setVersionInfo({ - status: VERSION_STATUS.downloaded, - }) - }).catch(err => { - console.log(err) - setVersionInfo({ - status: VERSION_STATUS.failed, - }) - }) - } - const handleConfirm = () => { - switch (versionInfo.status) { - case VERSION_STATUS.available: - handleDownload() - break - case VERSION_STATUS.downloaded: - updateApp().catch(() => { - setVersionInfo({ - status: VERSION_STATUS.failed, - }) - }) - break - case VERSION_STATUS.failed: - handleDownload() - break - - case VERSION_STATUS.unknown: - default: - openUrl('https://github.com/lyswhut/lx-music-mobile#readme') - break - } - // setVersionInfo({ showModal: false }) - // Navigation.dismissOverlay(componentId) - } - - useEffect(() => { - switch (versionInfo.status) { - case VERSION_STATUS.available: - setTitle(t('version_title_new')) - setTip('') - setIgnoreBtn({ text: t('version_btn_ignore'), show: true, disabled: false }) - setConfirmBtn({ text: t('version_btn_new'), show: true, disabled: false }) - // setTip(t('version_btn_new')) - setCloseBtnText(t('version_btn_close')) - break - case VERSION_STATUS.downloading: - setTitle(t('version_title_new')) - setTip(t('version_btn_downloading', { - total: sizeFormate(versionInfo.downloadProgress.total), - current: sizeFormate(versionInfo.downloadProgress.current), - progress: versionInfo.downloadProgress.total ? (versionInfo.downloadProgress.current / versionInfo.downloadProgress.total * 100).toFixed(2) : '0', - })) - if (ignoreBtn.show) setIgnoreBtn({ text: t('version_btn_ignore'), show: false, disabled: true }) - if (!confirmBtn.disabled) setConfirmBtn({ text: t('version_btn_update'), show: true, disabled: true }) - setCloseBtnText(t('version_btn_min')) - break - case VERSION_STATUS.downloaded: - setTitle(t('version_title_update')) - setTip('') - if (ignoreBtn.show) setIgnoreBtn({ text: t('version_btn_ignore'), show: false, disabled: true }) - setConfirmBtn({ text: t('version_btn_update'), show: true, disabled: false }) - setCloseBtnText(t('version_btn_close')) - break - case VERSION_STATUS.checking: - setTitle(t('version_title_checking')) - setTip(t('')) - setIgnoreBtn({ text: t('version_btn_ignore'), show: false, disabled: true }) - setConfirmBtn({ text: t('version_btn_new'), show: false, disabled: true }) - setCloseBtnText(t('version_btn_close')) - break - case VERSION_STATUS.failed: - setTitle(t('version_title_failed')) - setTip(t('version_tip_failed')) - setIgnoreBtn({ text: t('version_btn_ignore'), show: true, disabled: false }) - setConfirmBtn({ text: t('version_btn_failed'), show: true, disabled: false }) - setCloseBtnText(t('version_btn_close')) - break - case VERSION_STATUS.unknown: - setTitle(t('version_title_unknown')) - setTip(t('version_tip_unknown')) - setIgnoreBtn({ text: t('version_btn_ignore'), show: false, disabled: true }) - setConfirmBtn({ text: t('version_btn_unknown'), show: true, disabled: false }) - setCloseBtnText(t('version_btn_close')) - break - case VERSION_STATUS.latest: - default: - setTitle(t('version_title_latest')) - setTip('') - setIgnoreBtn({ text: t('version_btn_ignore'), show: false, disabled: true }) - setConfirmBtn({ text: t('version_btn_new'), show: false, disabled: true }) - setCloseBtnText(t('version_btn_close')) - break - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [t, versionInfo]) - - return ( - <View style={{ ...styles.centeredView }}> - <View style={{ ...styles.modalView, backgroundColor: theme.primary }}> - <View style={{ ...styles.header, backgroundColor: theme.secondary }}></View> - <View style={styles.main}> - <Text style={{ ...styles.title, color: theme.normal }}>{title}</Text> - <ScrollView style={styles.content} keyboardShouldPersistTaps={'always'}> - <Text style={{ ...styles.label, color: theme.normal }}>{t('version_label_latest_ver')}{versionInfo.version}</Text> - <Text style={{ ...styles.label, color: theme.normal }}>{t('version_label_current_ver')}{currentVer}</Text> - { - versionInfo.desc - ? ( - <View> - <Text style={{ ...styles.label, color: theme.normal }}>{t('version_label_change_log')}</Text> - <View style={{ paddingLeft: 10, marginTop: 5 }}> - <Text selectable style={{ ...styles.desc, color: theme.normal }}>{versionInfo.desc}</Text> - </View> - </View> - ) - : null - } - { - history.length - ? ( - <View style={styles.history}> - <Text style={{ ...styles.label, color: theme.normal }}>{t('version_label_history')}</Text> - <View style={{ paddingLeft: 10, marginTop: 5 }}> - {history.map((item, index) => <VersionItem key={index} version={item.version} desc={item.desc} />)} - </View> - </View> - ) - : null - } - </ScrollView> - { tip.length ? <Text style={{ marginTop: 10, fontSize: 14, color: theme.secondary }}>{tip}</Text> : null } - </View> - <View style={styles.btns}> - { - ignoreBtn.show - ? ( - <Button disabled={ignoreBtn.disabled} style={{ ...styles.btn, backgroundColor: theme.secondary45 }} onPress={handleIgnore}> - <Text style={{ fontSize: 14, color: theme.secondary_5 }}>{ignoreBtn.text}</Text> - </Button> - ) - : null - } - <Button style={{ ...styles.btn, backgroundColor: theme.secondary45 }} onPress={handleCancel}> - <Text style={{ fontSize: 14, color: theme.secondary_5 }}>{closeBtnText}</Text> - </Button> - { - confirmBtn.show - ? ( - <Button disabled={confirmBtn.disabled} style={{ ...styles.btn, backgroundColor: theme.secondary45 }} onPress={handleConfirm}> - <Text style={{ fontSize: 14, color: theme.secondary_5 }}>{confirmBtn.text}</Text> - </Button> - ) - : null - } - </View> - </View> - </View> - ) -} - -const styles = StyleSheet.create({ - centeredView: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: 'rgba(50,50,50,.3)', - }, - modalView: { - maxWidth: '90%', - minWidth: '75%', - // minHeight: '36%', - maxHeight: '78%', - backgroundColor: 'white', - borderRadius: 4, - // shadowColor: '#000', - // shadowOffset: { - // width: 0, - // height: 2, - // }, - // shadowOpacity: 0.25, - // shadowRadius: 4, - elevation: 3, - }, - header: { - flexGrow: 0, - flexShrink: 0, - flexDirection: 'row', - borderTopLeftRadius: 4, - borderTopRightRadius: 4, - height: 20, - }, - - main: { - // flexGrow: 0, - flexShrink: 1, - marginTop: 15, - marginLeft: 15, - marginRight: 15, - marginBottom: 20, - }, - content: { - flexGrow: 0, - }, - title: { - fontSize: 18, - textAlign: 'center', - marginBottom: 15, - }, - history: { - marginTop: 15, - }, - label: { - fontSize: 14, - }, - desc: { - fontSize: 13, - lineHeight: 18, - }, - btns: { - flexDirection: 'row', - justifyContent: 'center', - paddingBottom: 15, - paddingLeft: 15, - // paddingRight: 15, - }, - btn: { - flex: 1, - paddingTop: 10, - paddingBottom: 10, - paddingLeft: 10, - paddingRight: 10, - alignItems: 'center', - borderRadius: 4, - marginRight: 15, - }, -}) - -export default VersionModal - diff --git a/src/navigation/components/VersionModal.tsx b/src/navigation/components/VersionModal.tsx new file mode 100644 index 000000000..27068547f --- /dev/null +++ b/src/navigation/components/VersionModal.tsx @@ -0,0 +1,263 @@ +import React, { useMemo, useState, useEffect, memo } from 'react' +import { View, ScrollView } from 'react-native' + +import { compareVer, sizeFormate } from '@/utils' + +import Button from '@/components/common/Button' +import { updateApp } from '@/utils/version' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { type VersionInfo } from '@/store/version/state' +import Text from '@/components/common/Text' +import { useI18n } from '@/lang' +import { useVersionDownloadProgressUpdated, useVersionInfo, useVersionInfoIgnoreVersionUpdated } from '@/store/version/hook' +import ModalContent from './ModalContent' +import { checkUpdate, downloadUpdate, hideModal, setIgnoreVersion } from '@/core/version' + +const VersionItem = ({ version, desc }: VersionInfo) => { + return ( + <View style={styles.versionItem}> + <Text style={styles.label}>v{version}</Text> + <Text selectable style={styles.desc}>{desc}</Text> + </View> + ) +} + +const Content = memo(({ title, newVersionInfo }: { + title: string + newVersionInfo: VersionInfo | null +}) => { + const t = useI18n() + + const history = useMemo(() => { + if (!newVersionInfo?.history) return [] + let arr = [] + for (const ver of newVersionInfo?.history) { + if (compareVer(currentVer, ver.version) < 0) arr.push(ver) + } + return arr + }, [newVersionInfo]) + + return ( + <View style={styles.main}> + <Text style={styles.title}>{title}</Text> + <ScrollView style={styles.content} keyboardShouldPersistTaps={'always'}> + <Text style={styles.label}>{t('version_label_latest_ver')}{newVersionInfo?.version}</Text> + <Text style={styles.label}>{t('version_label_current_ver')}{currentVer}</Text> + { + newVersionInfo?.desc + ? ( + <View> + <Text style={styles.label}>{t('version_label_change_log')}</Text> + <View style={{ paddingLeft: 10, marginTop: 5 }}> + <Text selectable style={styles.desc}>{newVersionInfo.desc}</Text> + </View> + </View> + ) + : null + } + { + history.length + ? ( + <View style={styles.history}> + <Text style={styles.label}>{t('version_label_history')}</Text> + <View style={{ paddingLeft: 10, marginTop: 5 }}> + {history.map((item, index) => <VersionItem key={index} version={item.version} desc={item.desc} />)} + </View> + </View> + ) + : null + } + </ScrollView> + </View> + ) +}) + +const currentVer = process.versions.app +const VersionModal = ({ componentId }: { componentId: string }) => { + const theme = useTheme() + const t = useI18n() + const versionInfo = useVersionInfo() + const progress = useVersionDownloadProgressUpdated() + const ignoreVersion = useVersionInfoIgnoreVersionUpdated() + const [ignoreBtn, setIgnoreBtn] = useState({ text: t('version_btn_ignore'), show: true, disabled: false }) + const [closeBtnText, setCloseBtnText] = useState(t('version_btn_close')) + const [confirmBtn, setConfirmBtn] = useState({ text: '', show: true, disabled: false }) + const [title, setTitle] = useState('') + const [tip, setTip] = useState('') + + + useEffect(() => { + let ignoreBtnConfig = { ...ignoreBtn } + if (versionInfo.isLatest) { + setTitle(t('version_title_latest')) + setTip('') + ignoreBtnConfig.show = false + setConfirmBtn({ text: t('version_btn_new'), show: false, disabled: true }) + setCloseBtnText(t('version_btn_close')) + } else if (versionInfo.isUnknown) { + setTitle(t('version_title_unknown')) + setTip(t('version_tip_unknown')) + ignoreBtnConfig.show = false + setConfirmBtn({ text: t('version_btn_failed'), show: true, disabled: false }) + setCloseBtnText(t('version_btn_close')) + } else { + switch (versionInfo.status) { + case 'downloading': + setTitle(t('version_title_new')) + setTip(t('version_btn_downloading', { + total: sizeFormate(progress.total), + current: sizeFormate(progress.current), + progress: progress.total ? (progress.current / progress.total * 100).toFixed(2) : '0', + })) + if (ignoreBtnConfig.show) ignoreBtnConfig.show = false + if (!confirmBtn.disabled) setConfirmBtn({ text: t('version_btn_update'), show: true, disabled: true }) + setCloseBtnText(t('version_btn_min')) + break + case 'downloaded': + setTitle(t('version_title_update')) + setTip('') + if (ignoreBtnConfig.show) ignoreBtnConfig.show = false + setConfirmBtn({ text: t('version_btn_update'), show: true, disabled: false }) + setCloseBtnText(t('version_btn_close')) + break + case 'checking': + setTitle(t('version_title_checking')) + setTip('') + ignoreBtnConfig.show = false + setConfirmBtn({ text: t('version_btn_new'), show: false, disabled: true }) + setCloseBtnText(t('version_btn_close')) + break + case 'error': + setTitle(t('version_title_failed')) + setTip(t('version_tip_failed')) + ignoreBtnConfig.show = true + ignoreBtnConfig.disabled = false + setConfirmBtn({ text: t('version_btn_failed'), show: true, disabled: false }) + setCloseBtnText(t('version_btn_close')) + break + // case 'idle': + // break + default: + setTitle(t('version_title_new')) + setTip('') + ignoreBtnConfig.show = true + ignoreBtnConfig.disabled = false + setConfirmBtn({ text: t('version_btn_new'), show: true, disabled: false }) + // setTip(t('version_btn_new')) + setCloseBtnText(t('version_btn_close')) + break + } + } + ignoreBtnConfig.text = t(ignoreVersion == versionInfo.newVersion?.version ? 'version_btn_ignore_cancel' : 'version_btn_ignore') + setIgnoreBtn(ignoreBtnConfig) + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [t, versionInfo, ignoreVersion, progress]) + + const handleCancel = () => { + hideModal(componentId) + } + const handleIgnore = () => { + setIgnoreVersion(ignoreVersion != versionInfo.newVersion!.version ? versionInfo.newVersion!.version : null) + // handleCancel() + } + + const handleConfirm = () => { + if (versionInfo.isLatest || versionInfo.isUnknown) { + void checkUpdate() + } else if (versionInfo.status == 'downloaded') { + void updateApp() + } else if (versionInfo.status == 'idle' || versionInfo.status == 'error') { + downloadUpdate() + } + } + + return ( + <ModalContent> + <Content title={title} newVersionInfo={versionInfo.newVersion} /> + { tip.length ? <Text style={styles.tip} color={theme['c-primary-font']}>{tip}</Text> : null } + <View style={styles.btns}> + { + ignoreBtn.show + ? ( + <Button disabled={ignoreBtn.disabled} style={{ ...styles.btn, backgroundColor: theme['c-button-background'] }} onPress={handleIgnore}> + <Text color={theme['c-button-font']}>{ignoreBtn.text}</Text> + </Button> + ) + : null + } + <Button style={{ ...styles.btn, backgroundColor: theme['c-button-background'] }} onPress={handleCancel}> + <Text color={theme['c-button-font']}>{closeBtnText}</Text> + </Button> + { + confirmBtn.show + ? ( + <Button disabled={confirmBtn.disabled} style={{ ...styles.btn, backgroundColor: theme['c-button-background'] }} onPress={handleConfirm}> + <Text color={theme['c-button-font']}>{confirmBtn.text}</Text> + </Button> + ) + : null + } + </View> + </ModalContent> + ) +} + +const styles = createStyle({ + main: { + // flexGrow: 0, + flexShrink: 1, + marginTop: 15, + marginLeft: 15, + marginRight: 15, + marginBottom: 20, + }, + content: { + flexGrow: 0, + }, + title: { + fontSize: 18, + textAlign: 'center', + marginBottom: 15, + }, + history: { + marginTop: 15, + }, + versionItem: { + marginBottom: 10, + }, + label: { + fontSize: 14, + marginBottom: 2, + }, + desc: { + fontSize: 13, + lineHeight: 18, + }, + tip: { + paddingLeft: 15, + paddingRight: 15, + paddingBottom: 10, + }, + btns: { + flexDirection: 'row', + justifyContent: 'center', + paddingBottom: 15, + paddingLeft: 15, + // paddingRight: 15, + }, + btn: { + flex: 1, + paddingTop: 10, + paddingBottom: 10, + paddingLeft: 10, + paddingRight: 10, + alignItems: 'center', + borderRadius: 4, + marginRight: 15, + }, +}) + +export default VersionModal + diff --git a/src/navigation/hooks.js b/src/navigation/hooks.ts similarity index 78% rename from src/navigation/hooks.js rename to src/navigation/hooks.ts index 15a92fb0e..80a22df3d 100644 --- a/src/navigation/hooks.js +++ b/src/navigation/hooks.ts @@ -1,10 +1,11 @@ import { useEffect } from 'react' +import { EmitterSubscription } from 'react-native' import { Navigation } from 'react-native-navigation' export const useNavigationCommandComplete = (callback = () => {}) => { useEffect(() => { // Register the listener to all events related to our component - let commandCompletedListener = Navigation.events().registerCommandCompletedListener(({ commandId }) => { + let commandCompletedListener: EmitterSubscription | null = Navigation.events().registerCommandCompletedListener(({ commandId }) => { callback() if (!commandCompletedListener) return commandCompletedListener.remove() @@ -18,7 +19,7 @@ export const useNavigationCommandComplete = (callback = () => {}) => { } }, [callback]) } -export const useNavigationComponentDidAppear = (componentId, callback = () => {}) => { +export const useNavigationComponentDidAppear = (componentId: string, callback = () => {}) => { useEffect(() => { const listener = { componentDidAppear: () => { @@ -34,7 +35,7 @@ export const useNavigationComponentDidAppear = (componentId, callback = () => {} }, [callback, componentId]) } -export const onNavigationComponentDidDisappearEvent = (componentId, callback = () => {}) => { +export const onNavigationComponentDidDisappearEvent = (componentId: string, callback = () => {}) => { const listener = { componentDidDisappear: () => { callback() @@ -44,7 +45,7 @@ export const onNavigationComponentDidDisappearEvent = (componentId, callback = ( return unsubscribe } -export const useNavigationComponentDidDisappear = (componentId, callback = () => {}) => { +export const useNavigationComponentDidDisappear = (componentId: string, callback = () => {}) => { useEffect(() => { const unsubscribe = onNavigationComponentDidDisappearEvent(componentId, callback) return () => { diff --git a/src/navigation/index.js b/src/navigation/index.ts similarity index 59% rename from src/navigation/index.js rename to src/navigation/index.ts index 870554e99..e75d44dbb 100644 --- a/src/navigation/index.js +++ b/src/navigation/index.ts @@ -3,31 +3,29 @@ import * as screenNames from './screenNames' import * as navigations from './navigation' import registerScreens from './registerScreens' -import { getStore } from '@/store' -import { action as commonAction } from '@/store/modules/common' +import { removeComponentId } from '@/core/common' -let unRegisterEvent +let unRegisterEvent: ReturnType<ReturnType<typeof Navigation.events>['registerScreenPoppedListener']> -const init = callback => { +const init = (callback: () => void | Promise<void>) => { // Register all screens on launch registerScreens() - if (unRegisterEvent) unRegisterEvent() + if (unRegisterEvent) unRegisterEvent.remove() Navigation.setDefaultOptions({ - animations: { - setRoot: { - waitForRender: true, - }, - }, + // animations: { + // setRoot: { + // waitForRender: true, + // }, + // }, }) unRegisterEvent = Navigation.events().registerScreenPoppedListener(({ componentId }) => { - const store = getStore() - store.dispatch(commonAction.removeComponentId(componentId)) + removeComponentId(componentId) }) Navigation.events().registerAppLaunchedListener(() => { console.log('Register app launched listener') - callback() + void callback() }) } diff --git a/src/navigation/navigation.js b/src/navigation/navigation.ts similarity index 77% rename from src/navigation/navigation.js rename to src/navigation/navigation.ts index 26b8df573..d8553c084 100644 --- a/src/navigation/navigation.js +++ b/src/navigation/navigation.ts @@ -9,13 +9,14 @@ import { // SETTING_SCREEN, } from './screenNames' -import { getter, getStore } from '@/store' +import themeState from '@/store/theme/state' +import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant' -const store = getStore() -const getTheme = () => getter('common', 'theme')(store.getState()) -const getStatusBarStyle = () => getter('common', 'isDarkTheme')(store.getState()) ? 'light' : 'dark' +// const store = getStore() +// const getTheme = () => getter('common', 'theme')(store.getState()) +const getStatusBarStyle = (isDark: boolean) => isDark ? 'light' : 'dark' -export function pushHomeScreen() { +export async function pushHomeScreen() { /* Navigation.setDefaultOptions({ topBar: { @@ -49,7 +50,7 @@ export function pushHomeScreen() { }) */ - const theme = getTheme() + const theme = themeState.theme return Navigation.setRoot({ root: { stack: { @@ -65,15 +66,15 @@ export function pushHomeScreen() { statusBar: { drawBehind: true, visible: true, - style: getStatusBarStyle(), + style: getStatusBarStyle(theme.isDark), backgroundColor: 'transparent', }, navigationBar: { // visible: false, - backgroundColor: theme.primary, + backgroundColor: theme.isDark ? '#000' : '#fff', }, layout: { - componentBackgroundColor: theme.primary, + // componentBackgroundColor: theme.isDark ? '#000' : '#fff', }, }, }, @@ -82,7 +83,7 @@ export function pushHomeScreen() { }, }) } -export function pushPlayDetailScreen(componentId, id) { +export function pushPlayDetailScreen(componentId: string) { /* Navigation.setDefaultOptions({ topBar: { @@ -115,10 +116,10 @@ export function pushPlayDetailScreen(componentId, id) { }, }) */ - InteractionManager.runAfterInteractions(() => { - const theme = getTheme() + void InteractionManager.runAfterInteractions(() => { + const theme = themeState.theme - Navigation.push(componentId, { + void Navigation.push(componentId, { component: { name: PLAY_DETAIL_SCREEN, options: { @@ -130,28 +131,28 @@ export function pushPlayDetailScreen(componentId, id) { statusBar: { drawBehind: true, visible: true, - style: getStatusBarStyle(), + style: getStatusBarStyle(theme.isDark), backgroundColor: 'transparent', }, navigationBar: { // visible: false, - backgroundColor: theme.primary, + backgroundColor: theme.isDark ? '#000' : '#fff', }, layout: { - componentBackgroundColor: theme.primary, + componentBackgroundColor: theme.isDark ? '#000' : '#fff', }, animations: { push: { sharedElementTransitions: [ { - fromId: `pic${id}`, - toId: `pic${id}Dest`, + fromId: NAV_SHEAR_NATIVE_IDS.playDetail_pic, + toId: NAV_SHEAR_NATIVE_IDS.playDetail_pic, interpolation: { type: 'spring' }, }, ], elementTransitions: [ { - id: 'header', + id: NAV_SHEAR_NATIVE_IDS.playDetail_header, alpha: { from: 0, // We don't declare 'to' value as that is the element's current alpha value, here we're essentially animating from 0 to 1 duration: 300, @@ -162,7 +163,7 @@ export function pushPlayDetailScreen(componentId, id) { }, }, { - id: 'pageIndicator', + id: NAV_SHEAR_NATIVE_IDS.playDetail_pageIndicator, alpha: { from: 0, // We don't declare 'to' value as that is the element's current alpha value, here we're essentially animating from 0 to 1 duration: 300, @@ -173,7 +174,7 @@ export function pushPlayDetailScreen(componentId, id) { }, }, { - id: 'player', + id: NAV_SHEAR_NATIVE_IDS.playDetail_player, alpha: { from: 0, // We don't declare 'to' value as that is the element's current alpha value, here we're essentially animating from 0 to 1 duration: 300, @@ -207,10 +208,11 @@ export function pushPlayDetailScreen(componentId, id) { }) }) } -export function pushSonglistDetailScreen(componentId, id) { - const theme = getTheme() - InteractionManager.runAfterInteractions(() => { - Navigation.push(componentId, { +export function pushSonglistDetailScreen(componentId: string, id: string) { + const theme = themeState.theme + + void InteractionManager.runAfterInteractions(() => { + void Navigation.push(componentId, { component: { name: SONGLIST_DETAIL_SCREEN, options: { @@ -222,28 +224,28 @@ export function pushSonglistDetailScreen(componentId, id) { statusBar: { drawBehind: true, visible: true, - style: getStatusBarStyle(), + style: getStatusBarStyle(theme.isDark), backgroundColor: 'transparent', }, navigationBar: { // visible: false, - backgroundColor: theme.primary, + backgroundColor: theme.isDark ? '#000' : '#fff', }, layout: { - componentBackgroundColor: theme.primary, + componentBackgroundColor: theme.isDark ? '#000' : '#fff', }, animations: { push: { sharedElementTransitions: [ { - fromId: `pic${id}`, - toId: `pic${id}Dest`, + fromId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_from_${id}`, + toId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_to_${id}`, interpolation: { type: 'spring' }, }, ], elementTransitions: [ { - id: 'title', + id: NAV_SHEAR_NATIVE_IDS.songlistDetail_title, alpha: { from: 0, // We don't declare 'to' value as that is the element's current alpha value, here we're essentially animating from 0 to 1 duration: 300, @@ -275,14 +277,14 @@ export function pushSonglistDetailScreen(componentId, id) { pop: { sharedElementTransitions: [ { - fromId: `pic${id}Dest`, - toId: `pic${id}`, + fromId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_to_${id}`, + toId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_from_${id}`, interpolation: { type: 'spring' }, }, ], elementTransitions: [ { - id: 'title', + id: NAV_SHEAR_NATIVE_IDS.songlistDetail_title, alpha: { to: 0, // We don't declare 'to' value as that is the element's current alpha value, here we're essentially animating from 0 to 1 duration: 300, @@ -307,7 +309,7 @@ export function pushSonglistDetailScreen(componentId, id) { }) }) } -export function pushCommentScreen(componentId) { +export function pushCommentScreen(componentId: string) { /* Navigation.setDefaultOptions({ topBar: { @@ -340,9 +342,10 @@ export function pushCommentScreen(componentId) { }, }) */ - InteractionManager.runAfterInteractions(() => { - const theme = getTheme() - Navigation.push(componentId, { + void InteractionManager.runAfterInteractions(() => { + const theme = themeState.theme + + void Navigation.push(componentId, { component: { name: COMMENT_SCREEN, options: { @@ -354,15 +357,15 @@ export function pushCommentScreen(componentId) { statusBar: { drawBehind: true, visible: true, - style: getStatusBarStyle(), + style: getStatusBarStyle(theme.isDark), backgroundColor: 'transparent', }, navigationBar: { // visible: false, - backgroundColor: theme.primary, + backgroundColor: theme.isDark ? '#000' : '#fff', }, layout: { - componentBackgroundColor: theme.primary, + componentBackgroundColor: theme.isDark ? '#000' : '#fff', }, animations: { push: { @@ -390,7 +393,7 @@ export function pushCommentScreen(componentId) { }) } -// export function pushSettingScreen(componentId) { +// export function pushSettingScreen(componentId: string) { // /* // Navigation.setDefaultOptions({ // topBar: { @@ -423,46 +426,57 @@ export function pushCommentScreen(componentId) { // }, // }) // */ +// void InteractionManager.runAfterInteractions(() => { +// const theme = themeState.theme -// Navigation.push(componentId, { -// component: { -// name: SETTING_SCREEN, -// options: { -// topBar: { -// visible: false, -// height: 0, -// drawBehind: false, -// }, -// statusBar: { -// drawBehind: true, -// visible: true, -// style: getStatusBarStyle(), -// backgroundColor: 'transparent', -// }, -// animations: { -// push: { -// content: { -// translationX: { -// from: Dimensions.get('window').width, -// to: 0, -// duration: 300, +// void Navigation.push(componentId, { +// component: { +// name: SETTING_SCREEN, +// options: { +// topBar: { +// visible: false, +// height: 0, +// drawBehind: false, +// }, +// statusBar: { +// drawBehind: true, +// visible: true, +// style: getStatusBarStyle(theme.isDark), +// backgroundColor: 'transparent', +// }, +// navigationBar: { +// // visible: false, +// backgroundColor: theme.isDark ? '#000' : '#fff', +// }, +// layout: { +// componentBackgroundColor: theme.isDark ? '#000' : '#fff', +// }, +// animations: { +// push: { +// content: { +// translationX: { +// from: Dimensions.get('window').width, +// to: 0, +// duration: 300, +// }, // }, // }, -// }, -// pop: { -// content: { -// translationX: { -// from: 0, -// to: Dimensions.get('window').width, -// duration: 300, +// pop: { +// content: { +// translationX: { +// from: 0, +// to: Dimensions.get('window').width, +// duration: 300, +// }, // }, // }, // }, // }, // }, -// }, +// }) // }) // } + /* export function pushSingleScreenApp() { Navigation.setRoot({ diff --git a/src/navigation/registerScreens.js b/src/navigation/registerScreens.tsx similarity index 84% rename from src/navigation/registerScreens.js rename to src/navigation/registerScreens.tsx index b7988a54c..907ac33eb 100644 --- a/src/navigation/registerScreens.js +++ b/src/navigation/registerScreens.tsx @@ -10,7 +10,7 @@ import { Comment, // Setting, } from '@/screens' -import { Provider } from '@/store' +import { Provider } from '@/store/Provider' import { HOME_SCREEN, @@ -24,8 +24,8 @@ import { import VersionModal from './components/VersionModal' import PactModal from './components/PactModal' -function WrappedComponent(Component) { - return function inject(props) { +function WrappedComponent(Component: any) { + return function inject(props: Record<string, any>) { const EnhancedComponent = () => ( <Provider> <Component @@ -45,6 +45,7 @@ export default () => { Navigation.registerComponent(COMMENT_SCREEN, () => WrappedComponent(Comment)) Navigation.registerComponent(VERSION_MODAL, () => WrappedComponent(VersionModal)) Navigation.registerComponent(PACT_MODAL, () => WrappedComponent(PactModal)) + // Navigation.registerComponent(SETTING_SCREEN, () => WrappedComponent(Setting)) console.info('All screens have been registered...') } diff --git a/src/navigation/screenNames.js b/src/navigation/screenNames.ts similarity index 100% rename from src/navigation/screenNames.js rename to src/navigation/screenNames.ts index 8899781d6..20e3ddf72 100644 --- a/src/navigation/screenNames.js +++ b/src/navigation/screenNames.ts @@ -4,6 +4,6 @@ export const SONGLIST_DETAIL_SCREEN = 'lxm.SonglistDetailScreen' export const COMMENT_SCREEN = 'lxm.CommentScreen' export const VERSION_MODAL = 'lxm.VersionModal' export const PACT_MODAL = 'lxm.PactModal' -// export const TOAST_SCREEN = 'lxm.ToastScreen' // export const SETTING_SCREEN = 'lxm.SettingScreen' +// export const TOAST_SCREEN = 'lxm.ToastScreen' diff --git a/src/navigation/utils.js b/src/navigation/utils.ts similarity index 76% rename from src/navigation/utils.js rename to src/navigation/utils.ts index cd3886861..10293ab3a 100644 --- a/src/navigation/utils.js +++ b/src/navigation/utils.ts @@ -1,19 +1,18 @@ import { Navigation } from 'react-native-navigation' import { VERSION_MODAL, PACT_MODAL } from './screenNames' +import themeState from '@/store/theme/state' -import { getter, getStore } from '@/store' -const store = getStore() -const getStatusBarStyle = () => getter('common', 'isDarkTheme')(store.getState()) ? 'light' : 'dark' +export const getStatusBarStyle = (isDark: boolean) => isDark ? 'light' : 'dark' -export const dismissOverlay = compId => Navigation.dismissOverlay(compId) +export const dismissOverlay = async(compId: string) => Navigation.dismissOverlay(compId) -export const pop = compId => Navigation.pop(compId) -export const popToRoot = compId => Navigation.popToRoot(compId) -export const popTo = compId => Navigation.popTo(compId) +export const pop = async(compId: string) => Navigation.pop(compId) +export const popToRoot = async(compId: string) => Navigation.popToRoot(compId) +export const popTo = async(compId: string) => Navigation.popTo(compId) export const showPactModal = () => { - Navigation.showOverlay({ + void Navigation.showOverlay({ component: { name: PACT_MODAL, options: { @@ -26,9 +25,8 @@ export const showPactModal = () => { statusBar: { drawBehind: true, visible: true, - style: getStatusBarStyle(), + style: getStatusBarStyle(themeState.theme.isDark), backgroundColor: 'transparent', - animate: true, }, // animations: { @@ -57,7 +55,7 @@ export const showPactModal = () => { } export const showVersionModal = () => { - Navigation.showOverlay({ + void Navigation.showOverlay({ component: { name: VERSION_MODAL, options: { @@ -70,9 +68,9 @@ export const showVersionModal = () => { statusBar: { drawBehind: true, visible: true, - style: getStatusBarStyle(), + style: getStatusBarStyle(themeState.theme.isDark), backgroundColor: 'transparent', - animate: true, + // animate: true, }, // animations: { diff --git a/src/plugins/i18n.js b/src/plugins/i18n.js deleted file mode 100644 index d0186f8ad..000000000 --- a/src/plugins/i18n.js +++ /dev/null @@ -1,48 +0,0 @@ -import i18n from 'i18next' -import { useTranslation, initReactI18next } from 'react-i18next' -import langs from '@/lang' - -const resources = {} -const supportedLngs = [] -const langList = [] -for (const { id, name, translation } of langs) { - resources[id] = { - id, - name, - translation, - } - langList.push({ - id, - name, - }) - supportedLngs.push(id) -} - -global.i18n = i18n - -// console.log(resources) -export const init = (lang = 'zh_cn') => { - return i18n - .use(initReactI18next) // passes i18n down to react-i18next - .init({ - compatibilityJSON: 'v3', // https://www.i18next.com/misc/json-format - // debug: true, - resources, - lng: lang, - fallbackLng: 'en_us', - keySeparator: false, - lowerCaseLng: true, - interpolation: { - escapeValue: false, - }, - }) -} - -export const changeLanguage = lang => i18n.changeLanguage(lang) - -export { - useTranslation, - langList, - i18n, - supportedLngs, -} diff --git a/src/plugins/lyric.js b/src/plugins/lyric.ts similarity index 55% rename from src/plugins/lyric.js rename to src/plugins/lyric.ts index 89a4c9cae..bbac42cb4 100644 --- a/src/plugins/lyric.js +++ b/src/plugins/lyric.ts @@ -1,20 +1,24 @@ import { useEffect, useState } from 'react' import Lyric from 'lrc-file-parser' // import { getStore, subscribe } from '@/store' +type Lines = Parameters<ConstructorParameters<typeof Lyric>[0]['onSetLyric']>['0'] +export type Line = Lines[number] +type PlayHook = (line: number, text: string) => void +type SetLyricHook = (lines: Lines) => void const lrcTools = { isInited: false, - lrc: null, + lrc: null as Lyric | null, currentLineData: { line: 0, text: '' }, - currentLines: [], - playHooks: [], - setLyricHooks: [], + currentLines: [] as Lines, + playHooks: [] as PlayHook[], + setLyricHooks: [] as SetLyricHook[], isPlay: false, isShowTranslation: false, isShowRoma: false, lyricText: '', - translationText: '', - romaText: '', + translationText: '' as string | null | undefined, + romaText: '' as string | null | undefined, init() { if (this.isInited) return this.isInited = true @@ -24,36 +28,36 @@ const lrcTools = { offset: 100, // offset time(ms), default is 150 ms }) }, - onPlay(line, text) { + onPlay(line: number, text: string) { this.currentLineData.line = line // console.log(line) this.currentLineData.text = text for (const hook of this.playHooks) hook(line, text) }, - onSetLyric(lines) { + onSetLyric(lines: Lines) { this.currentLines = lines for (const hook of this.playHooks) hook(-1, '') for (const hook of this.setLyricHooks) hook(lines) }, - addPlayHook(callback) { - this.playHooks.push(callback) - callback(this.currentLineData.line, this.currentLineData.text) + addPlayHook(hook: PlayHook) { + this.playHooks.push(hook) + hook(this.currentLineData.line, this.currentLineData.text) }, - removePlayHook(callback) { - this.playHooks.splice(this.playHooks.indexOf(callback), 1) + removePlayHook(hook: PlayHook) { + this.playHooks.splice(this.playHooks.indexOf(hook), 1) }, - addSetLyricHook(callback) { - this.setLyricHooks.push(callback) - callback(this.currentLines) + addSetLyricHook(hook: SetLyricHook) { + this.setLyricHooks.push(hook) + hook(this.currentLines) }, - removeSetLyricHook(callback) { - this.setLyricHooks.splice(this.setLyricHooks.indexOf(callback), 1) + removeSetLyricHook(hook: SetLyricHook) { + this.setLyricHooks.splice(this.setLyricHooks.indexOf(hook), 1) }, setLyric() { - const extendedLyrics = [] + const extendedLyrics = [] as string[] if (this.isShowTranslation && this.translationText) extendedLyrics.push(this.translationText) if (this.isShowRoma && this.romaText) extendedLyrics.push(this.romaText) - this.lrc.setLyric(this.lyricText, extendedLyrics) + this.lrc!.setLyric(this.lyricText, extendedLyrics) }, } @@ -62,42 +66,43 @@ export const init = async() => { lrcTools.init() } -export const setLyric = (lyric, translation, romalrc) => { +export const setLyric = (lyric: string, translation?: string, romalrc?: string) => { lrcTools.isPlay = false lrcTools.lyricText = lyric lrcTools.translationText = translation lrcTools.romaText = romalrc lrcTools.setLyric() } -export const toggleTranslation = isShow => { +export const toggleTranslation = (isShow: boolean) => { lrcTools.isShowTranslation = isShow if (!lrcTools.lyricText) return lrcTools.setLyric() } -export const toggleRoma = isShow => { +export const toggleRoma = (isShow: boolean) => { lrcTools.isShowRoma = isShow if (!lrcTools.lyricText) return lrcTools.setLyric() } -export const play = time => { +export const play = (time: number) => { // console.log(time) lrcTools.isPlay = true - lrcTools.lrc.play(time) + lrcTools.lrc!.play(time) } export const pause = () => { // console.log('pause') lrcTools.isPlay = false - lrcTools.lrc.pause() + lrcTools.lrc!.pause() } // on lyric play hook -export const useLrcPlay = () => { - const [lrcInfo, setLrcInfo] = useState({ line: 0, text: '' }) +export const useLrcPlay = (autoUpdate = true) => { + const [lrcInfo, setLrcInfo] = useState(lrcTools.currentLineData) useEffect(() => { - const setLrcCallback = () => { + if (!autoUpdate) return + const setLrcCallback: SetLyricHook = () => { setLrcInfo({ line: 0, text: '' }) } - const playCallback = (line, text) => { + const playCallback: PlayHook = (line, text) => { setLrcInfo({ line, text }) } lrcTools.addSetLyricHook(setLrcCallback) @@ -106,21 +111,21 @@ export const useLrcPlay = () => { lrcTools.removeSetLyricHook(setLrcCallback) lrcTools.removePlayHook(playCallback) } - }, [setLrcInfo]) + }, [autoUpdate]) return lrcInfo } // on lyric set hook export const useLrcSet = () => { - const [lines, setLines] = useState([]) + const [lines, setLines] = useState<Lines>(lrcTools.currentLines) useEffect(() => { - const callback = lines => { + const callback = (lines: Lines) => { setLines(lines) } lrcTools.addSetLyricHook(callback) return () => lrcTools.removeSetLyricHook(callback) - }, [setLines]) + }, []) return lines } diff --git a/src/plugins/player/hook.js b/src/plugins/player/hook.ts similarity index 60% rename from src/plugins/player/hook.js rename to src/plugins/player/hook.ts index 7b22089a6..9088b1390 100644 --- a/src/plugins/player/hook.js +++ b/src/plugins/player/hook.ts @@ -11,13 +11,13 @@ export const usePlaybackState = () => { setState(playerState) } - setPlayerState() + void setPlayerState() const sub = TrackPlayer.addEventListener(Event.PlaybackState, data => { setState(data.state) }) - return () => sub.remove() + return () => { sub.remove() } }, []) return state @@ -28,45 +28,45 @@ export const usePlaybackState = () => { * @param events - TrackPlayer events to subscribe to * @param handler - callback invoked when the event fires */ -export const useTrackPlayerEvents = (events, handler) => { - const savedHandler = useRef() - - useEffect(() => { - savedHandler.current = handler - }, [handler]) - - useEffect(() => { - // eslint-disable-next-line no-undef - if (__DEV__) { - const allowedTypes = Object.values(Event) - const invalidTypes = events.filter(type => !allowedTypes.includes(type)) - if (invalidTypes.length) { - console.warn( - 'One or more of the events provided to useTrackPlayerEvents is ' + - `not a valid TrackPlayer event: ${invalidTypes.join("', '")}. ` + - 'A list of available events can be found at ' + - 'https://react-native-kit.github.io/react-native-track-player/documentation/#events', - ) - } - } - - const subs = events.map(event => - TrackPlayer.addEventListener(event, payload => savedHandler.current({ ...payload, type: event })), - ) - - return () => subs.forEach(sub => sub.remove()) - }, [events]) -} +// export const useTrackPlayerEvents = (events, handler) => { +// const savedHandler = useRef() + +// useEffect(() => { +// savedHandler.current = handler +// }, [handler]) + +// useEffect(() => { +// // eslint-disable-next-line no-undef +// if (__DEV__) { +// const allowedTypes = Object.values(Event) +// const invalidTypes = events.filter(type => !allowedTypes.includes(type)) +// if (invalidTypes.length) { +// console.warn( +// 'One or more of the events provided to useTrackPlayerEvents is ' + +// `not a valid TrackPlayer event: ${invalidTypes.join("', '")}. ` + +// 'A list of available events can be found at ' + +// 'https://react-native-kit.github.io/react-native-track-player/documentation/#events', +// ) +// } +// } + +// const subs = events.map(event => +// TrackPlayer.addEventListener(event, payload => savedHandler.current({ ...payload, type: event })), +// ) + +// return () => subs.forEach(sub => sub.remove()) +// }, [events]) +// } const pollTrackPlayerStates = [ State.Playing, State.Buffering, -] +] as const /** * Poll for track progress for the given interval (in miliseconds) - * @param interval - ms interval + * @param updateInterval - ms interval */ -export function useProgress(updateInterval) { +export function useProgress(updateInterval: number) { const [state, setState] = useState({ position: 0, duration: 0, buffered: 0 }) const playerState = usePlaybackState() const stateRef = useRef(state) @@ -94,7 +94,6 @@ export function useProgress(updateInterval) { ) return const state = { position, duration, buffered } - // @ts-ignore stateRef.current = state setState(state) } @@ -102,10 +101,11 @@ export function useProgress(updateInterval) { useEffect(() => { if (!pollTrackPlayerStates.includes(playerState)) return - getProgress() + void getProgress() + // eslint-disable-next-line @typescript-eslint/no-misused-promises const poll = setInterval(getProgress, updateInterval || 1000) - return () => clearInterval(poll) + return () => { clearInterval(poll) } }, [playerState, updateInterval]) return state diff --git a/src/plugins/player/index.js b/src/plugins/player/index.ts similarity index 59% rename from src/plugins/player/index.js rename to src/plugins/player/index.ts index 3b966e9e4..e2dd121e2 100644 --- a/src/plugins/player/index.js +++ b/src/plugins/player/index.ts @@ -1,5 +1,4 @@ import TrackPlayer from 'react-native-track-player' -import service from './service' import { updateOptions } from './utils' // const listenEvent = () => { @@ -17,9 +16,9 @@ import { updateOptions } from './utils' // }) // } -const initial = async({ cacheSize, isHandleAudioFocus }) => { - if (global.playerStatus.isIniting || global.playerStatus.isInitialized) return - global.playerStatus.isIniting = true +const initial = async({ cacheSize, isHandleAudioFocus }: { cacheSize: number, isHandleAudioFocus: boolean }) => { + if (global.lx.playerStatus.isIniting || global.lx.playerStatus.isInitialized) return + global.lx.playerStatus.isIniting = true console.log('Cache Size', cacheSize * 1024) await TrackPlayer.setupPlayer({ maxCacheSize: cacheSize * 1024, @@ -28,25 +27,31 @@ const initial = async({ cacheSize, isHandleAudioFocus }) => { handleAudioFocus: isHandleAudioFocus, autoUpdateMetadata: false, }) - global.playerStatus.isInitialized = true - global.playerStatus.isIniting = false + global.lx.playerStatus.isInitialized = true + global.lx.playerStatus.isIniting = false await updateOptions() // listenEvent() } -const registerPlaybackService = async() => { - if (global.playerStatus.isRegisteredService) return - console.log('handle registerPlaybackService...') - await TrackPlayer.registerPlaybackService(() => service) - global.playerStatus.isRegisteredService = true -} - -const isInitialized = () => global.playerStatus.isInitialized +const isInitialized = () => global.lx.playerStatus.isInitialized export { - registerPlaybackService, initial, isInitialized, } + +export { + setResource, + setPause, + setPlay, + setCurrentTime, + getDuration, + setStop, + resetPlay, + getPosition, + updateMetaData, + onStateChange, + isEmpty, +} from './utils' diff --git a/src/plugins/player/playList.js b/src/plugins/player/playList.js deleted file mode 100644 index a0592ede8..000000000 --- a/src/plugins/player/playList.js +++ /dev/null @@ -1,238 +0,0 @@ -import TrackPlayer, { State } from 'react-native-track-player' -import BackgroundTimer from 'react-native-background-timer' -import { defaultUrl } from '@/config' -import { getStore } from '@/store' -import { action as playerAction } from '@/store/modules/player' - -const store = getStore() -const list = [] - -const defaultUserAgent = 'Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Mobile Safari/537.36' -const httpRxp = /^(https?:\/\/.+|\/.+)/ - -export const buildTracks = ({ musicInfo, type, url, duration }) => { - const track = [] - const isShowNotificationImage = store.getState().common.setting.player.isShowNotificationImage - if (url) { - track.push({ - id: `${musicInfo.source}__//${musicInfo.songmid}__//${type}__//${Math.random()}__//${url}`, - url, - title: musicInfo.name || 'Unknow', - artist: musicInfo.singer || 'Unknow', - album: musicInfo.albumName || null, - artwork: isShowNotificationImage && httpRxp.test(musicInfo.img) ? musicInfo.img : null, - userAgent: defaultUserAgent, - musicId: `${musicInfo.source}__//${musicInfo.songmid}__//${type}`, - original: { ...musicInfo }, - duration, - type, - }) - } - track.push({ - id: `${musicInfo.source}__//${musicInfo.songmid}__//${type}__//${Math.random()}__//default`, - url: defaultUrl, - title: musicInfo.name || 'Unknow', - artist: musicInfo.singer || 'Unknow', - album: musicInfo.albumName || null, - artwork: isShowNotificationImage && httpRxp.test(musicInfo.img) ? musicInfo.img : null, - musicId: `${musicInfo.source}__//${musicInfo.songmid}__//${type}`, - original: { ...musicInfo }, - duration: 0, - type, - }) - return track - // console.log('buildTrack', musicInfo.name, url) -} -export const buildTrack = ({ musicInfo, type, url, duration }) => { - const isShowNotificationImage = store.getState().common.setting.player.isShowNotificationImage - return url - ? { - id: `${musicInfo.source}__//${musicInfo.songmid}__//${type}__//${Math.random()}__//${url}`, - url, - title: musicInfo.name || 'Unknow', - artist: musicInfo.singer || 'Unknow', - album: musicInfo.albumName || null, - artwork: isShowNotificationImage && httpRxp.test(musicInfo.img) ? musicInfo.img : null, - userAgent: defaultUserAgent, - musicId: `${musicInfo.source}__//${musicInfo.songmid}__//${type}`, - original: { ...musicInfo }, - duration, - type, - } - : { - id: `${musicInfo.source}__//${musicInfo.songmid}__//${type}__//${Math.random()}__//default`, - url: defaultUrl, - title: musicInfo.name || 'Unknow', - artist: musicInfo.singer || 'Unknow', - album: musicInfo.albumName || null, - artwork: isShowNotificationImage && httpRxp.test(musicInfo.img) ? musicInfo.img : null, - musicId: `${musicInfo.source}__//${musicInfo.songmid}__//${type}`, - original: { ...musicInfo }, - duration: 0, - type, - } -} - -export const isTempTrack = trackId => /\/\/default$/.test(trackId) - - -export const getCurrentTrackId = async() => { - const currentTrackIndex = await TrackPlayer.getCurrentTrack() - return list[currentTrackIndex]?.id -} -export const getCurrentTrack = async() => { - const currentTrackIndex = await TrackPlayer.getCurrentTrack() - return list[currentTrackIndex] -} - -export const playMusic = async(tracks, time) => { - // console.log(tracks, time) - const track = tracks[0] - // await updateMusicInfo(track) - const currentTrackIndex = await TrackPlayer.getCurrentTrack() - await TrackPlayer.add(tracks).then(() => list.push(...tracks)) - const queue = await TrackPlayer.getQueue() - await TrackPlayer.skip(queue.findIndex(t => t.id == track.id)) - - if (currentTrackIndex == null) { - if (!isTempTrack(track.id)) { - if (time) await TrackPlayer.seekTo(time) - if (global.restorePlayInfo) { - await TrackPlayer.pause() - let startupAutoPlay = global.restorePlayInfo.startupAutoPlay - global.restorePlayInfo = null - - if (startupAutoPlay) store.dispatch(playerAction.playMusic()) - } else { - await TrackPlayer.play() - } - } - } else { - await TrackPlayer.pause() - if (!isTempTrack(track.id)) { - await TrackPlayer.seekTo(time) - await TrackPlayer.play() - } - } - - if (queue.length > 2) { - TrackPlayer.remove(Array(queue.length - 2).fill(null).map((_, i) => i)).then(() => list.splice(0, list.length - 2)) - } -} - -// let musicId = null -// let duration = 0 -// let artwork = null -export const updateMetaInfo = async track => { - const isShowNotificationImage = store.getState().common.setting.player.isShowNotificationImage - // console.log('+++++updateMusicPic+++++', track.artwork, track.duration) - - // if (track.musicId == musicId) { - // if (global.playInfo.musicInfo.img != null) artwork = global.playInfo.musicInfo.img - // if (track.duration != null) duration = global.playInfo.duration - // } else { - // musicId = track.musicId - // artwork = global.playInfo.musicInfo.img - // duration = global.playInfo.duration || 0 - // } - // console.log(global.playInfo) - global.playInfo.isPlaying = await TrackPlayer.getState() == State.Playing - await TrackPlayer.updateNowPlayingMetadata({ - title: track.title || 'Unknow', - artist: track.artist || 'Unknow', - album: track.album || null, - artwork: isShowNotificationImage ? global.playInfo?.currentPlayMusicInfo?.img ?? null : null, - duration: global.playInfo?.duration || 0, - }, global.playInfo?.isPlaying) -} - - -// 解决快速切歌导致的通知栏歌曲信息与当前播放歌曲对不上的问题 -const debounceUpdateMetaInfoTools = { - updateMetaPromise: Promise.resolve(), - track: null, - debounce(fn) { - // let delayTimer = null - let isDelayRun = false - let timer = null - let _track = null - return track => { - // console.log('debounceUpdateMetaInfoTools', track.duration, track.artwork) - if (timer) { - BackgroundTimer.clearTimeout(timer) - timer = null - } - // if (delayTimer) { - // BackgroundTimer.clearTimeout(delayTimer) - // delayTimer = null - // } - if (isDelayRun) { - _track = track - timer = BackgroundTimer.setTimeout(() => { - timer = null - let track = _track - _track = null - // isDelayRun = false - fn(track) - }, 1200) - } else { - isDelayRun = true - fn(track) - BackgroundTimer.setTimeout(() => { - // delayTimer = null - isDelayRun = false - }, 1200) - } - } - }, - init() { - return this.debounce(track => { - this.track = track - return this.updateMetaPromise.then(() => { - // console.log('run') - if (this.track.id === track.id) { - this.updateMetaPromise = updateMetaInfo(track) - } - }) - }) - }, -} - -export const delayUpdateMusicInfo = debounceUpdateMetaInfoTools.init() - -// export const delayUpdateMusicInfo = ((fn, delay = 800) => { -// let delayTimer = null -// let isDelayRun = false -// let timer = null -// let _track = null -// return track => { -// _track = track -// if (timer) { -// BackgroundTimer.clearTimeout(timer) -// timer = null -// } -// if (isDelayRun) { -// if (delayTimer) { -// BackgroundTimer.clearTimeout(delayTimer) -// delayTimer = null -// } -// timer = BackgroundTimer.setTimeout(() => { -// timer = null -// let track = _track -// _track = null -// isDelayRun = false -// fn(track) -// }, delay) -// } else { -// isDelayRun = true -// fn(track) -// delayTimer = BackgroundTimer.setTimeout(() => { -// delayTimer = null -// isDelayRun = false -// }, 500) -// } -// } -// })(track => { -// console.log('+++++delayUpdateMusicPic+++++', track.artwork) -// updateMetaInfo(track) -// }) diff --git a/src/plugins/player/playList.ts b/src/plugins/player/playList.ts new file mode 100644 index 000000000..fbb9cb775 --- /dev/null +++ b/src/plugins/player/playList.ts @@ -0,0 +1,283 @@ +import TrackPlayer, { State } from 'react-native-track-player' +import BackgroundTimer from 'react-native-background-timer' +import { defaultUrl } from '@/config' +// import { action as playerAction } from '@/store/modules/player' +import settingState from '@/store/setting/state' + + +const list: LX.Player.Track[] = [] + +const defaultUserAgent = 'Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Mobile Safari/537.36' +const httpRxp = /^(https?:\/\/.+|\/.+)/ + +let isPlaying = false +let prevDuration = -1 + +const formatMusicInfo = (musicInfo: LX.Player.PlayMusic) => { + return 'progress' in musicInfo ? { + id: musicInfo.id, + pic: musicInfo.metadata.musicInfo.meta.picUrl, + name: musicInfo.metadata.musicInfo.name, + singer: musicInfo.metadata.musicInfo.singer, + album: musicInfo.metadata.musicInfo.meta.albumName, + } : { + id: musicInfo.id, + pic: musicInfo.meta.picUrl, + name: musicInfo.name, + singer: musicInfo.singer, + album: musicInfo.meta.albumName, + } +} + +const buildTracks = (musicInfo: LX.Player.PlayMusic, url: LX.Player.Track['url'], duration?: LX.Player.Track['duration']): LX.Player.Track[] => { + const mInfo = formatMusicInfo(musicInfo) + const track = [] as LX.Player.Track[] + const isShowNotificationImage = settingState.setting['player.isShowNotificationImage'] + const album = mInfo.album || undefined + const artwork = isShowNotificationImage && mInfo.pic && httpRxp.test(mInfo.pic) ? mInfo.pic : undefined + if (url) { + track.push({ + id: `${mInfo.id}__//${Math.random()}__//${url}`, + url, + title: mInfo.name || 'Unknow', + artist: mInfo.singer || 'Unknow', + album, + artwork, + userAgent: defaultUserAgent, + musicId: mInfo.id, + original: { ...musicInfo }, + duration, + }) + } + track.push({ + id: `${mInfo.id}__//${Math.random()}__//default`, + url: defaultUrl, + title: mInfo.name || 'Unknow', + artist: mInfo.singer || 'Unknow', + album, + artwork, + musicId: mInfo.id, + original: { ...musicInfo }, + duration: 0, + }) + return track + // console.log('buildTrack', musicInfo.name, url) +} +// const buildTrack = (musicInfo: LX.Player.PlayMusic, url: LX.Player.Track['url'], duration?: LX.Player.Track['duration']): LX.Player.Track => { +// const mInfo = formatMusicInfo(musicInfo) +// const isShowNotificationImage = settingState.setting['player.isShowNotificationImage'] +// const album = mInfo.album || undefined +// const artwork = isShowNotificationImage && mInfo.pic && httpRxp.test(mInfo.pic) ? mInfo.pic : undefined +// return url +// ? { +// id: `${mInfo.id}__//${Math.random()}__//${url}`, +// url, +// title: mInfo.name || 'Unknow', +// artist: mInfo.singer || 'Unknow', +// album, +// artwork, +// userAgent: defaultUserAgent, +// musicId: `${mInfo.id}`, +// original: { ...musicInfo }, +// duration, +// } +// : { +// id: `${mInfo.id}__//${Math.random()}__//default`, +// url: defaultUrl, +// title: mInfo.name || 'Unknow', +// artist: mInfo.singer || 'Unknow', +// album, +// artwork, +// musicId: `${mInfo.id}`, +// original: { ...musicInfo }, +// duration: 0, +// } +// } + +export const isTempTrack = (trackId: string) => /\/\/default$/.test(trackId) + + +export const getCurrentTrackId = async() => { + const currentTrackIndex = await TrackPlayer.getCurrentTrack() + return list[currentTrackIndex]?.id +} +export const getCurrentTrack = async() => { + const currentTrackIndex = await TrackPlayer.getCurrentTrack() + return list[currentTrackIndex] +} + +export const updateMetaData = async(musicInfo: LX.Player.MusicInfo, isPlay: boolean) => { + if (isPlay == isPlaying) { + const duration = await TrackPlayer.getDuration() + // console.log('currentIsPlaying', prevDuration, duration) + if (prevDuration != duration) { + prevDuration = duration + const trackInfo = await getCurrentTrack() + if (trackInfo && musicInfo) { + delayUpdateMusicInfo(musicInfo) + } + } + } else { + const [duration, trackInfo] = await Promise.all([TrackPlayer.getDuration(), getCurrentTrack()]) + prevDuration = duration + if (trackInfo && musicInfo) { + delayUpdateMusicInfo(musicInfo) + } + } +} + +export const playMusic = async(musicInfo: LX.Player.PlayMusic, url: string, time: number) => { + // console.log(tracks, time) + const tracks = buildTracks(musicInfo, url) + const track = tracks[0] + // await updateMusicInfo(track) + const currentTrackIndex = await TrackPlayer.getCurrentTrack() + await TrackPlayer.add(tracks).then(() => list.push(...tracks)) + const queue = await TrackPlayer.getQueue() as LX.Player.Track[] + await TrackPlayer.skip(queue.findIndex(t => t.id == track.id)) + + if (currentTrackIndex == null) { + if (!isTempTrack(track.id)) { + if (time) await TrackPlayer.seekTo(time) + if (global.lx.restorePlayInfo) { + await TrackPlayer.pause() + // let startupAutoPlay = settingState.setting['player.startupAutoPlay'] + global.lx.restorePlayInfo = null + + // TODO startupAutoPlay + // if (startupAutoPlay) store.dispatch(playerAction.playMusic()) + } else { + await TrackPlayer.play() + } + } + } else { + await TrackPlayer.pause() + if (!isTempTrack(track.id)) { + await TrackPlayer.seekTo(time) + await TrackPlayer.play() + } + } + + if (queue.length > 2) { + void TrackPlayer.remove(Array(queue.length - 2).fill(null).map((_, i) => i)).then(() => list.splice(0, list.length - 2)) + } +} + +// let musicId = null +// let duration = 0 +// let artwork = null +const updateMetaInfo = async(mInfo: LX.Player.MusicInfo) => { + const isShowNotificationImage = settingState.setting['player.isShowNotificationImage'] + // const mInfo = formatMusicInfo(musicInfo) + // console.log('+++++updateMusicPic+++++', track.artwork, track.duration) + + // if (track.musicId == musicId) { + // if (global.playInfo.musicInfo.img != null) artwork = global.playInfo.musicInfo.img + // if (track.duration != null) duration = global.playInfo.duration + // } else { + // musicId = track.musicId + // artwork = global.playInfo.musicInfo.img + // duration = global.playInfo.duration || 0 + // } + // console.log('+++++updateMetaInfo+++++', mInfo.name) + isPlaying = await TrackPlayer.getState() == State.Playing + await TrackPlayer.updateNowPlayingMetadata({ + title: mInfo.name ?? 'Unknow', + artist: mInfo.singer ?? 'Unknow', + album: mInfo.album ?? undefined, + artwork: isShowNotificationImage ? mInfo.pic ?? undefined : undefined, + duration: prevDuration || 0, + }, isPlaying) +} + + +// 解决快速切歌导致的通知栏歌曲信息与当前播放歌曲对不上的问题 +const debounceUpdateMetaInfoTools = { + updateMetaPromise: Promise.resolve(), + musicInfo: null as LX.Player.MusicInfo | null, + debounce(fn: (musicInfo: LX.Player.MusicInfo) => void | Promise<void>) { + // let delayTimer = null + let isDelayRun = false + let timer: number | null = null + let _musicInfo: LX.Player.MusicInfo | null = null + return (musicInfo: LX.Player.MusicInfo) => { + // console.log('debounceUpdateMetaInfoTools', musicInfo) + if (timer) { + BackgroundTimer.clearTimeout(timer) + timer = null + } + // if (delayTimer) { + // BackgroundTimer.clearTimeout(delayTimer) + // delayTimer = null + // } + if (isDelayRun) { + _musicInfo = musicInfo + timer = BackgroundTimer.setTimeout(() => { + timer = null + let musicInfo = _musicInfo + _musicInfo = null + if (!musicInfo) return + // isDelayRun = false + void fn(musicInfo) + }, 1200) + } else { + isDelayRun = true + void fn(musicInfo) + BackgroundTimer.setTimeout(() => { + // delayTimer = null + isDelayRun = false + }, 1200) + } + } + }, + init() { + return this.debounce(async(musicInfo: LX.Player.MusicInfo) => { + this.musicInfo = musicInfo + return this.updateMetaPromise.then(() => { + // console.log('run') + if (this.musicInfo?.id === musicInfo.id) { + this.updateMetaPromise = updateMetaInfo(musicInfo) + } + }) + }) + }, +} + +export const delayUpdateMusicInfo = debounceUpdateMetaInfoTools.init() + +// export const delayUpdateMusicInfo = ((fn, delay = 800) => { +// let delayTimer = null +// let isDelayRun = false +// let timer = null +// let _track = null +// return track => { +// _track = track +// if (timer) { +// BackgroundTimer.clearTimeout(timer) +// timer = null +// } +// if (isDelayRun) { +// if (delayTimer) { +// BackgroundTimer.clearTimeout(delayTimer) +// delayTimer = null +// } +// timer = BackgroundTimer.setTimeout(() => { +// timer = null +// let track = _track +// _track = null +// isDelayRun = false +// fn(track) +// }, delay) +// } else { +// isDelayRun = true +// fn(track) +// delayTimer = BackgroundTimer.setTimeout(() => { +// delayTimer = null +// isDelayRun = false +// }, 500) +// } +// } +// })(track => { +// console.log('+++++delayUpdateMusicPic+++++', track.artwork) +// updateMetaInfo(track) +// }) diff --git a/src/plugins/player/service.js b/src/plugins/player/service.js deleted file mode 100644 index d48dff2b6..000000000 --- a/src/plugins/player/service.js +++ /dev/null @@ -1,266 +0,0 @@ -import TrackPlayer, { State as TPState, Event as TPEvent } from 'react-native-track-player' -import { getStore } from '@/store' -import { action as playerAction, STATUS } from '@/store/modules/player' -import { isTempId, isEmpty } from './utils' -import { play as lrcPlay, pause as lrcPause } from '@/utils/lyric' -import { exitApp } from '@/utils/common' -import { getCurrentTrackId, getCurrentTrack, delayUpdateMusicInfo, buildTrack } from './playList' - -const store = getStore() - -let isInitialized = false - -let retryTrack = null -let retryGetUrlId = null -let retryGetUrlNum = 0 -let errorTime = 0 -// let prevDuration = 0 -// let isPlaying = false - -// 销毁播放器并退出 -const handleExitApp = async() => { - global.isPlayedExit = false - exitApp() -} - -const updateMetaData = async isPlaying => { - if (isPlaying == global.playInfo.isPlaying) { - const duration = await TrackPlayer.getDuration() - // console.log('currentIsPlaying', global.playInfo.duration, duration) - if (global.playInfo.duration != duration) { - global.playInfo.duration = duration - const trackInfo = await getCurrentTrack() - if (trackInfo && global.playInfo.currentPlayMusicInfo) { - delayUpdateMusicInfo(buildTrack({ musicInfo: global.playInfo.currentPlayMusicInfo, type: trackInfo.type, url: trackInfo.url, duration })) - } - } - } else { - const [duration, trackInfo] = await Promise.all([TrackPlayer.getDuration(), getCurrentTrack()]) - global.playInfo.duration = duration - if (trackInfo && global.playInfo.currentPlayMusicInfo) { - delayUpdateMusicInfo(buildTrack({ musicInfo: global.playInfo.currentPlayMusicInfo, type: trackInfo.type, url: trackInfo.url, duration })) - } - } -} - -export default async() => { - if (isInitialized) return - - console.log('reg services...') - TrackPlayer.addEventListener(TPEvent.RemotePlay, () => { - // console.log('remote-play') - // TrackPlayer.play() - store.dispatch(playerAction.playMusic()) - }) - - TrackPlayer.addEventListener(TPEvent.RemotePause, () => { - console.log('remote-pause') - store.dispatch(playerAction.pauseMusic()) - // TrackPlayer.pause() - }) - - TrackPlayer.addEventListener(TPEvent.RemoteNext, () => { - console.log('remote-next') - store.dispatch(playerAction.playNext()) - // TrackPlayer.skipToNext() - }) - - TrackPlayer.addEventListener(TPEvent.RemotePrevious, () => { - console.log('remote-previous') - store.dispatch(playerAction.playPrev()) - // TrackPlayer.skipToPrevious() - }) - - TrackPlayer.addEventListener(TPEvent.RemoteStop, async() => { - console.log('remote-stop') - handleExitApp() - }) - - // TrackPlayer.addEventListener(TPEvent.RemoteDuck, async({ permanent, paused, ducking }) => { - // console.log('remote-duck') - // if (paused) { - // store.dispatch(playerAction.setStatus({ status: STATUS.pause, text: '已暂停' })) - // lrcPause() - // } else { - // store.dispatch(playerAction.setStatus({ status: STATUS.playing, text: '播放中...' })) - // TrackPlayer.getPosition().then(position => { - // lrcPlay(position * 1000) - // }) - // } - // }) - - TrackPlayer.addEventListener(TPEvent.PlaybackError, async err => { - console.log('playback-error', err) - // console.log((await TrackPlayer.getQueue())) - lrcPause() - if (!retryTrack) errorTime = await TrackPlayer.getPosition() - retryTrack = await getCurrentTrack() - await TrackPlayer.skipToNext() - }) - - TrackPlayer.addEventListener(TPEvent.RemoteSeek, async({ position }) => { - // console.log(position) - store.dispatch(playerAction.setProgress(position)) - }) - - TrackPlayer.addEventListener(TPEvent.PlaybackState, async info => { - const state = store.getState() - // console.log('playback-state', TPState[info.state]) - - // console.log((await getCurrentTrack())?.id) - if (state.player.isGettingUrl) return - if (isTempId()) return - let currentIsPlaying = false - - switch (info.state) { - case TPState.None: - // console.log('state', 'State.NONE') - break - case TPState.Ready: - // console.log('state', 'State.READY') - // store.dispatch(playerAction.setStatus({ status: STATUS.pause, text: '已暂停' })) - lrcPause() - break - case TPState.Playing: - retryTrack = null - // console.log('state', 'State.PLAYING') - store.dispatch(playerAction.setStatus({ status: STATUS.playing, text: '播放中...' })) - TrackPlayer.getPosition().then(position => { - lrcPlay(position * 1000) - }) - currentIsPlaying = true - break - case TPState.Paused: - // console.log('state', 'State.PAUSED') - store.dispatch(playerAction.setStatus({ status: STATUS.pause, text: '已暂停' })) - lrcPause() - break - case TPState.Stopped: - switch (state.player.status) { - case STATUS.none: - break - - default: - store.dispatch(playerAction.setStatus({ status: STATUS.stop, text: '已停止' })) - break - } - // console.log('state', 'State.STOPPED') - lrcPause() - break - case TPState.Buffering: - store.dispatch(playerAction.setStatus({ status: STATUS.buffering, text: '缓冲中...' })) - // console.log('state', 'State.BUFFERING') - lrcPause() - break - case TPState.Connecting: - switch (state.player.status) { - case STATUS.none: - case STATUS.pause: - case STATUS.stop: - break - - default: - store.dispatch(playerAction.setStatus({ text: '加载中...' })) - break - } - lrcPause() - // console.log('state', 'State.CONNECTING') - break - - default: - console.log('playback-state', info) - break - } - if (global.isPlayedExit) return handleExitApp() - - // console.log('currentIsPlaying', currentIsPlaying, global.playInfo.isPlaying) - await updateMetaData(currentIsPlaying) - }) - TrackPlayer.addEventListener(TPEvent.PlaybackTrackChanged, async info => { - // console.log('nextTrack====>', info) - if (global.isPlayedExit) return handleExitApp() - - global.playerTrackId = await getCurrentTrackId() - if (isEmpty()) { - console.log('====TEMP PAUSE====') - TrackPlayer.pause() - if (retryTrack) { - if (retryTrack.musicId == retryGetUrlId) { - if (++retryGetUrlNum > 1) { - store.dispatch(playerAction.playNext(true)) - retryGetUrlId = null - retryTrack = null - return - } - } else { - retryGetUrlId = retryTrack.musicId - retryGetUrlNum = 0 - } - store.dispatch(playerAction.refreshMusicUrl(global.playInfo.currentPlayMusicInfo, errorTime)) - } else { - store.dispatch(playerAction.playNext(true)) - } - } - // // if (!info.nextTrack) return - // // if (info.track) { - // // const track = info.track.substring(0, info.track.lastIndexOf('__//')) - // // const nextTrack = info.track.substring(0, info.nextTrack.lastIndexOf('__//')) - // // console.log(nextTrack, track) - // // if (nextTrack == track) return - // // } - // // const track = await TrackPlayer.getTrack(info.nextTrack) - // // if (!track) return - // // let newTrack - // // if (track.url == defaultUrl) { - // // TrackPlayer.pause().then(async() => { - // // isRefreshUrl = true - // // retryGetUrlId = track.id - // // retryGetUrlNum = 0 - // // try { - // // newTrack = await updateTrackUrl(track) - // // console.log('++++newTrack++++', newTrack) - // // } catch (error) { - // // console.log('error', error) - // // if (error.message != '跳过播放') TrackPlayer.skipToNext() - // // isRefreshUrl = false - // // retryGetUrlId = null - // // return - // // } - // // retryGetUrlId = null - // // isRefreshUrl = false - // // console.log(await TrackPlayer.getQueue(), null, 2) - // // await TrackPlayer.play() - // // }) - // // } - // // store.dispatch(playerAction.playNext()) - }) - // TrackPlayer.addEventListener('playback-queue-ended', async info => { - // // console.log('playback-queue-ended', info) - // store.dispatch(playerAction.playNext()) - // // if (!info.nextTrack) return - // // const track = await TrackPlayer.getTrack(info.nextTrack) - // // if (!track) return - // // // if (track.url == defaultUrl) { - // // // TrackPlayer.pause() - // // // getMusicUrl(track.original).then(url => { - // // // TrackPlayer.updateMetadataForTrack(info.nextTrack, { - // // // url, - // // // }) - // // // TrackPlayer.play() - // // // }) - // // // } - // // if (!track.artwork) { - // // getMusicPic(track.original).then(url => { - // // console.log(url) - // // TrackPlayer.updateMetadataForTrack(info.nextTrack, { - // // artwork: url, - // // }) - // // }) - // // } - // }) - // TrackPlayer.addEventListener('playback-destroy', async() => { - // console.log('playback-destroy') - // store.dispatch(playerAction.destroy()) - // }) - isInitialized = true -} diff --git a/src/plugins/player/service.ts b/src/plugins/player/service.ts new file mode 100644 index 000000000..461b1af14 --- /dev/null +++ b/src/plugins/player/service.ts @@ -0,0 +1,212 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ +import TrackPlayer, { State as TPState, Event as TPEvent } from 'react-native-track-player' +// import { store } from '@/store' +// import { action as playerAction, STATUS } from '@/store/modules/player' +import { isTempId, isEmpty } from './utils' +// import { play as lrcPlay, pause as lrcPause } from '@/core/lyric' +import { exitApp } from '@/core/common' +import { getCurrentTrackId } from './playList' +import { pause, play, playNext, playPrev } from '@/core/player/player' + +let isInitialized = false + +// let retryTrack: LX.Player.Track | null = null +// let retryGetUrlId: string | null = null +// let retryGetUrlNum = 0 +// let errorTime = 0 +// let prevDuration = 0 +// let isPlaying = false + +// 销毁播放器并退出 +const handleExitApp = async() => { + global.lx.isPlayedStop = false + exitApp() +} + + +const registerPlaybackService = async() => { + if (isInitialized) return + + console.log('reg services...') + TrackPlayer.addEventListener(TPEvent.RemotePlay, () => { + // console.log('remote-play') + play() + }) + + TrackPlayer.addEventListener(TPEvent.RemotePause, () => { + // console.log('remote-pause') + void pause() + }) + + TrackPlayer.addEventListener(TPEvent.RemoteNext, () => { + // console.log('remote-next') + void playNext() + }) + + TrackPlayer.addEventListener(TPEvent.RemotePrevious, () => { + // console.log('remote-previous') + void playPrev() + }) + + TrackPlayer.addEventListener(TPEvent.RemoteStop, () => { + // console.log('remote-stop') + void handleExitApp() + }) + + // TrackPlayer.addEventListener(TPEvent.RemoteDuck, async({ permanent, paused, ducking }) => { + // console.log('remote-duck') + // if (paused) { + // store.dispatch(playerAction.setStatus({ status: STATUS.pause, text: '已暂停' })) + // lrcPause() + // } else { + // store.dispatch(playerAction.setStatus({ status: STATUS.playing, text: '播放中...' })) + // TrackPlayer.getPosition().then(position => { + // lrcPlay(position * 1000) + // }) + // } + // }) + + TrackPlayer.addEventListener(TPEvent.PlaybackError, async(err: any) => { + console.log('playback-error', err) + global.app_event.error() + global.app_event.playerError() + }) + + TrackPlayer.addEventListener(TPEvent.RemoteSeek, async({ position }) => { + global.app_event.setProgress(position) + }) + + TrackPlayer.addEventListener(TPEvent.PlaybackState, info => { + if (global.lx.gettingUrlId || isTempId()) return + // let currentIsPlaying = false + + switch (info.state) { + case TPState.None: + // console.log('state', 'State.NONE') + break + case TPState.Ready: + case TPState.Stopped: + case TPState.Paused: + global.app_event.playerPause() + global.app_event.pause() + break + case TPState.Playing: + global.app_event.playerPlaying() + global.app_event.play() + break + case TPState.Buffering: + global.app_event.pause() + global.app_event.playerWaiting() + break + case TPState.Connecting: + global.app_event.playerLoadstart() + break + default: + // console.log('playback-state', info) + break + } + if (global.lx.isPlayedStop) return handleExitApp() + + // console.log('currentIsPlaying', currentIsPlaying, global.lx.playInfo.isPlaying) + // void updateMetaData(global.lx.store_playMusicInfo.musicInfo, currentIsPlaying) + }) + TrackPlayer.addEventListener(TPEvent.PlaybackTrackChanged, async info => { + // console.log('PlaybackTrackChanged====>', info) + global.lx.playerTrackId = await getCurrentTrackId() + if (info.track == null) return + if (global.lx.isPlayedStop) return handleExitApp() + + // console.log('global.lx.playerTrackId====>', global.lx.playerTrackId) + if (isEmpty()) { + // console.log('====TEMP PAUSE====') + await TrackPlayer.pause() + global.app_event.playerEnded() + global.app_event.playerEmptied() + // if (retryTrack) { + // if (retryTrack.musicId == retryGetUrlId) { + // if (++retryGetUrlNum > 1) { + // store.dispatch(playerAction.playNext(true)) + // retryGetUrlId = null + // retryTrack = null + // return + // } + // } else { + // retryGetUrlId = retryTrack.musicId + // retryGetUrlNum = 0 + // } + // store.dispatch(playerAction.refreshMusicUrl(global.lx.playInfo.currentPlayMusicInfo, errorTime)) + // } else { + // store.dispatch(playerAction.playNext(true)) + // } + } + // // if (!info.nextTrack) return + // // if (info.track) { + // // const track = info.track.substring(0, info.track.lastIndexOf('__//')) + // // const nextTrack = info.track.substring(0, info.nextTrack.lastIndexOf('__//')) + // // console.log(nextTrack, track) + // // if (nextTrack == track) return + // // } + // // const track = await TrackPlayer.getTrack(info.nextTrack) + // // if (!track) return + // // let newTrack + // // if (track.url == defaultUrl) { + // // TrackPlayer.pause().then(async() => { + // // isRefreshUrl = true + // // retryGetUrlId = track.id + // // retryGetUrlNum = 0 + // // try { + // // newTrack = await updateTrackUrl(track) + // // console.log('++++newTrack++++', newTrack) + // // } catch (error) { + // // console.log('error', error) + // // if (error.message != '跳过播放') TrackPlayer.skipToNext() + // // isRefreshUrl = false + // // retryGetUrlId = null + // // return + // // } + // // retryGetUrlId = null + // // isRefreshUrl = false + // // console.log(await TrackPlayer.getQueue(), null, 2) + // // await TrackPlayer.play() + // // }) + // // } + // // store.dispatch(playerAction.playNext()) + }) + // TrackPlayer.addEventListener('playback-queue-ended', async info => { + // // console.log('playback-queue-ended', info) + // store.dispatch(playerAction.playNext()) + // // if (!info.nextTrack) return + // // const track = await TrackPlayer.getTrack(info.nextTrack) + // // if (!track) return + // // // if (track.url == defaultUrl) { + // // // TrackPlayer.pause() + // // // getMusicUrl(track.original).then(url => { + // // // TrackPlayer.updateMetadataForTrack(info.nextTrack, { + // // // url, + // // // }) + // // // TrackPlayer.play() + // // // }) + // // // } + // // if (!track.artwork) { + // // getMusicPic(track.original).then(url => { + // // console.log(url) + // // TrackPlayer.updateMetadataForTrack(info.nextTrack, { + // // artwork: url, + // // }) + // // }) + // // } + // }) + // TrackPlayer.addEventListener('playback-destroy', async() => { + // console.log('playback-destroy') + // store.dispatch(playerAction.destroy()) + // }) + isInitialized = true +} + + +export default () => { + if (global.lx.playerStatus.isRegisteredService) return + console.log('handle registerPlaybackService...') + TrackPlayer.registerPlaybackService(() => registerPlaybackService) + global.lx.playerStatus.isRegisteredService = true +} diff --git a/src/plugins/player/utils.js b/src/plugins/player/utils.ts similarity index 68% rename from src/plugins/player/utils.js rename to src/plugins/player/utils.ts index 29e00e864..77fe199ff 100644 --- a/src/plugins/player/utils.js +++ b/src/plugins/player/utils.ts @@ -1,14 +1,18 @@ -import TrackPlayer, { Capability } from 'react-native-track-player' +import TrackPlayer, { Capability, Event, State } from 'react-native-track-player' import BackgroundTimer from 'react-native-background-timer' import { playMusic as handlePlayMusic } from './playList' +// import { PlayerMusicInfo } from '@/store/modules/player/playInfo' export { useProgress } from './hook' const emptyIdRxp = /\/\/default$/ const tempIdRxp = /\/\/default$|\/\/default\/\/restorePlay$/ -export const isEmpty = (trackId = global.playerTrackId) => emptyIdRxp.test(trackId) -export const isTempId = (trackId = global.playerTrackId) => tempIdRxp.test(trackId) +export const isEmpty = (trackId = global.lx.playerTrackId) => { + console.log(trackId) + return !trackId || emptyIdRxp.test(trackId) +} +export const isTempId = (trackId = global.lx.playerTrackId) => !trackId || tempIdRxp.test(trackId) // export const replacePlayTrack = async(newTrack, oldTrack) => { // console.log('replaceTrack') @@ -100,14 +104,16 @@ export const isTempId = (trackId = global.playerTrackId) => tempIdRxp.test(track // }, // } -export const playMusic = ((fn, delay = 800) => { - let delayTimer = null +const playMusic = ((fn: (musicInfo: LX.Player.PlayMusic, url: string, time: number) => void, delay = 800) => { + let delayTimer: number | null = null let isDelayRun = false - let timer = null - let _tracks = null - let _time = null - return (tracks, time) => { - _tracks = tracks + let timer: number | null = null + let _musicInfo: LX.Player.PlayMusic | null = null + let _url = '' + let _time = 0 + return (musicInfo: LX.Player.PlayMusic, url: string, time: number) => { + _musicInfo = musicInfo + _url = url _time = time if (timer) { BackgroundTimer.clearTimeout(timer) @@ -120,50 +126,96 @@ export const playMusic = ((fn, delay = 800) => { } timer = BackgroundTimer.setTimeout(() => { timer = null - let tracks = _tracks + let musicInfo = _musicInfo + let url = _url let time = _time - _tracks = null - _time = null + _musicInfo = null + _url = '' + _time = 0 isDelayRun = false - fn(tracks, time) + fn(musicInfo as LX.Player.PlayMusic, url, time) }, delay) } else { isDelayRun = true - fn(tracks, time) + fn(musicInfo, url, time) delayTimer = BackgroundTimer.setTimeout(() => { delayTimer = null isDelayRun = false }, 500) } } -})((tracks, time) => { - handlePlayMusic(tracks, time) +})((musicInfo, url, time) => { + void handlePlayMusic(musicInfo, url, time) }) -export const play = () => TrackPlayer.play() -export const getPosition = () => TrackPlayer.getPosition() -export const stop = () => TrackPlayer.stop() -export const pause = () => TrackPlayer.pause() +export const setResource = (musicInfo: LX.Player.PlayMusic, url: string, duration?: number) => { + playMusic(musicInfo, url, duration ?? 0) +} + +export const setPlay = async() => TrackPlayer.play() +export const getPosition = async() => TrackPlayer.getPosition() +export const getDuration = async() => TrackPlayer.getDuration() +export const setStop = async() => { + await TrackPlayer.stop() + if (!isEmpty()) await TrackPlayer.skipToNext() +} +export const setPause = async() => TrackPlayer.pause() // export const skipToNext = () => TrackPlayer.skipToNext() -export const seekTo = time => TrackPlayer.seekTo(time) +export const setCurrentTime = async(time: number) => TrackPlayer.seekTo(time) -export const resetPlay = async() => Promise.all([pause(), seekTo(0)]) +export const resetPlay = async() => Promise.all([setPause(), setCurrentTime(0)]) export const destroy = async() => { - if (global.playerStatus.isIniting || !global.playerStatus.isInitialized) return + if (global.lx.playerStatus.isIniting || !global.lx.playerStatus.isInitialized) return await TrackPlayer.destroy() - global.playerStatus.isInitialized = false + global.lx.playerStatus.isInitialized = false } +type PlayStatus = 'None' | 'Ready' | 'Playing' | 'Paused' | 'Stopped' | 'Buffering' | 'Connecting' + +export const onStateChange = async(listener: (state: PlayStatus) => void) => { + const sub = TrackPlayer.addEventListener(Event.PlaybackState, state => { + let _state: PlayStatus + switch (state) { + case State.Ready: + _state = 'Ready' + break + case State.Playing: + _state = 'Playing' + break + case State.Paused: + _state = 'Paused' + break + case State.Stopped: + _state = 'Stopped' + break + case State.Buffering: + _state = 'Buffering' + break + case State.Connecting: + _state = 'Connecting' + break + case State.None: + default: + _state = 'None' + break + } + listener(_state) + }) + + return () => { + sub.remove() + } +} /** * Subscription player state chuange event - * @param {*} callback state change event + * @param options state change event * @returns remove event function */ // export const playState = callback => TrackPlayer.addEventListener('playback-state', callback) -export const updateOptions = (options = { +export const updateOptions = async(options = { // Whether the player should stop running when the app is closed on Android // stopWithApp: true, @@ -230,3 +282,5 @@ export const updateOptions = (options = { // export { // useProgress, // } + +export { updateMetaData } from './playList' diff --git a/src/plugins/storage.js b/src/plugins/storage.js deleted file mode 100644 index 9d8b56724..000000000 --- a/src/plugins/storage.js +++ /dev/null @@ -1,167 +0,0 @@ -import AsyncStorage from '@react-native-async-storage/async-storage' - -const partKeyPrefix = '@___PART___' -const partKeyPrefixRxp = /^@___PART___/ -const keySplit = ',' -const limit = 500000 - -const buildData = (key, value, datas) => { - let valueStr = JSON.stringify(value) - if (valueStr.length <= limit) return datas.push([key, valueStr]) - - const partKeys = [] - for (let i = 0, len = Math.floor(valueStr.length / limit); i <= len; i++) { - let partKey = `${partKeyPrefix}${key}${i}` - partKeys.push(partKey) - datas.push([partKey, valueStr.substring(i * limit, (i + 1) * limit)]) - } - datas.push([key, `${partKeyPrefix}${partKeys.join(keySplit)}`]) - return datas -} - -const handleGetData = partKeys => { - partKeys = partKeys.replace(partKeyPrefixRxp, '').split(keySplit) - - return AsyncStorage.multiGet(partKeys).then(datas => { - return JSON.parse(datas.map(data => data[1]).join('')) - }) -} - -export const setData = async(key, value) => { - const datas = [] - buildData(key, value, datas) - - try { - await AsyncStorage.multiSet(datas) - } catch (e) { - // saving error - console.log(e.message) - throw e - } -} - -export const getData = async key => { - let value - try { - value = await AsyncStorage.getItem(key) - } catch (e) { - // error reading value - console.log(e.message) - throw e - } - if (partKeyPrefixRxp.test(value)) { - return handleGetData(value) - } else if (value) value = JSON.parse(value) - return value -} - -export const removeData = async key => { - let value - try { - value = await AsyncStorage.getItem(key) - } catch (e) { - // error reading value - console.log(e.message) - throw e - } - if (partKeyPrefixRxp.test(value)) { - let partKeys = value.replace(partKeyPrefixRxp, '').split(keySplit) - partKeys.push(key) - try { - await AsyncStorage.multiRemove(partKeys) - } catch (e) { - // remove error - console.log(e.message) - throw e - } - } else { - try { - await AsyncStorage.removeItem(key) - } catch (e) { - // remove error - console.log(e.message) - throw e - } - } -} - -export const getAllKeys = async() => { - let keys - try { - keys = await AsyncStorage.getAllKeys() - } catch (e) { - // read key error - console.log(e.message) - throw e - } - - return keys -} - -export const getDataMultiple = async keys => { - let datas - try { - datas = await AsyncStorage.multiGet(keys) - } catch (e) { - // read error - console.log(e.message) - throw e - } - const promises = [] - for (const data of datas) { - if (partKeyPrefixRxp.test(data[1])) { - promises.push(handleGetData(data[1])) - } else { - promises.push(Promise.resolve(data[1] ? JSON.parse(data[1]) : data[1])) - } - } - return Promise.all(promises).then(values => { - return datas.map(([key], index) => ({ key, value: values[index] })) - }) -} - -export const setDataMultiple = async datas => { - const allData = [] - for (const { key, value } of datas) { - buildData(key, value, allData) - } - try { - await AsyncStorage.multiSet(allData) - } catch (e) { - // save error - console.log(e.message) - throw e - } -} - - -export const removeDataMultiple = async keys => { - if (!keys.length) return - const datas = await AsyncStorage.multiGet(keys) - let allKeys = [] - for (const [key, value] of datas) { - allKeys.push(key) - if (partKeyPrefixRxp.test(value)) { - allKeys.push(...value.replace(partKeyPrefixRxp, '').split(keySplit)) - } - } - try { - await AsyncStorage.multiRemove(allKeys) - } catch (e) { - // remove error - console.log(e.message) - throw e - } -} - -export const clearAll = async() => { - try { - await AsyncStorage.clear() - } catch (e) { - // clear error - console.log(e.message) - throw e - } -} - -export const useAsyncStorage = AsyncStorage.useAsyncStorage diff --git a/src/plugins/storage.ts b/src/plugins/storage.ts new file mode 100644 index 000000000..6146ce330 --- /dev/null +++ b/src/plugins/storage.ts @@ -0,0 +1,172 @@ +import AsyncStorage from '@react-native-async-storage/async-storage' +import { log } from '@/utils/log' + +const partKeyPrefix = '@___PART___' +const partKeyPrefixRxp = /^@___PART___/ +const keySplit = ',' +const limit = 500000 + +const buildData = (key: string, value: any, datas: Array<[string, string]>) => { + let valueStr = JSON.stringify(value) + if (valueStr.length <= limit) { + datas.push([key, valueStr]) + return + } + + const partKeys = [] + for (let i = 0, len = Math.floor(valueStr.length / limit); i <= len; i++) { + let partKey = `${partKeyPrefix}${key}${i}` + partKeys.push(partKey) + datas.push([partKey, valueStr.substring(i * limit, (i + 1) * limit)]) + } + datas.push([key, `${partKeyPrefix}${partKeys.join(keySplit)}`]) +} + +const handleGetData = async<T>(partKeys: string): Promise<T> => { + const keys = partKeys.replace(partKeyPrefixRxp, '').split(keySplit) + + return AsyncStorage.multiGet(keys).then(datas => { + return JSON.parse(datas.map(data => data[1]).join('')) + }) +} + +export const saveData = async(key: string, value: any) => { + const datas: Array<[string, string]> = [] + buildData(key, value, datas) + + try { + await AsyncStorage.multiSet(datas) + } catch (e: any) { + // saving error + log.error('storage error[saveData]:', key, e.message) + throw e + } +} + +export const getData = async<T = unknown>(key: string): Promise<T | null> => { + let value: string | null + try { + value = await AsyncStorage.getItem(key) + } catch (e: any) { + // error reading value + log.error('storage error[getData]:', key, e.message) + throw e + } + if (value && partKeyPrefixRxp.test(value)) { + return handleGetData<T>(value) + } else if (value == null) return value + return JSON.parse(value) +} + +export const removeData = async(key: string) => { + let value: string | null + try { + value = await AsyncStorage.getItem(key) + } catch (e: any) { + // error reading value + log.error('storage error[removeData]:', key, e.message) + throw e + } + if (value && partKeyPrefixRxp.test(value)) { + let partKeys = value.replace(partKeyPrefixRxp, '').split(keySplit) + partKeys.push(key) + try { + await AsyncStorage.multiRemove(partKeys) + } catch (e: any) { + // remove error + log.error('storage error[removeData]:', key, e.message) + throw e + } + } else { + try { + await AsyncStorage.removeItem(key) + } catch (e: any) { + // remove error + log.error('storage error[removeData]:', key, e.message) + throw e + } + } +} + +export const getAllKeys = async() => { + let keys + try { + keys = await AsyncStorage.getAllKeys() + } catch (e: any) { + // read key error + log.error('storage error[getAllKeys]:', e.message) + throw e + } + + return keys +} + + +export const getDataMultiple = async<T extends readonly string[]>(keys: T) => { + type RawData = { [K in keyof T]: [T[K], string | null] } + let datas: RawData + try { + datas = await AsyncStorage.multiGet(keys) as RawData + } catch (e: any) { + // read error + log.error('storage error[getDataMultiple]:', e.message) + throw e + } + const promises: Array<Promise<ReadonlyArray<[unknown | null]>>> = [] + for (const [, value] of datas) { + if (value && partKeyPrefixRxp.test(value)) { + promises.push(handleGetData(value)) + } else { + promises.push(Promise.resolve(value ? JSON.parse(value) : value)) + } + } + return Promise.all(promises).then(values => { + return datas.map(([key], index) => ([key, values[index]])) as { [K in keyof T]: [T[K], unknown] } + }) +} + +export const saveDataMultiple = async(datas: Array<[string, any]>) => { + const allData: Array<[string, string]> = [] + for (const [key, value] of datas) { + buildData(key, value, allData) + } + try { + await AsyncStorage.multiSet(allData) + } catch (e: any) { + // save error + log.error('storage error[saveDataMultiple]:', e.message) + throw e + } +} + + +export const removeDataMultiple = async(keys: string[]) => { + if (!keys.length) return + const datas = await AsyncStorage.multiGet(keys) + let allKeys = [] + for (const [key, value] of datas) { + allKeys.push(key) + if (value && partKeyPrefixRxp.test(value)) { + allKeys.push(...value.replace(partKeyPrefixRxp, '').split(keySplit)) + } + } + try { + await AsyncStorage.multiRemove(allKeys) + } catch (e: any) { + // remove error + log.error('storage error[removeDataMultiple]:', e.message) + throw e + } +} + +export const clearAll = async() => { + try { + await AsyncStorage.clear() + } catch (e: any) { + // clear error + log.error('storage error[clearAll]:', e.message) + throw e + } +} + +export { useAsyncStorage } from '@react-native-async-storage/async-storage' diff --git a/src/plugins/sync/client/auth.js b/src/plugins/sync/client/auth.js deleted file mode 100644 index 9a77b8208..000000000 --- a/src/plugins/sync/client/auth.js +++ /dev/null @@ -1,76 +0,0 @@ -import { getSyncAuthKey, setSyncAuthKey } from '@/utils/tools' -import { request, aesEncrypt, aesDecrypt } from './utils' -import { getDeviceName } from '@/utils/utils' -import { SYNC_CODE } from './config' -import log from '../log' - - -const hello = (host, port) => request(`http://${host}:${port}/hello`) - .then(text => text == SYNC_CODE.helloMsg) - .catch(err => { - log.error('[auth] hello', err.message) - console.log(err) - return false - }) - -const getServerId = (host, port) => request(`http://${host}:${port}/id`) - .then(text => { - if (!text.startsWith(SYNC_CODE.idPrefix)) return '' - return text.replace(SYNC_CODE.idPrefix, '') - }) - .catch(err => { - log.error('[auth] getServerId', err.message) - console.log(err) - return false - }) - -const codeAuth = async(host, port, serverId, authCode) => { - let key = ''.padStart(16, Buffer.from(authCode).toString('hex')) - const iv = Buffer.from(key.split('').reverse().join('')).toString('base64') - key = Buffer.from(key).toString('base64') - const msg = aesEncrypt(SYNC_CODE.authMsg + await getDeviceName(), key, iv) - return request(`http://${host}:${port}/ah`, { headers: { m: msg } }).then(text => { - // console.log(text) - let msg - try { - msg = aesDecrypt(text, key, iv) - } catch (err) { - log.error('[auth] codeAuth decryptMsg error', err.message) - throw new Error(SYNC_CODE.authFailed) - } - if (!msg) return Promise.reject(new Error(SYNC_CODE.authFailed)) - const info = JSON.parse(msg) - setSyncAuthKey(serverId, info) - return info - }) -} - -const keyAuth = async(host, port, keyInfo) => { - const msg = aesEncrypt(SYNC_CODE.authMsg + await getDeviceName(), keyInfo.key, keyInfo.iv) - return request(`http://${host}:${port}/ah`, { headers: { i: keyInfo.clientId, m: msg } }).then(text => { - let msg - try { - msg = aesDecrypt(text, keyInfo.key, keyInfo.iv) - } catch (err) { - log.error('[auth] keyAuth decryptMsg error', err.message) - throw new Error(SYNC_CODE.authFailed) - } - if (msg != SYNC_CODE.helloMsg) return Promise.reject(new Error(SYNC_CODE.authFailed)) - }) -} - -const auth = async(host, port, serverId, authCode) => { - if (authCode) return codeAuth(host, port, serverId, authCode) - const keyInfo = await getSyncAuthKey(serverId) - if (!keyInfo) throw new Error(SYNC_CODE.missingAuthCode) - await keyAuth(host, port, keyInfo) - return keyInfo -} - -export default async(host, port, authCode) => { - console.log('connect: ', host, port, authCode) - if (!await hello(host, port)) throw new Error(SYNC_CODE.connectServiceFailed) - const serverId = await getServerId(host, port) - if (!serverId) throw new Error(SYNC_CODE.getServiceIdFailed) - return auth(host, port, serverId, authCode) -} diff --git a/src/plugins/sync/client/auth.ts b/src/plugins/sync/client/auth.ts new file mode 100644 index 000000000..cb0a6cb54 --- /dev/null +++ b/src/plugins/sync/client/auth.ts @@ -0,0 +1,92 @@ +import { getSyncAuthKey, setSyncAuthKey } from '@/utils/data' +import { request, aesEncrypt, aesDecrypt, generateRsaKey, rsaDecrypt } from './utils' +import { getDeviceName } from '@/utils/nativeModules/utils' +import { SYNC_CODE } from './config' +import log from '../log' + + +const hello = async(host: string, port: string) => request(`http://${host}:${port}/hello`) + .then(({ text }) => text == SYNC_CODE.helloMsg) + .catch((err: any) => { + log.error('[auth] hello', err.message) + console.log(err) + return false + }) + +const getServerId = async(host: string, port: string) => request(`http://${host}:${port}/id`) + .then(({ text }) => { + if (!text.startsWith(SYNC_CODE.idPrefix)) return '' + return text.replace(SYNC_CODE.idPrefix, '') + }) + .catch((err: any) => { + log.error('[auth] getServerId', err.message) + console.log(err) + throw err + }) + +const codeAuth = async(host: string, port: string, serverId: string, authCode: string) => { + let key = ''.padStart(16, Buffer.from(authCode).toString('hex')) + // const iv = Buffer.from(key.split('').reverse().join('')).toString('base64') + key = Buffer.from(key).toString('base64') + let { publicKey, privateKey } = await generateRsaKey() + publicKey = publicKey.replace(/\n/g, '') + .replace('-----BEGIN PUBLIC KEY-----', '') + .replace('-----END PUBLIC KEY-----', '') + const msg = aesEncrypt(`${SYNC_CODE.authMsg}\n${publicKey}\n${await getDeviceName()}`, key) + // console.log(msg, key) + return request(`http://${host}:${port}/ah`, { headers: { m: msg } }).then(async({ text, code }) => { + // console.log(text) + switch (text) { + case SYNC_CODE.msgBlockedIp: + throw new Error(SYNC_CODE.msgBlockedIp) + case SYNC_CODE.authFailed: + throw new Error(SYNC_CODE.authFailed) + default: + if (code != 200) throw new Error(SYNC_CODE.authFailed) + } + let msg + try { + msg = rsaDecrypt(Buffer.from(text, 'base64'), privateKey).toString() + } catch (err: any) { + log.error('[auth] codeAuth decryptMsg error', err.message) + throw new Error(SYNC_CODE.authFailed) + } + // console.log(msg) + if (!msg) return Promise.reject(new Error(SYNC_CODE.authFailed)) + const info = JSON.parse(msg) + void setSyncAuthKey(serverId, info) + return info + }) +} + +const keyAuth = async(host: string, port: string, keyInfo: LX.Sync.KeyInfo) => { + const msg = aesEncrypt(SYNC_CODE.authMsg + await getDeviceName(), keyInfo.key) + return request(`http://${host}:${port}/ah`, { headers: { i: keyInfo.clientId, m: msg } }).then(({ text, code }) => { + if (code != 200) throw new Error(SYNC_CODE.authFailed) + + let msg + try { + msg = aesDecrypt(text, keyInfo.key) + } catch (err: any) { + log.error('[auth] keyAuth decryptMsg error', err.message) + throw new Error(SYNC_CODE.authFailed) + } + if (msg != SYNC_CODE.helloMsg) return Promise.reject(new Error(SYNC_CODE.authFailed)) + }) +} + +const auth = async(host: string, port: string, serverId: string, authCode?: string) => { + if (authCode) return codeAuth(host, port, serverId, authCode) + const keyInfo = await getSyncAuthKey(serverId) + if (!keyInfo) throw new Error(SYNC_CODE.missingAuthCode) + await keyAuth(host, port, keyInfo) + return keyInfo +} + +export default async(host: string, port: string, authCode?: string) => { + console.log('connect: ', host, port, authCode) + if (!await hello(host, port)) throw new Error(SYNC_CODE.connectServiceFailed) + const serverId = await getServerId(host, port) + if (!serverId) throw new Error(SYNC_CODE.getServiceIdFailed) + return auth(host, port, serverId, authCode) +} diff --git a/src/plugins/sync/client/client.js b/src/plugins/sync/client/client.ts similarity index 71% rename from src/plugins/sync/client/client.js rename to src/plugins/sync/client/client.ts index c719284c1..44398dc32 100644 --- a/src/plugins/sync/client/client.js +++ b/src/plugins/sync/client/client.ts @@ -1,27 +1,29 @@ -import { io } from 'socket.io/client-dist/socket.io' +import { io } from 'socket.io-client' import { aesEncrypt } from './utils' import * as modules from '../modules' -import { action as commonAction } from '@/store/modules/common' -import { getStore } from '@/store' +// import { action as commonAction } from '@/store/modules/common' +// import { getStore } from '@/store' import registerSyncListHandler from './syncList' import log from '../log' +import { setSyncStatus } from '@/core/sync' +import { SYNC_CODE } from './config' -const handleConnection = (socket) => { +const handleConnection = (socket: LX.Sync.Socket) => { for (const module of Object.values(modules)) { module.registerListHandler(socket) } } -let socket -let listSyncPromise -export const connect = (host, port, keyInfo) => { +let socket: LX.Sync.Socket | null +let listSyncPromise: Promise<void> +export const connect = (host: string, port: string, keyInfo: LX.Sync.KeyInfo) => { socket = io(`ws://${host}:${port}`, { path: '/sync', reconnectionAttempts: 5, transports: ['websocket'], query: { i: keyInfo.clientId, - t: aesEncrypt('lx-music connect', keyInfo.key, keyInfo.iv), + t: aesEncrypt(SYNC_CODE.msgConnect, keyInfo.key), }, }) @@ -30,39 +32,38 @@ export const connect = (host, port, keyInfo) => { socket.on('connect', async() => { console.log('connect') log.info('connect') - const store = getStore() - global.syncKeyInfo = keyInfo - store.dispatch(commonAction.setSyncStatus({ + // const store = getStore() + // global.lx.syncKeyInfo = keyInfo + setSyncStatus({ status: false, message: 'Wait syncing...', - })) + }) try { await listSyncPromise - } catch (err) { + } catch (err: any) { console.log(err) log.r_error(err.stack) - store.dispatch(commonAction.setSyncStatus({ + setSyncStatus({ status: false, message: err.message, - })) + }) return } log.info('sync list success') - handleConnection(socket) + handleConnection(socket as LX.Sync.Socket) log.info('register list sync service success') - store.dispatch(commonAction.setSyncStatus({ + setSyncStatus({ status: true, message: '', - })) + }) }) socket.on('connect_error', (err) => { console.log(err.message) log.error('connect error: ', err.stack) - const store = getStore() - store.dispatch(commonAction.setSyncStatus({ + setSyncStatus({ status: false, message: err.message, - })) + }) // if (err.message === 'invalid credentials') { // socket.auth.token = 'efgh' // socket.connect() @@ -71,11 +72,10 @@ export const connect = (host, port, keyInfo) => { socket.on('disconnect', (reason) => { console.log('disconnect', reason) log.warn('disconnect: ', reason) - const store = getStore() - store.dispatch(commonAction.setSyncStatus({ + setSyncStatus({ status: false, message: reason, - })) + }) // if (reason === 'io server disconnect') { // // the disconnection was initiated by the server, you need to reconnect manually // socket.connect() @@ -107,6 +107,7 @@ export const connect = (host, port, keyInfo) => { export const disconnect = async() => { if (!socket) return log.info('disconnecting...') - await socket.close() + socket.close() socket = null } + diff --git a/src/plugins/sync/client/config.js b/src/plugins/sync/client/config.ts similarity index 75% rename from src/plugins/sync/client/config.js rename to src/plugins/sync/client/config.ts index c63defd42..ebd2036c6 100644 --- a/src/plugins/sync/client/config.js +++ b/src/plugins/sync/client/config.ts @@ -1,5 +1,5 @@ export const SYNC_CODE = { - helloMsg: 'Hello~::^-^::', + helloMsg: 'Hello~::^-^::~v2~', idPrefix: 'OjppZDo6', authMsg: 'lx-music auth::', authFailed: 'Auth failed', @@ -8,4 +8,6 @@ export const SYNC_CODE = { connectServiceFailed: 'Connect service failed', connecting: 'Connecting...', unknownServiceAddress: 'Unknown service address', -} + msgBlockedIp: 'Blocked IP', + msgConnect: 'lx-music connect', +} as const diff --git a/src/plugins/sync/client/index.js b/src/plugins/sync/client/index.ts similarity index 55% rename from src/plugins/sync/client/index.js rename to src/plugins/sync/client/index.ts index 34c0f6a5b..37692de7c 100644 --- a/src/plugins/sync/client/index.js +++ b/src/plugins/sync/client/index.ts @@ -1,41 +1,37 @@ import handleAuth from './auth' import { connect as socketConnect, disconnect as socketDisconnect } from './client' -import { getSyncHost } from '@/utils/tools' -import { action as commonAction } from '@/store/modules/common' -import { getStore } from '@/store' +import { getSyncHost } from '@/utils/data' import { SYNC_CODE } from './config' import log from '../log' +import { setSyncMessage, setSyncStatus } from '@/core/sync' -const handleConnect = async authCode => { +const handleConnect = async(authCode?: string) => { const hostInfo = await getSyncHost() // console.log(hostInfo) if (!hostInfo || !hostInfo.host || !hostInfo.port) throw new Error(SYNC_CODE.unknownServiceAddress) await disconnect(false) const keyInfo = await handleAuth(hostInfo.host, hostInfo.port, authCode) - await socketConnect(hostInfo.host, hostInfo.port, keyInfo) + socketConnect(hostInfo.host, hostInfo.port, keyInfo) } const handleDisconnect = async() => { await socketDisconnect() } -const connect = authCode => { - const store = getStore() - store.dispatch(commonAction.setSyncStatus({ +const connect = async(authCode?: string) => { + setSyncStatus({ status: false, message: SYNC_CODE.connecting, - })) + }) return handleConnect(authCode).then(() => { - const store = getStore() - store.dispatch(commonAction.setSyncStatus({ + setSyncStatus({ status: true, message: '', - })) - }).catch(err => { - const store = getStore() - store.dispatch(commonAction.setSyncStatus({ + }) + }).catch(async err => { + setSyncStatus({ status: false, message: err.message, - })) + }) switch (err.message) { case SYNC_CODE.connectServiceFailed: case SYNC_CODE.missingAuthCode: @@ -49,21 +45,17 @@ const connect = authCode => { }) } -const disconnect = (isResetStatus = true) => handleDisconnect().then(() => { +const disconnect = async(isResetStatus = true) => handleDisconnect().then(() => { log.info('disconnect...') if (isResetStatus) { - const store = getStore() - store.dispatch(commonAction.setSyncStatus({ + setSyncStatus({ status: false, message: '', - })) + }) } -}).catch(err => { - const store = getStore() - log.error('disconnect error: ' + err.message) - store.dispatch(commonAction.setSyncStatus({ - message: err.message, - })) +}).catch((err: any) => { + log.error(`disconnect error: ${err.message as string}`) + setSyncMessage(err.message) }) export { diff --git a/src/plugins/sync/client/syncList.js b/src/plugins/sync/client/syncList.js deleted file mode 100644 index cdb435c94..000000000 --- a/src/plugins/sync/client/syncList.js +++ /dev/null @@ -1,85 +0,0 @@ -import { getStore } from '@/store' -// import { action as commonAction } from '@/store/modules/common' -import { action as listAction } from '@/store/modules/list' -import { toast } from '@/utils/tools' - -import { decryptMsg, encryptMsg } from './utils' -import log from '../log' - -let socket -let syncAction - -const wait = () => new Promise((resolve, reject) => { - syncAction = [resolve, reject] -}) - -const sendListData = type => { - const store = getStore() - const state = store.getState() - let listData - switch (type) { - case 'all': - listData = { - defaultList: state.list.defaultList, - loveList: state.list.loveList, - userList: state.list.userList, - } - break - - default: - break - } - // console.log('sendListData') - socket.emit('list:sync', encryptMsg(JSON.stringify({ - action: 'getData', - data: listData, - })), () => { - log.info('[syncList]send data success') - }) - // console.log('sendListData', 'encryptMsg') -} - -const saveList = ({ defaultList, loveList, userList }) => { - const store = getStore() - store.dispatch(listAction.setSyncList({ defaultList, loveList, userList })) -} - -const handleListSync = enMsg => { - // console.log('handleListSync', enMsg.length) - const { action, data } = JSON.parse(decryptMsg(enMsg)) - // console.log('handleListSync', action) - switch (action) { - case 'getData': - log.info('[syncList]get data') - sendListData(data) - break - case 'setData': - log.info('[syncList]set data') - saveList(data) - log.info('[syncList]set data success') - break - case 'finished': - if (!syncAction) return - log.info('[syncList]finished') - syncAction[0]() - syncAction = null - toast('Sync successfully') - break - default: - break - } -} - -const handleDisconnect = err => { - if (!syncAction) return - syncAction[1](err.message ? err : new Error(err)) - syncAction = null -} - -export default _socket => { - socket = _socket - socket.on('list:sync', handleListSync) - socket.on('connect_error', handleDisconnect) - socket.on('disconnect', handleDisconnect) - return wait() -} diff --git a/src/plugins/sync/client/syncList.ts b/src/plugins/sync/client/syncList.ts new file mode 100644 index 000000000..b473b1e57 --- /dev/null +++ b/src/plugins/sync/client/syncList.ts @@ -0,0 +1,97 @@ +// import { getStore } from '@/store' +// import { action as commonAction } from '@/store/modules/common' +// import { action as listAction } from '@/store/modules/list' +import { toast } from '@/utils/tools' + +import { decryptMsg, encryptMsg } from './utils' +import log from '../log' +import { LIST_IDS } from '@/config/constant' +import { getListMusics, userLists } from '@/utils/listManage' + +let socket: LX.Sync.Socket | null +let syncAction: [() => void, (err: any) => void] | null + +const wait = async(): Promise<void> => new Promise((resolve, reject) => { + syncAction = [resolve, reject] +}) + +const getListDataFull = async(): Promise<LX.Sync.ListData> => { + return Promise.all([ + getListMusics(LIST_IDS.DEFAULT), + getListMusics(LIST_IDS.LOVE), + // eslint-disable-next-line @typescript-eslint/promise-function-async + ...userLists.map(l => getListMusics(l.id)), + ]).then(([defaultList, loveList, ...userList]) => { + return { + defaultList, + loveList, + userList: userLists.map((l, i) => ({ ...l, list: userList[i] })), + } + }) +} +const sendListData = async(type: LX.Sync.SyncClientActionGetData) => { + // const state = store.getState() + + let listData + switch (type) { + case 'all': + listData = await getListDataFull() + break + + default: + break + } + // console.log('sendListData') + socket!.emit('list:sync', encryptMsg(JSON.stringify({ + action: 'getData', + data: listData, + })), () => { + log.info('[syncList]send data success') + }) + // console.log('sendListData', 'encryptMsg') +} + +const saveList = ({ defaultList, loveList, userList }: LX.Sync.ListData) => { + // const store = getStore() + void global.list_event.list_data_overwrite({ defaultList, loveList, userList }, true) +} + +const handleListSync = (enMsg: string) => { + // console.log('handleListSync', enMsg.length) + const msg = JSON.parse(decryptMsg(enMsg)) as LX.Sync.SyncClientAction + // console.log('handleListSync', action) + switch (msg.action) { + case 'getData': + log.info('[syncList]get data') + void sendListData(msg.data) + break + case 'setData': + log.info('[syncList]set data') + saveList(msg.data) + log.info('[syncList]set data success') + break + case 'finished': + if (!syncAction) return + log.info('[syncList]finished') + syncAction[0]() + syncAction = null + toast('Sync successfully') + break + default: + break + } +} + +const handleDisconnect = (err: any) => { + if (!syncAction) return + syncAction[1](err.message ? err : new Error(err)) + syncAction = null +} + +export default async(_socket: LX.Sync.Socket) => { + socket = _socket + socket.on('list:sync', handleListSync) + socket.on('connect_error', handleDisconnect) + socket.on('disconnect', handleDisconnect) + return wait() +} diff --git a/src/plugins/sync/client/utils.js b/src/plugins/sync/client/utils.js deleted file mode 100644 index 118f0dd96..000000000 --- a/src/plugins/sync/client/utils.js +++ /dev/null @@ -1,47 +0,0 @@ -import { createCipheriv, createDecipheriv } from 'crypto' -import BackgroundTimer from 'react-native-background-timer' - -export const request = (url, { timeout = 10000, ...options } = {}) => { - const controller = new global.AbortController() - const id = BackgroundTimer.setTimeout(() => controller.abort(), timeout) - return global.fetch(url, { - ...options, - signal: controller.signal, - }).then(response => { - BackgroundTimer.clearTimeout(id) - return response.text() - }).catch(err => { - // console.log(err, err.code, err.message) - return Promise.reject(err) - }) -} - -export const aesEncrypt = (text, key, iv) => { - const cipher = createCipheriv('aes-128-cbc', Buffer.from(key, 'base64'), Buffer.from(iv, 'base64')) - return Buffer.concat([cipher.update(Buffer.from(text)), cipher.final()]).toString('base64') -} - -export const aesDecrypt = (text, key, iv) => { - const decipher = createDecipheriv('aes-128-cbc', Buffer.from(key, 'base64'), Buffer.from(iv, 'base64')) - return Buffer.concat([decipher.update(Buffer.from(text, 'base64')), decipher.final()]).toString() -} - -export const encryptMsg = msg => { - return msg - // const keyInfo = global.syncKeyInfo - // if (!keyInfo) return '' - // return aesEncrypt(msg, keyInfo.key, keyInfo.iv) -} - -export const decryptMsg = enMsg => { - return enMsg - // const keyInfo = global.syncKeyInfo - // if (!keyInfo) return '' - // let msg = '' - // try { - // msg = aesDecrypt(enMsg, keyInfo.key, keyInfo.iv) - // } catch (err) { - // console.log(err) - // } - // return msg -} diff --git a/src/plugins/sync/client/utils.ts b/src/plugins/sync/client/utils.ts new file mode 100644 index 000000000..e1e42e35b --- /dev/null +++ b/src/plugins/sync/client/utils.ts @@ -0,0 +1,102 @@ +import { createCipheriv, createDecipheriv, generateKeyPair, publicEncrypt, privateDecrypt, constants } from 'crypto' +import BackgroundTimer from 'react-native-background-timer' + +export const request = async(url: string, { timeout = 10000, ...options }: RequestInit & { timeout?: number } = {}) => { + const controller = new AbortController() + let id: number | null = BackgroundTimer.setTimeout(() => { + id = null + controller.abort() + }, timeout) + return fetch(url, { + ...options, + signal: controller.signal, + // eslint-disable-next-line @typescript-eslint/promise-function-async + }).then(async(response) => { + const text = await response.text() + return { + text, + code: response.status, + } + }).catch(err => { + // console.log(err, err.code, err.message) + throw err + }).finally(() => { + if (id == null) return + BackgroundTimer.clearTimeout(id) + }) +} + +// export const aesEncrypt = (text: string, key: string, iv: string) => { +// const cipher = createCipheriv('aes-128-cbc', Buffer.from(key, 'base64'), Buffer.from(iv, 'base64')) +// return Buffer.concat([cipher.update(Buffer.from(text)), cipher.final()]).toString('base64') +// } + +// export const aesDecrypt = (text: string, key: string, iv: string) => { +// const decipher = createDecipheriv('aes-128-cbc', Buffer.from(key, 'base64'), Buffer.from(iv, 'base64')) +// return Buffer.concat([decipher.update(Buffer.from(text, 'base64')), decipher.final()]).toString() +// } + +export const aesEncrypt = (text: string, key: string) => { + const cipher = createCipheriv('aes-128-ecb', Buffer.from(key, 'base64'), '') + return Buffer.concat([cipher.update(Buffer.from(text)), cipher.final()]).toString('base64') +} + +export const aesDecrypt = (text: string, key: string) => { + const decipher = createDecipheriv('aes-128-ecb', Buffer.from(key, 'base64'), '') + return Buffer.concat([decipher.update(Buffer.from(text, 'base64')), decipher.final()]).toString() +} + +export const generateRsaKey = async() => new Promise<{ publicKey: string, privateKey: string }>((resolve, reject) => { + generateKeyPair( + 'rsa', + { + modulusLength: 2048, // It holds a number. It is the key size in bits and is applicable for RSA, and DSA algorithm only. + publicKeyEncoding: { + type: 'spki', // Note the type is pkcs1 not spki + format: 'pem', + }, + privateKeyEncoding: { + type: 'pkcs8', // Note again the type is set to pkcs1 + format: 'pem', + // cipher: "aes-256-cbc", //Optional + // passphrase: "", //Optional + }, + }, + (err, publicKey, privateKey) => { + if (err) return reject(err) + resolve({ + publicKey, + privateKey, + }) + }, + ) +}) + +export const rsaEncrypt = (buffer: Buffer, key: string): string => { + return publicEncrypt({ key, padding: constants.RSA_PKCS1_OAEP_PADDING }, buffer).toString('base64') +} +export const rsaDecrypt = (buffer: Buffer, key: string): Buffer => { + return privateDecrypt({ key, padding: constants.RSA_PKCS1_OAEP_PADDING }, buffer) +} + + +export const encryptMsg = (msg: string) => { + return msg + // return `${createHash('md5').update(msg).digest('hex')}${msg}` + // const keyInfo = global.lx.syncKeyInfo + // if (!keyInfo) return '' + // return aesEncrypt(msg, keyInfo.key) +} + +export const decryptMsg = (enMsg: string) => { + return enMsg + // const keyInfo = global.lx.syncKeyInfo + // if (!keyInfo) return '' + // let msg = '' + // try { + // msg = aesDecrypt(enMsg, keyInfo.key, keyInfo.iv) + // } catch (err) { + // console.log(err) + // } + // return msg +} diff --git a/src/plugins/sync/modules/index.js b/src/plugins/sync/modules/index.ts similarity index 100% rename from src/plugins/sync/modules/index.js rename to src/plugins/sync/modules/index.ts diff --git a/src/plugins/sync/modules/list/index.js b/src/plugins/sync/modules/list/index.ts similarity index 83% rename from src/plugins/sync/modules/list/index.js rename to src/plugins/sync/modules/list/index.ts index 6a73b8a4d..0e2bf5daf 100644 --- a/src/plugins/sync/modules/list/index.js +++ b/src/plugins/sync/modules/list/index.ts @@ -4,7 +4,7 @@ import { unregister as unregisterSend, } from './send' -export const registerListHandler = _socket => { +export const registerListHandler = (_socket: LX.Sync.Socket) => { unregisterListHandler() registerOn(_socket) registerSend(_socket) diff --git a/src/plugins/sync/modules/list/on.js b/src/plugins/sync/modules/list/on.js deleted file mode 100644 index 45969f828..000000000 --- a/src/plugins/sync/modules/list/on.js +++ /dev/null @@ -1,99 +0,0 @@ -import { getStore } from '@/store' -import { decryptMsg } from '../../client/utils' -import log from '../../log' -import { - setList, - listAdd, - listMove, - listAddMultiple, - listMoveMultiple, - listRemove, - listRemoveMultiple, - listClear, - updateMusicInfo, - createUserList, - removeUserList, - setUserListName, - setMusicPosition, - setUserListPosition, -} from '@/store/modules/list/action' - -const store = getStore() - -let socket - -const handleListAction = enMsg => { - const { action, data } = JSON.parse(decryptMsg(enMsg)) - if (typeof data == 'object') data.isSync = true - console.log(action) - log.info(action) - - switch (action) { - // case 'init_list': - // store.dispatch(initList(data)) - // break - case 'set_list': - store.dispatch(setList(data)) - break - case 'list_add': - store.dispatch(listAdd(data)) - break - case 'list_move': - store.dispatch(listMove(data)) - break - case 'list_add_multiple': - store.dispatch(listAddMultiple(data)) - break - case 'list_move_multiple': - store.dispatch(listMoveMultiple(data)) - break - case 'list_remove': - store.dispatch(listRemove(data)) - break - case 'list_remove_multiple': - store.dispatch(listRemoveMultiple(data)) - break - case 'list_clear': - store.dispatch(listClear(data)) - break - case 'update_music_info': - store.dispatch(updateMusicInfo(data)) - break - case 'create_user_list': - store.dispatch(createUserList(data)) - break - case 'remove_user_list': - store.dispatch(removeUserList(data)) - break - case 'set_user_list_name': - store.dispatch(setUserListName(data)) - break - case 'set_user_list_position': - store.dispatch(setUserListPosition(data)) - break - case 'set_music_position': - store.dispatch(setMusicPosition(data)) - break - // case 'moveup_user_list': - // store.dispatch(moveupUserList(data)) - // break - // case 'movedown_user_list': - // store.dispatch(movedownUserList(data)) - // break - default: - break - } -} - -export const register = _socket => { - unregister() - socket = _socket - socket.on('list:action', handleListAction) - // socket.on('list:add', addMusic) -} - -export const unregister = () => { - if (!socket) return - socket.off('list:action', handleListAction) - socket = null -} diff --git a/src/plugins/sync/modules/list/on.ts b/src/plugins/sync/modules/list/on.ts new file mode 100644 index 000000000..4faebaea1 --- /dev/null +++ b/src/plugins/sync/modules/list/on.ts @@ -0,0 +1,64 @@ +import { decryptMsg } from '../../client/utils' +import log from '../../log' + + +let socket: LX.Sync.Socket | null +const handleRemoteListAction = (enMsg: string) => { + const { action, data } = JSON.parse(decryptMsg(enMsg)) as LX.Sync.ActionList + // console.log('handleRemoteListAction', action) + log.info(action) + + switch (action) { + case 'list_data_overwrite': + void global.list_event.list_data_overwrite(data, true) + break + case 'list_create': + void global.list_event.list_create(data.position, data.listInfos, true) + break + case 'list_remove': + void global.list_event.list_remove(data, true) + break + case 'list_update': + void global.list_event.list_update(data, true) + break + case 'list_update_position': + void global.list_event.list_update_position(data.position, data.ids, true) + break + case 'list_music_add': + void global.list_event.list_music_add(data.id, data.musicInfos, data.addMusicLocationType, true) + break + case 'list_music_move': + void global.list_event.list_music_move(data.fromId, data.toId, data.musicInfos, data.addMusicLocationType, true) + break + case 'list_music_remove': + void global.list_event.list_music_remove(data.listId, data.ids, true) + break + case 'list_music_update': + void global.list_event.list_music_update(data, true) + break + case 'list_music_update_position': + void global.list_event.list_music_update_position(data.listId, data.position, data.ids, true) + break + case 'list_music_overwrite': + void global.list_event.list_music_overwrite(data.listId, data.musicInfos, true) + break + case 'list_music_clear': + void global.list_event.list_music_clear(data, true) + break + default: + break + } +} + +export const register = (_socket: LX.Sync.Socket) => { + unregister() + socket = _socket + socket.on('list:action', handleRemoteListAction) + // socket.on('list:add', addMusic) +} + +export const unregister = () => { + if (!socket) return + socket.off('list:action', handleRemoteListAction) + socket = null +} diff --git a/src/plugins/sync/modules/list/send.js b/src/plugins/sync/modules/list/send.js deleted file mode 100644 index 36ac733dd..000000000 --- a/src/plugins/sync/modules/list/send.js +++ /dev/null @@ -1,16 +0,0 @@ -import { encryptMsg } from '../../client/utils' - -let socket - -export const sendListAction = (action, data) => { - if (!socket) return - socket.emit('list:action', encryptMsg(JSON.stringify({ action, data }))) -} - -export const register = _socket => { - socket = _socket -} - -export const unregister = () => { - socket = null -} diff --git a/src/plugins/sync/modules/list/send.ts b/src/plugins/sync/modules/list/send.ts new file mode 100644 index 000000000..e60580d06 --- /dev/null +++ b/src/plugins/sync/modules/list/send.ts @@ -0,0 +1,102 @@ +import { encryptMsg } from '../../client/utils' + +let socket: LX.Sync.Socket | null +let unregisterLocalListAction: (() => void) | null + +const handleLocalListAction = () => { + const list_data_overwrite = async(listData: MakeOptional<LX.List.ListDataFull, 'tempList'>, isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_data_overwrite', data: listData }) + } + const list_create = async(position: number, listInfos: LX.List.UserListInfo[], isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_create', data: { position, listInfos } }) + } + const list_remove = async(ids: string[], isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_remove', data: ids }) + } + const list_update = async(lists: LX.List.UserListInfo[], isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_update', data: lists }) + } + const list_update_position = async(position: number, ids: string[], isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_update_position', data: { position, ids } }) + } + const list_music_overwrite = async(listId: string, musicInfos: LX.Music.MusicInfo[], isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_music_overwrite', data: { listId, musicInfos } }) + } + const list_music_add = async(id: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_music_add', data: { id, musicInfos, addMusicLocationType } }) + } + const list_music_move = async(fromId: string, toId: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_music_move', data: { fromId, toId, musicInfos, addMusicLocationType } }) + } + const list_music_remove = async(listId: string, ids: string[], isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_music_remove', data: { listId, ids } }) + } + const list_music_update = async(musicInfos: LX.List.ListActionMusicUpdate, isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_music_update', data: musicInfos }) + } + const list_music_clear = async(ids: string[], isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_music_clear', data: ids }) + } + const list_music_update_position = async(listId: string, position: number, ids: string[], isRemote: boolean = false) => { + if (isRemote) return + sendListAction({ action: 'list_music_update_position', data: { listId, position, ids } }) + } + global.list_event.on('list_data_overwrite', list_data_overwrite) + global.list_event.on('list_create', list_create) + global.list_event.on('list_remove', list_remove) + global.list_event.on('list_update', list_update) + global.list_event.on('list_update_position', list_update_position) + global.list_event.on('list_music_overwrite', list_music_overwrite) + global.list_event.on('list_music_add', list_music_add) + global.list_event.on('list_music_move', list_music_move) + global.list_event.on('list_music_remove', list_music_remove) + global.list_event.on('list_music_update', list_music_update) + global.list_event.on('list_music_clear', list_music_clear) + global.list_event.on('list_music_update_position', list_music_update_position) + return () => { + global.list_event.off('list_data_overwrite', list_data_overwrite) + global.list_event.off('list_create', list_create) + global.list_event.off('list_remove', list_remove) + global.list_event.off('list_update', list_update) + global.list_event.off('list_update_position', list_update_position) + global.list_event.off('list_music_overwrite', list_music_overwrite) + global.list_event.off('list_music_add', list_music_add) + global.list_event.off('list_music_move', list_music_move) + global.list_event.off('list_music_remove', list_music_remove) + global.list_event.off('list_music_update', list_music_update) + global.list_event.off('list_music_clear', list_music_clear) + global.list_event.off('list_music_update_position', list_music_update_position) + } +} + + +export const sendListAction = (action: LX.Sync.ActionList) => { + // console.log('sendListAction', action.action) + if (!socket) return + socket.emit('list:action', encryptMsg(JSON.stringify(action))) +} + +export const register = (_socket: LX.Sync.Socket) => { + unregister() + socket = _socket + unregisterLocalListAction = handleLocalListAction() +} + +export const unregister = () => { + socket = null + if (unregisterLocalListAction) { + unregisterLocalListAction() + unregisterLocalListAction = null + } +} diff --git a/src/resources/fonts/icomoon.ttf b/src/resources/fonts/icomoon.ttf index 96df7084d..ad3ecd824 100644 Binary files a/src/resources/fonts/icomoon.ttf and b/src/resources/fonts/icomoon.ttf differ diff --git a/src/resources/fonts/selection.json b/src/resources/fonts/selection.json index bea56e710..44d322779 100644 --- a/src/resources/fonts/selection.json +++ b/src/resources/fonts/selection.json @@ -1 +1 @@ -{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M666.587 719.627l-207.627-207.627 207.627-208.080-63.92-63.92-272 272 272 272 63.92-64.373z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-chevron-left"]},"attrs":[{}],"properties":{"order":845,"id":23,"name":"chevron-left","prevSize":32,"code":59669},"setIdx":0,"setId":3,"iconIdx":0},{"icon":{"paths":["M366.507 707.413l195.413-195.413-195.413-195.84 60.16-60.16 256 256-256 256-60.16-60.587z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-chevron-right"]},"attrs":[{}],"properties":{"order":853,"id":31,"name":"chevron-right","prevSize":32,"code":59671},"setIdx":0,"setId":3,"iconIdx":1},{"icon":{"paths":["M842.667 247.937l-66.604-66.604-264.063 264.063-264.063-264.063-66.604 66.604 264.063 264.063-264.063 264.063 66.604 66.604 264.063-264.063 264.063 264.063 66.604-66.604-264.063-264.063 264.063-264.063z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-remove"]},"attrs":[{}],"properties":{"order":828,"id":17,"prevSize":32,"code":59663,"name":"remove"},"setIdx":0,"setId":3,"iconIdx":2},{"icon":{"paths":["M85.333 170.667v128h213.333v512h128v-512h213.333v-128h-554.667zM896 384h-384v128h128v298.667h128v-298.667h128v-128z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-font-size"]},"attrs":[{}],"properties":{"order":852,"id":30,"name":"font-size","prevSize":32,"code":59676},"setIdx":0,"setId":3,"iconIdx":3},{"icon":{"paths":["M932.54 573.38c17.54-29.7 27.46-61.38 27.46-99.68 0-88.030-74.436-171.16-171.64-171.16h-72.96c9.84-25.62 17.7-56.26 17.7-93.080 0-145.588-75.38-209.46-190.54-209.46-123.214 0-116.186 189.866-143.52 217.2-45.494 45.494-99.23 132.894-137.52 166.8h-197.52c-35.346 0-64 28.654-64 64v480c0 35.346 28.654 64 64 64h128c29.786 0 54.816-20.348 61.956-47.9 89.018 2.002 150.12 79.88 355.604 79.88 14.44 0 30.44 0.020 44.44 0.020 154.234 0 223.972-78.846 225.88-190.66 26.638-36.85 40.598-86.244 34.68-133.98 19.708-36.904 27.328-80.686 17.98-125.98zM809.040 681.040c25.12 42.26 2.52 98.82-27.88 115.14 15.4 97.56-35.216 131.8-106.24 131.8h-75.64c-143.278 0-236.058-75.64-343.28-75.64v-372.34h21.84c56.72 0 135.96-141.78 189.080-194.92 56.72-56.72 37.82-151.26 75.64-189.080 94.54 0 94.54 65.96 94.54 113.46 0 78.34-56.72 113.44-56.72 189.080h207.98c42.22 0 75.46 37.82 75.64 75.64 0.18 37.8-25.64 75.62-44.54 75.62 26.978 29.11 32.742 90.472-10.42 131.24zM176 864c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-thumbs-up"]},"attrs":[{}],"properties":{"order":851,"id":29,"name":"thumbs-up","prevSize":32,"code":59675},"setIdx":0,"setId":3,"iconIdx":4},{"icon":{"paths":["M666.667 473.333h-309.333v-77.333h309.333v77.333zM898.667 202.667v464c0 42.92-34.413 77.333-77.333 77.333h-235.867l-143.067 143.453c-7.733 7.347-17.4 11.213-27.067 11.213h-19.333c-21.267 0-38.667-17.4-38.667-38.667v-116h-154.667c-42.533 0-77.333-34.413-77.333-77.333v-464c0-42.92 34.8-77.333 77.333-77.333h618.667c42.92 0 77.333 34.8 77.333 77.333zM821.333 202.667h-618.667v464h232v119.093l119.093-119.093h267.573v-464z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-comment"]},"attrs":[{}],"properties":{"order":850,"id":28,"name":"comment","prevSize":32,"code":59674},"setIdx":0,"setId":3,"iconIdx":5},{"icon":{"paths":["M342.759 158.32l-52.579-62.85-188.959 158.149 52.99 62.85 188.548-158.149zM922.779 254.031l-188.959-158.559-52.99 62.85 188.959 158.559 52.99-62.85zM512 183.378c-204.179 0-369.7 165.521-369.7 369.7v0c0 204.179 165.521 369.7 369.7 369.7v0c204.179 0 369.7-165.521 369.7-369.7v0c0-204.179-165.521-369.7-369.7-369.7v0zM512 840.622c-158.807 0-287.545-128.738-287.545-287.545v0c0-158.807 128.738-287.545 287.545-287.545v0c158.807 0 287.545 128.738 287.545 287.545v0c0 158.807-128.738 287.545-287.545 287.545v0zM388.766 470.921h149.112l-149.112 172.526v73.94h246.466v-82.155h-149.112l149.112-172.526v-73.94h-246.466v82.155z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-alarm-snooze"]},"attrs":[{}],"properties":{"order":849,"id":27,"name":"alarm-snooze","prevSize":32,"code":59673},"setIdx":0,"setId":3,"iconIdx":6},{"icon":{"paths":["M85.333 682.667h341.333v-85.333h-341.333zM768 597.333v-170.667h-85.333v170.667h-170.667v85.333h170.667v170.667h85.333v-170.667h170.667v-85.333zM597.333 256h-512v85.333h512zM597.333 426.667h-512v85.333h512v-85.333z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-playlist-plus"]},"attrs":[{}],"properties":{"order":847,"id":26,"name":"playlist-plus","prevSize":32,"code":59672},"setIdx":0,"setId":3,"iconIdx":7},{"icon":{"paths":["M512 340s-124.938-153.616-282-48c-140.476 153.648-60.182 358.16 282 538 42.678-16.722 88-34 88-34 38-12.784 56.31 41.484 32 52-55.178 23.87 11.948-8.282-120 56-583.048-276.3-424.014-605.938-322-670 173.6-131.78 324 20 324 20s116.316-121.046 280-46c208.064 117.056 128 323.8 90 392-18.304 30.308-79.118-8.318-64-32 40.68-75.776 91.044-214.698-50-300-140.162-60.16-258 72-258 72z","M766 736c-16.2 0.020-49.54-0.31-80 0-31.426 0.32-30.564 69.928 0 70 30.2 0.070 80 0 80 0s-0.136 85.6 0 96c0.416 31.922 64.522 31.582 64-2-0.144-9.298 0-94 0-94s76.016-0.062 86 0c31.464 0.092 29.894-67.96-2-68-9.768 0.186-84 0-84 0s-0.106-56.682 0-92c0.092-30.378-64.056-31.024-64 0 0.054 29.48-0.436 84.278 0 90z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-add-music"]},"attrs":[{},{}],"properties":{"order":843,"id":25,"name":"add-music","prevSize":32,"code":59670},"setIdx":0,"setId":3,"iconIdx":8},{"icon":{"paths":["M512 682.667c47.128 0 85.333 38.205 85.333 85.333v0c0 47.128-38.205 85.333-85.333 85.333v0c-47.128 0-85.333-38.205-85.333-85.333v0c0-47.128 38.205-85.333 85.333-85.333v0zM512 426.667c47.128 0 85.333 38.205 85.333 85.333v0c0 47.128-38.205 85.333-85.333 85.333v0c-47.128 0-85.333-38.205-85.333-85.333v0c0-47.128 38.205-85.333 85.333-85.333v0zM512 170.667c47.128 0 85.333 38.205 85.333 85.333v0c0 47.128-38.205 85.333-85.333 85.333v0c-47.128 0-85.333-38.205-85.333-85.333v0c0-47.128 38.205-85.333 85.333-85.333v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-dots-vertical"]},"attrs":[{}],"properties":{"order":833,"id":21,"name":"dots-vertical","prevSize":32,"code":59667},"setIdx":0,"setId":3,"iconIdx":9},{"icon":{"paths":["M256 512h128l-170.667-170.667-170.667 170.667h128c0 188.513 152.82 341.333 341.333 341.333v0c66.987 0 129.28-19.627 181.76-52.907l-62.293-62.293c-35.413 19.2-76.8 29.867-119.467 29.867-141.385 0-256-114.615-256-256v0zM330.24 223.573l62.293 62.293c35.84-18.773 76.8-29.867 119.467-29.867 141.385 0 256 114.615 256 256v0h-128l170.667 170.667 170.667-170.667-128 0c0-188.513-152.82-341.333-341.333-341.333v0c-66.987 0-129.28 19.627-181.76 52.907z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-autorenew"]},"attrs":[{}],"properties":{"order":832,"id":20,"name":"autorenew","prevSize":32,"code":59665},"setIdx":0,"setId":3,"iconIdx":10},{"icon":{"paths":["M426.667 170.667l85.333 85.333h341.333c47.128 0 85.333 38.205 85.333 85.333v0 426.667c0 47.128-38.205 85.333-85.333 85.333v0h-682.667c-47.36 0-85.333-38.4-85.333-85.333v-512c0-47.36 37.973-85.333 85.333-85.333h256zM640 384v128h-128v85.333h128v128h85.333v-128h128v-85.333h-128v-128h-85.333z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-folder-plus"]},"attrs":[{}],"properties":{"order":831,"id":19,"name":"folder-plus","prevSize":32,"code":59666},"setIdx":0,"setId":3,"iconIdx":11},{"icon":{"paths":["M570.952 545.942l-388.688 388.686c-18.746 18.746-49.138 18.746-67.882 0l-45.334-45.334c-18.714-18.714-18.75-49.044-0.080-67.802l308.042-309.492-308.042-309.49c-18.67-18.758-18.634-49.088 0.080-67.802l45.334-45.334c18.746-18.746 49.138-18.746 67.882 0l388.686 388.686c18.746 18.744 18.746 49.136 0.002 67.882z"],"attrs":[{}],"width":640,"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-chevron-right"]},"attrs":[{}],"properties":{"order":854,"id":18,"name":"chevron-right-2","prevSize":32,"code":59664},"setIdx":0,"setId":3,"iconIdx":12},{"icon":{"paths":["M633.703 512l365.094-365.094c33.607-33.607 33.607-88.095 0-121.698-33.607-33.607-88.091-33.607-121.698 0l-365.099 365.099-365.099-365.104c-33.607-33.607-88.091-33.607-121.698 0-33.603 33.607-33.603 88.095 0 121.698l365.099 365.094-365.099 365.099c-33.603 33.607-33.603 88.095 0 121.698 33.607 33.607 88.091 33.607 121.698 0l365.099-365.099 365.099 365.099c33.603 33.607 88.091 33.607 121.698 0s33.607-88.091 0-121.698l-365.094-365.094z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-close"]},"attrs":[{}],"properties":{"order":826,"id":15,"name":"close","prevSize":32,"code":59662},"setIdx":0,"setId":3,"iconIdx":13},{"icon":{"paths":["M298.667 298.667h426.667v128l170.667-170.667-170.667-170.667v128h-512v256h85.333v-170.667zM725.333 725.333h-426.667v-128l-170.667 170.667 170.667 170.667v-128h512v-256h-85.333v170.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-list-loop"],"defaultCode":59648},"attrs":[{}],"properties":{"order":809,"id":2,"name":"list-loop","prevSize":32,"code":59648},"setIdx":0,"setId":3,"iconIdx":14},{"icon":{"paths":["M856 213.862v567.6h-120.4v-303.862c0-45.862 0-68.8 0-80.262s-5.738-17.2-17.2-22.938c-5.738-5.738-28.662-5.738-57.338-5.738h-11.462v-63.062c57.338-17.2 103.2-45.862 131.862-91.738h74.538z","M168 856l487.338-344-487.338-344z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-single"],"defaultCode":59649},"attrs":[{},{}],"properties":{"order":810,"id":3,"name":"single","prevSize":32,"code":59649},"setIdx":0,"setId":3,"iconIdx":15},{"icon":{"paths":["M298.667 298.667h426.667v128l170.667-170.667-170.667-170.667v128h-512v256h85.333v-170.667zM725.333 725.333h-426.667v-128l-170.667 170.667 170.667 170.667v-128h512v-256h-85.333v170.667zM554.667 640v-256h-42.667l-85.333 42.667v42.667h64v170.667h64z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-single-loop"],"defaultCode":59650},"attrs":[{}],"properties":{"order":811,"id":4,"name":"single-loop","prevSize":32,"code":59650},"setIdx":0,"setId":3,"iconIdx":16},{"icon":{"paths":["M167.065 412.951h594.284v99.049h-594.284zM167.065 214.858h594.284v99.049h-594.284zM167.065 611.049h396.191v99.049h-396.191zM662.301 611.049v297.142l247.617-148.574z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-list-order"],"defaultCode":59651},"attrs":[{}],"properties":{"order":812,"id":5,"name":"list-order","prevSize":32,"code":59651},"setIdx":0,"setId":3,"iconIdx":17},{"icon":{"paths":["M451.84 391.253l-221.013-220.587-60.16 60.16 220.587 220.587 60.587-60.16zM618.667 170.667l87.040 87.040-535.040 535.467 60.16 60.16 535.467-535.040 87.040 87.040v-234.667h-234.667zM632.747 572.16l-60.16 60.16 133.547 133.547-87.467 87.467h234.667v-234.667l-87.040 87.040-133.547-133.547z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-list-random"],"defaultCode":59652},"attrs":[{}],"properties":{"order":813,"id":6,"name":"list-random","prevSize":32,"code":59652},"setIdx":0,"setId":3,"iconIdx":18},{"icon":{"paths":["M52.504 168.606v686.806c0 93.13 61.701 168.588 137.82 168.588 76.127 0 137.865-75.462 137.865-168.588v-686.806c0-93.085-61.738-168.577-137.865-168.577-76.119-0.030-137.82 75.492-137.82 168.577z","M833.635 0c-76.112 0-137.813 75.492-137.813 168.577v686.806c0 93.13 61.701 168.558 137.813 168.558s137.861-75.433 137.861-168.558v-686.776c-0.033-93.085-61.749-168.606-137.861-168.606z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-pause"]},"attrs":[{},{}],"properties":{"order":808,"id":1,"name":"pause","prevSize":32,"code":59661},"setIdx":0,"setId":3,"iconIdx":19},{"icon":{"paths":["M209.962 21.763c-88.986-51.043-161.129-9.228-161.129 93.323v756.778c0 102.653 72.144 144.414 161.129 93.419l661.462-379.344c89.016-51.061 89.016-133.789 0-184.838l-661.462-379.338z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-play"],"defaultCode":59653},"attrs":[{}],"properties":{"order":814,"id":7,"name":"play","prevSize":32,"code":59653},"setIdx":0,"setId":3,"iconIdx":20},{"icon":{"paths":["M96.902 152.172c-53.489 0-96.898 64.037-96.898 143.005v433.651c0 78.944 43.432 143 96.898 143 53.545 0 96.902-64.056 96.902-143v-119.627l352.203 201.97c67.023 38.471 121.477 8.351 123.795-67l-225.149-129.123c-44.415-25.451-69.917-63.036-69.917-103.083 0-40.084 25.502-77.637 69.917-103.134l225.149-129.072c-2.318-75.295-56.772-105.452-123.795-66.986l-352.203 201.919v-119.515c0.023-78.995-43.358-143.005-96.902-143.005z","M502.256 583.092l397.712 228.079c68.475 39.291 124.032 7.103 124.032-71.883v-454.684c0-78.94-55.557-111.137-124.032-71.832l-397.74 228.019c-68.452 39.301-68.452 103.009 0.028 142.3z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-prevMusic"],"defaultCode":59654},"attrs":[{},{}],"properties":{"order":838,"id":22,"prevSize":32,"code":59668,"name":"prevMusic"},"setIdx":0,"setId":3,"iconIdx":21},{"icon":{"paths":["M927.098 871.828c53.489 0 96.898-64.037 96.898-143.005v-433.651c0-78.944-43.432-143-96.898-143-53.545 0-96.902 64.056-96.902 143v119.627l-352.203-201.97c-67.023-38.471-121.477-8.351-123.795 67l225.149 129.123c44.415 25.451 69.917 63.036 69.917 103.083 0 40.084-25.502 77.637-69.917 103.134l-225.149 129.072c2.318 75.295 56.772 105.452 123.795 66.986l352.203-201.919v119.515c-0.023 78.995 43.358 143.005 96.902 143.005z","M521.744 440.908l-397.712-228.079c-68.475-39.291-124.032-7.103-124.032 71.883v454.684c0 78.94 55.557 111.137 124.032 71.832l397.74-228.019c68.452-39.301 68.452-103.009-0.028-142.3z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-nextMusic"],"defaultCode":59654},"attrs":[{},{}],"properties":{"order":836,"id":8,"name":"nextMusic","prevSize":32,"code":59654},"setIdx":0,"setId":3,"iconIdx":22},{"icon":{"paths":["M583.263 738.762c-122.639 0-222.058-99.419-222.058-222.058s99.419-222.058 222.058-222.058c122.639 0 222.058 99.419 222.058 222.058v-0c-0.147 122.58-99.478 221.911-222.044 222.058l-0.014 0zM583.263 387.95c-71.109 0-128.754 57.645-128.754 128.754s57.645 128.754 128.754 128.754c71.109 0 128.754-57.645 128.754-128.754v0c-0.080-71.076-57.677-128.674-128.746-128.754l-0.008-0z","M1155.053 473.653l-248.686-430.602c-15.186-25.863-42.83-42.97-74.477-43.051l-0.012-0h-497.208c-31.693 0.050-59.378 17.165-74.362 42.646l-0.22 0.405-248.592 430.602c-7.228 12.356-11.496 27.205-11.496 43.051s4.268 30.695 11.717 43.461l-0.221-0.41 248.686 430.602c15.201 25.879 42.875 42.992 74.55 43.051l0.009 0h497.137c31.685-0.054 59.362-17.168 74.339-42.646l0.22-0.405 248.686-430.602c7.206-12.341 11.461-27.168 11.461-42.99 0-15.871-4.281-30.742-11.752-43.521l0.221 0.409zM344.242 930.696l-239.020-413.992 239.020-414.015h478.064l239.020 414.015-239.020 413.992z"],"attrs":[{},{}],"width":1157,"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-setting"],"defaultCode":59655},"attrs":[{},{}],"properties":{"order":816,"id":9,"name":"setting","prevSize":32,"code":59655},"setIdx":0,"setId":3,"iconIdx":23},{"icon":{"paths":["M974.751 1024h-925.525c-27.228-0.19-49.226-22.307-49.226-49.561 0-0.119 0-0.238 0.001-0.357l-0 0.018v-414.489c-0.001-0.1-0.001-0.219-0.001-0.338 0-27.254 21.999-49.371 49.208-49.561l0.018-0c27.228 0.19 49.226 22.307 49.226 49.561 0 0.119-0 0.238-0.001 0.357l0-0.018v364.613h827.075v-365.504c0-27.193 22.044-49.237 49.237-49.237s49.237 22.044 49.237 49.237v0 415.38c0 0.007 0 0.016 0 0.025 0 13.741-5.516 26.193-14.456 35.262l0.006-0.006c-8.86 9.010-21.175 14.599-34.796 14.618l-0.004 0z","M512 582.803c-25.964-0.191-46.938-21.283-46.938-47.273 0-0.102 0-0.204 0.001-0.306l-0 0.016v-487.676c0-25.936 21.025-46.961 46.961-46.961s46.961 21.025 46.961 46.961v0 487.58c0.001 0.115 0.002 0.25 0.002 0.386 0 26.008-21.002 47.111-46.972 47.274l-0.016 0z","M512 658.929c-0.024 0-0.052 0-0.080 0-13.966 0-26.633-5.558-35.912-14.582l0.012 0.012-193.361-186.497c-8.999-8.738-14.582-20.95-14.582-34.466 0-12.694 4.925-24.238 12.969-32.824l-0.025 0.027c8.515-9.098 20.596-14.768 34.002-14.768 12.587 0 24.006 4.998 32.382 13.118l164.57 158.742 164.582-158.754c8.364-8.108 19.783-13.106 32.37-13.106 13.406 0 25.487 5.67 33.978 14.742l0.024 0.026c8.019 8.56 12.945 20.104 12.945 32.798 0 13.516-5.584 25.728-14.571 34.454l-0.012 0.011-193.385 186.521c-9.268 8.998-21.928 14.546-35.885 14.546-0.008 0-0.016-0-0.024-0l0.001 0zM540.755 575.41v0z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-download-2"],"defaultCode":59656},"attrs":[{},{},{}],"properties":{"order":817,"id":10,"name":"download-2","prevSize":32,"code":59656},"setIdx":0,"setId":3,"iconIdx":24},{"icon":{"paths":["M582.103 1024c-0.017 0-0.037 0-0.057 0-9.91 0-19.136-2.929-26.859-7.969l0.189 0.116-0.366-0.236c-37.015-20.471-322.346-182.272-474.148-387.423-50.493-68.213-80.822-154.009-80.822-246.889 0-19.705 1.365-39.091 4.006-58.069l-0.25 2.192c14.345-104.709 67.040-196.329 148.372-258.055 92.563-70.286 201.617-86.228 315.357-45.862 43.793 16.084 81.686 36.311 116.214 60.949l-1.48-1.003c33.049-23.635 70.942-43.862 111.376-58.855l3.359-1.091c113.792-40.339 222.847-24.423 315.383 45.862 81.333 61.831 134.027 153.477 148.372 258.055 2.401 16.819 3.771 36.243 3.771 55.988 0 92.855-30.315 178.629-81.587 247.965l0.802-1.136c-152.718 206.198-440.432 368.811-474.802 387.658-7.598 4.896-16.87 7.819-26.822 7.853l-0.009 0zM347.581 105.677c-43.428 0-89.997 12.46-135.598 47.119-59.056 44.894-97.353 111.593-107.798 187.821-1.757 12.365-2.76 26.647-2.76 41.162 0 68.642 22.432 132.045 60.365 183.279l-0.591-0.835c123.426 166.67 348.157 304.781 421.087 347.031 73.008-42.171 297.661-180.361 421.087-347.031 37.343-50.395 59.775-113.796 59.775-182.436 0-14.518-1.004-28.802-2.945-42.786l0.184 1.616c-10.471-76.202-48.742-142.901-107.824-187.821-159.131-120.939-330.121 28.271-337.398 34.685-8.691 7.859-20.269 12.668-32.97 12.668s-24.279-4.809-33.013-12.706l0.043 0.038c-5.052-4.555-93.557-81.804-201.643-81.804z"],"attrs":[{}],"width":1165,"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-love"],"defaultCode":59657},"attrs":[{}],"properties":{"order":818,"id":11,"name":"love","prevSize":32,"code":59657},"setIdx":0,"setId":3,"iconIdx":25},{"icon":{"paths":["M968.321 913.171h-912.93c-30.591 0-55.39 24.799-55.39 55.39s24.799 55.39 55.39 55.39v0h912.93c30.591 0 55.39-24.799 55.39-55.39s-24.799-55.39-55.39-55.39v0z","M931.065 848.942c30.591 0 55.39-24.799 55.39-55.39v0-738.161c0-30.591-24.799-55.39-55.39-55.39s-55.39 24.799-55.39 55.39v0 738.137c-0 0.007-0 0.016-0 0.024 0 30.591 24.799 55.39 55.39 55.39l0-0z","M511.735 848.942c30.591 0 55.39-24.799 55.39-55.39v0-504.896c0-30.591-24.799-55.39-55.39-55.39s-55.39 24.799-55.39 55.39v0 504.871c-0 0.007-0 0.016-0 0.024 0 30.591 24.799 55.39 55.39 55.39l0-0z","M92.406 848.942c30.591 0 55.39-24.799 55.39-55.39v0-331.62c0-30.591-24.799-55.39-55.39-55.39s-55.39 24.799-55.39 55.39v0 331.596c-0 0.007-0 0.016-0 0.024 0 30.591 24.799 55.39 55.39 55.39l0-0z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-leaderboard"],"defaultCode":59658},"attrs":[{},{},{},{}],"properties":{"order":819,"id":12,"name":"leaderboard","prevSize":32,"code":59658},"setIdx":0,"setId":3,"iconIdx":26},{"icon":{"paths":["M48.166 895.663c-26.601 0-48.166-21.564-48.166-48.166v0-799.332c0-26.601 21.564-48.166 48.166-48.166v0h755.983c26.601 0 48.166 21.564 48.166 48.166s-21.564 48.166-48.166 48.166v0h-707.817v751.166c0 26.601-21.564 48.166-48.166 48.166v0z","M975.834 1024h-736.933c-26.601 0-48.166-21.564-48.166-48.166v0-354.499c0-26.601 21.564-48.166 48.166-48.166s48.166 21.564 48.166 48.166v0 306.333h640.602v-633.859h-515.372c-26.601 0-48.166-21.564-48.166-48.166s21.564-48.166 48.166-48.166v0h563.537c26.601 0 48.166 21.564 48.166 48.166v0 730.19c0 26.601-21.564 48.166-48.166 48.166v0z","M623.744 786.76c-23.941 0-43.349-19.408-43.349-43.349v0-346.046c0-23.941 19.408-43.349 43.349-43.349s43.349 19.408 43.349 43.349v0 345.829c0 0.064 0.001 0.141 0.001 0.217 0 23.941-19.408 43.349-43.349 43.349-0 0-0-0-0.001-0l0 0z","M764.002 581.238c-0.010 0-0.022 0-0.034 0-11.992 0-22.847-4.869-30.695-12.739l-0.001-0.001-140.306-140.306c-7.864-7.864-12.729-18.729-12.729-30.73 0-24.001 19.457-43.458 43.458-43.458 12.001 0 22.865 4.864 30.73 12.729l140.306 140.33c7.964 7.864 12.896 18.781 12.896 30.851 0 23.941-19.408 43.349-43.349 43.349-0.097 0-0.195-0-0.292-0.001l0.015 0z","M537.239 867.414c-0.021 0-0.047 0-0.072 0-71.756 0-129.927-58.17-129.927-129.927s58.17-129.927 129.927-129.927c71.756 0 129.927 58.17 129.927 129.927l-0-0c-0.068 71.704-58.157 129.817-129.844 129.927l-0.010 0zM537.239 694.499c-23.741 0-42.988 19.246-42.988 42.988s19.246 42.988 42.988 42.988c23.741 0 42.988-19.246 42.988-42.988h0c-0.027-23.73-19.257-42.96-42.985-42.988l-0.003-0z"],"attrs":[{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-album"],"defaultCode":59659},"attrs":[{},{},{},{},{}],"properties":{"order":820,"id":13,"name":"album","prevSize":32,"code":59659},"setIdx":0,"setId":3,"iconIdx":27},{"icon":{"paths":["M743.965 130.818c-78.798-80.684-188.672-130.72-310.232-130.72-239.41 0-433.49 194.080-433.49 433.49s194.080 433.49 433.49 433.49c117.777 0 224.584-46.97 302.71-123.199l-0.089 0.086c81.075-78.661 131.39-188.632 131.39-310.355 0-117.951-47.245-224.867-123.843-302.857l0.063 0.064zM669.092 675.089c-60.675 59.106-143.667 95.56-235.173 95.56-186.208 0-337.159-150.951-337.159-337.159 0-186.057 150.707-336.914 336.707-337.159l0.023-0c0.077-0 0.168-0 0.258-0 186.208 0 337.159 150.951 337.159 337.159 0 94.665-39.014 180.218-101.841 241.457l-0.071 0.069z","M1007.214 928.873l-159.5-163.763c-10.070-10.316-24.114-16.714-39.652-16.714-30.592 0-55.391 24.8-55.391 55.391 0 15.053 6.005 28.704 15.75 38.688l-0.011-0.011 160.536 164.823c10.025 10.268 24.006 16.636 39.474 16.636 2.35 0 4.666-0.147 6.939-0.432l-0.271 0.028c10.465-1.218 19.813-5.231 27.5-11.264l-0.118 0.089c13.151-10.191 21.535-25.989 21.535-43.745 0-0.259-0.002-0.517-0.005-0.775l0 0.039c-0.431-15.266-6.763-28.973-16.785-38.99l-0-0z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-search-2"],"defaultCode":59660},"attrs":[{},{}],"properties":{"order":821,"id":14,"name":"search-2","prevSize":32,"code":59660},"setIdx":0,"setId":3,"iconIdx":28}],"height":1024,"metadata":{"name":"icomoon"},"preferences":{"showGlyphs":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"icon-","metadata":{"fontFamily":"icomoon","majorVersion":1,"minorVersion":0},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"autoHost":false,"noie8":true,"ie7":false,"showSelector":false,"showMetrics":false,"showMetadata":false,"showVersion":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon","name":"icomoon"},"historySize":50,"showCodes":true,"gridSize":16,"showGrid":false,"quickUsageToken":{"UntitledProject":"N2VjNTI2ODAzZWI0N2M1NzhlMjNhYzY3OTEwMWRiMDEjMSMxNjA0MzkyNDUxIyMj"},"showLiga":false}} \ No newline at end of file +{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M512 141.505c-124.939 0-235.61 62.225-302.634 157.148-3.539 4.956-5.656 11.137-5.656 17.81 0 17.056 13.823 30.878 30.878 30.878 10.383 0 19.568-5.121 25.167-12.98l0.066-0.095c55.935-79.215 147.706-131.016 252.185-131.016 166.341 0 300.996 130.715 308.062 295.278l-49.532-49.532c-5.619-5.779-13.464-9.368-22.152-9.368v0c-17.051 0.004-30.866 13.823-30.866 30.876 0 8.685 3.587 16.53 9.355 22.141l92.631 92.631c5.585 5.583 13.307 9.041 21.831 9.041s16.24-3.452 21.831-9.041l7.154-7.154c2.263-1.729 4.223-3.683 5.897-5.874l0.056-0.072 79.519-79.519c5.857-5.628 9.492-13.526 9.492-22.273 0-17.055-13.823-30.876-30.876-30.876-8.746 0-16.648 3.637-22.262 9.481l-0.011 0.012-31.239 31.239c-16.193-189.427-175.348-338.737-368.888-338.737zM182.23 429.669c-8.362 0.125-15.906 3.557-21.386 9.047l-7.035 7.035c-2.334 1.766-4.344 3.777-6.053 6.036l-0.057 0.075-79.479 79.479c-5.857 5.628-9.492 13.526-9.492 22.273 0 17.055 13.823 30.876 30.876 30.876 8.746 0 16.648-3.637 22.262-9.481l0.011-0.012 31.239-31.239c16.193 189.427 175.348 338.737 368.888 338.737 124.939 0 235.61-62.225 302.634-157.148 3.539-4.956 5.656-11.137 5.656-17.81 0-17.056-13.823-30.878-30.878-30.878-10.383 0-19.568 5.121-25.167 12.98l-0.066 0.095c-55.935 79.215-147.706 131.016-252.185 131.016-166.341 0-300.996-130.715-308.062-295.278l49.532 49.532c5.628 5.857 13.526 9.492 22.273 9.492 17.055 0 30.876-13.823 30.876-30.876 0-8.746-3.637-16.648-9.481-22.262l-0.012-0.011-92.624-92.624c-5.586-5.588-13.312-9.050-21.835-9.050-0.154 0-0.3 0.001-0.455 0.003h0.022z"],"attrs":[{"fill":"rgb(91, 91, 91)"}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["available_updates"]},"attrs":[{"fill":"rgb(91, 91, 91)"}],"properties":{"order":882,"id":46,"name":"available_updates","prevSize":32,"code":59665},"setIdx":0,"setId":3,"iconIdx":0},{"icon":{"paths":["M311.416 63.632c-54.276 0-101.956 28.312-129.33 71.024 3.775-0.236 7.564-0.23 11.339-0.23h542.761c97.696 0 176.986 79.29 176.986 176.986v377.57c0 3.775 0.006 7.564-0.23 11.339 42.712-27.374 71.024-75.054 71.024-129.33v-259.58c0-136.633-111.147-247.78-247.78-247.78h-424.77zM193.425 181.626c-84.29 0-153.388 69.097-153.388 153.388v353.972c0 84.29 69.097 153.388 153.388 153.388h11.799v107.021c0 46.048 56.464 74.845 93.702 47.751l212.798-154.773h200.863c84.29 0 153.388-69.097 153.388-153.388v-353.972c0-84.29-69.097-153.388-153.388-153.388h-519.162zM193.425 252.42h519.162c46.018 0 82.594 36.575 82.594 82.594v353.972c0 46.018-36.575 82.594-82.594 82.594h-212.383c-0.001 0-0.004 0-0.006 0-7.828 0-15.066 2.542-20.925 6.845l0.097-0.070-203.349 147.903v-119.28c-0.002-19.549-15.848-35.395-35.397-35.397h-47.197c-46.018 0-82.594-36.575-82.594-82.594v-353.972c0-5.752 0.568-11.372 1.66-16.779 7.632-37.831 40.671-65.815 80.934-65.815z"],"attrs":[{"fill":"rgb(91, 91, 91)"}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-comment"]},"attrs":[{"fill":"rgb(91, 91, 91)"}],"properties":{"order":885,"id":45,"name":"comment","prevSize":32,"code":59672},"setIdx":0,"setId":3,"iconIdx":1},{"icon":{"paths":["M512 92.955c-231.063 0-419.045 187.982-419.045 419.045s187.982 419.045 419.045 419.045c11.039 0 21.862-0.797 32.697-1.634-17.366-18.376-32.24-39.139-43.99-61.792-191.152-6.030-344.891-163.022-344.891-355.611 0-196.407 159.784-356.19 356.19-356.19 192.588 0 349.581 153.752 355.611 344.891 22.674 11.75 43.422 26.596 61.792 43.99 0.841-10.832 1.634-21.651 1.634-32.697 0-231.063-187.982-419.045-419.045-419.045zM521.982 260.128c-17.144 0.276-30.937 14.239-30.937 31.432 0 0.156 0.001 0.314 0.005 0.469v-0.027 219.998h-136.192c-0.137-0.002-0.291-0.003-0.447-0.003-17.354 0-31.432 14.070-31.432 31.432s14.070 31.432 31.432 31.432c0.154 0 0.307-0.001 0.467-0.003h167.597c17.352-0.002 31.432-14.070 31.432-31.432v0-251.432c0.002-0.137 0.003-0.298 0.003-0.454 0-17.354-14.070-31.432-31.432-31.432-0.175 0-0.348 0.001-0.522 0.005h0.027zM742.477 512c-127.289 0-230.477 103.192-230.477 230.477s103.192 230.477 230.477 230.477c127.289 0 230.477-103.192 230.477-230.477s-103.192-230.477-230.477-230.477zM742.477 574.855c0.299 0 0.507 0.164 0.78 0.164 2.368 0.103 4.736 0.412 7.001 1.306l78.402 31.382c24.007 9.615 39.527 32.498 39.527 58.356v10.477c0 6.957-3.467 13.449-9.212 17.352-3.52 2.392-7.617 3.602-11.742 3.602-2.614 0-5.243-0.485-7.781-1.512l-76.037-30.403v171.184c0 3.416-0.432 5.887-1.107 7.893-5.362 25.145-35.518 44.479-72.232 44.479-40.506 0-73.338-23.449-73.338-52.386s32.832-52.386 73.338-52.386c11.299 0 21.87 1.966 31.432 5.241v-193.804c0-2.557 0.591-4.977 1.432-7.287 0.192-0.479 0.358-0.928 0.577-1.396 0.983-2.117 2.253-4.073 3.882-5.768 0.299-0.31 0.632-0.57 0.943-0.854 0.777-0.712 1.496-1.457 2.376-2.049 0.88-0.608 1.858-0.966 2.829-1.432 0.414-0.192 0.768-0.448 1.182-0.616 2.265-0.906 4.631-1.304 7.039-1.396 0.247-0.026 0.445-0.164 0.69-0.164z"],"attrs":[{"fill":"rgb(91, 91, 91)"}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["music_time"]},"attrs":[{"fill":"rgb(91, 91, 91)"}],"properties":{"order":874,"id":42,"name":"music_time","prevSize":32,"code":59648},"setIdx":0,"setId":3,"iconIdx":2},{"icon":{"paths":["M769.011 64.070c-18.539 0.005-33.566 15.036-33.566 33.572 0 9.438 3.894 17.972 10.168 24.072l76.976 76.976h-612.718c-67.808 0-123.084 55.277-123.084 123.084v361.214l67.136-67.136v-294.078c0-30.884 25.061-55.948 55.948-55.948h612.718l-76.972 76.972c-6.363 6.121-10.323 14.703-10.323 24.22 0 18.542 15.034 33.572 33.572 33.572 9.509 0 18.099-3.952 24.208-10.311l0.012-0.013 134.273-134.273c6.076-6.076 9.828-14.469 9.828-23.733s-3.756-17.662-9.828-23.733l-134.273-134.273c-6.108-6.286-14.644-10.183-24.084-10.183v0zM937.202 341.006l-67.136 67.136v294.078c0 30.884-25.061 55.948-55.948 55.948h-612.718l76.972-76.972c6.263-6.105 10.151-14.626 10.151-24.052 0-18.542-15.034-33.572-33.572-33.572-0.34 0-0.68 0.006-1.018 0.017l0.048-0.001c-9.070 0.272-17.196 4.104-23.071 10.133l-134.281 134.281c-6.076 6.076-9.828 14.469-9.828 23.733s3.756 17.662 9.828 23.733l134.273 134.273c6.121 6.363 14.703 10.323 24.22 10.323 18.542 0 33.572-15.034 33.572-33.572 0-9.509-3.952-18.099-10.311-24.208l-0.013-0.012-76.972-76.972h612.718c67.808 0 123.084-55.277 123.084-123.084v-361.214z"],"attrs":[{"fill":"rgb(91, 91, 91)"}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-list-loop"]},"attrs":[{"fill":"rgb(91, 91, 91)"}],"properties":{"order":878,"id":38,"name":"list-loop","prevSize":32,"code":59649},"setIdx":0,"setId":3,"iconIdx":3},{"icon":{"paths":["M812.371 117.66c-17.181 0.004-31.101 13.928-31.101 31.11 0 8.751 3.613 16.654 9.426 22.308l71.333 71.333h-127.421c-45.011 0-87.849 19.533-117.378 53.466l-340.347 391.422c-17.747 20.41-43.393 32.077-70.433 32.077h-119.567c-0.129-0.002-0.283-0.003-0.44-0.003-17.181 0-31.11 13.927-31.11 31.11s13.927 31.11 31.11 31.11c0.155 0 0.311-0.001 0.466-0.003h119.541c44.998 0 87.844-19.498 117.378-53.466l340.347-391.422c17.754-20.399 43.406-32.077 70.433-32.077h127.421l-71.325 71.325c-5.896 5.67-9.563 13.63-9.563 22.442 0 17.181 13.927 31.11 31.11 31.11 8.811 0 16.771-3.667 22.431-9.552l0.011-0.012 124.425-124.425c5.628-5.63 9.106-13.404 9.106-21.994s-3.478-16.364-9.106-21.994l-124.425-124.425c-5.658-5.825-13.567-9.439-22.315-9.439v0zM86.876 242.408c-17.213 0-31.106 13.893-31.106 31.106s13.893 31.106 31.106 31.106h119.646c26.958 0 52.685 11.628 70.315 32.161l111.143 127.952 41.274-47.509-105.349-121.305c-29.654-34.009-72.379-53.507-117.378-53.507h-119.646zM553.071 559.266l-41.274 47.509 105.349 121.305c29.654 34.009 72.379 53.507 117.378 53.507h127.507l-71.325 71.325c-5.896 5.67-9.563 13.63-9.563 22.442 0 17.181 13.927 31.11 31.11 31.11 8.811 0 16.771-3.667 22.431-9.552l0.011-0.012 124.425-124.425c5.628-5.63 9.106-13.404 9.106-21.994s-3.478-16.364-9.106-21.994l-124.425-124.425c-5.658-5.825-13.567-9.439-22.315-9.439v0c-17.181 0.004-31.101 13.928-31.101 31.11 0 8.751 3.613 16.654 9.426 22.308l71.333 71.333h-127.507c-26.958 0-52.685-11.628-70.315-32.161l-111.143-127.952z"],"attrs":[{"fill":"rgb(91, 91, 91)"}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-list-random"]},"attrs":[{"fill":"rgb(91, 91, 91)"}],"properties":{"order":873,"id":43,"name":"list-random","prevSize":32,"code":59650},"setIdx":0,"setId":3,"iconIdx":4},{"icon":{"paths":["M713.492 83.628c-19.45 0.31-35.103 16.154-35.103 35.656 0 0.182 0.001 0.358 0.005 0.536v-0.028 722.111l-105.523-105.523c-6.501-6.76-15.62-10.964-25.719-10.964-19.695 0-35.662 15.967-35.662 35.662 0 10.099 4.204 19.223 10.951 25.713l0.014 0.013 166.393 166.393c6.455 6.453 15.368 10.437 25.212 10.437s18.757-3.988 25.212-10.437l166.393-166.393c6.76-6.501 10.964-15.62 10.964-25.719 0-19.695-15.967-35.662-35.662-35.662-10.099 0-19.223 4.204-25.713 10.951l-0.013 0.014-105.523 105.523v-722.111c0.003-0.149 0.004-0.332 0.004-0.514 0-19.695-15.967-35.662-35.662-35.662-0.193 0-0.392 0.001-0.583 0.005h0.028zM283.215 131.815c-2.79 0.238-5.592 0.761-8.311 1.675l-71.308 23.771c-18.681 6.229-28.793 26.441-22.565 45.128s26.487 28.86 45.128 22.565l24.375-8.168v212.028c0 19.707 15.95 35.658 35.658 35.658s35.658-15.95 35.658-35.658v-261.472c0-11.46-5.518-22.22-14.813-28.922-6.989-5.031-15.439-7.295-23.817-6.592zM274.301 583.308c-63.132 0-109.64 39.984-118.48 101.903-2.778 19.495 10.733 37.562 30.223 40.343 19.467 2.804 37.562-10.705 40.343-30.223 2.665-18.563 13.134-40.719 47.913-40.719 26.216 0 47.544 21.319 47.544 47.544s-21.319 47.544-47.544 47.544c-57.236 0-118.85 40.907-118.85 130.735 0 19.707 15.977 35.658 35.658 35.658h166.393c19.707 0 35.658-15.95 35.658-35.658s-15.95-35.658-35.658-35.658h-123.397c11.247-21.559 32.216-23.771 40.204-23.771 65.533 0 118.85-53.32 118.85-118.85s-53.32-118.85-118.85-118.85z"],"attrs":[{"fill":"rgb(91, 91, 91)"}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-list-order"]},"attrs":[{"fill":"rgb(91, 91, 91)"}],"properties":{"order":875,"id":41,"name":"list-order","prevSize":32,"code":59651},"setIdx":0,"setId":3,"iconIdx":5},{"icon":{"paths":["M782.78 40.073c-19.532 0.005-35.363 15.841-35.363 35.37 0 9.945 4.104 18.935 10.714 25.362l81.101 81.101h-645.541c-71.441 0-129.678 58.238-129.678 129.678v380.564l70.733-70.733v-309.831c0-32.538 26.405-58.945 58.945-58.945h645.541l-81.095 81.095c-6.705 6.448-10.875 15.492-10.875 25.516 0 19.535 15.838 35.37 35.37 35.37 10.019 0 19.068-4.165 25.504-10.863l0.012-0.013 141.467-141.467c6.4-6.401 10.354-15.243 10.354-25.005s-3.957-18.607-10.354-25.005l-141.467-141.467c-6.435-6.622-15.427-10.729-25.374-10.729v0zM959.981 331.847l-70.733 70.733v309.831c0 32.538-26.405 58.945-58.945 58.945h-645.541l81.095-81.095c6.599-6.432 10.694-15.409 10.694-25.34 0-19.535-15.838-35.37-35.37-35.37-0.358 0-0.716 0.006-1.072 0.017l0.051-0.001c-9.556 0.287-18.117 4.323-24.307 10.676l-141.475 141.475c-6.4 6.401-10.354 15.243-10.354 25.005s3.957 18.607 10.354 25.005l141.467 141.467c6.448 6.705 15.492 10.875 25.516 10.875 19.535 0 35.37-15.838 35.37-35.37 0-10.019-4.165-19.068-10.863-25.504l-0.013-0.012-81.095-81.095h645.541c71.441 0 129.678-58.238 129.678-129.678v-380.564zM527.334 347.002c-2.311 0.196-4.617 0.675-6.863 1.429l-70.733 23.576c-15.442 5.162-23.792 21.859-18.651 37.302 5.162 15.422 21.834 23.746 37.302 18.651l31.913-10.639v230.251c0 16.268 13.203 29.471 29.471 29.471s29.471-13.202 29.471-29.52v-271.145c0-9.477-4.565-18.361-12.247-23.901-5.763-4.158-12.735-6.061-19.665-5.479z"],"attrs":[{"fill":"rgb(91, 91, 91)"}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-single-loop"]},"attrs":[{"fill":"rgb(91, 91, 91)"}],"properties":{"order":879,"id":44,"name":"single-loop","prevSize":32,"code":59652},"setIdx":0,"setId":3,"iconIdx":6},{"icon":{"paths":["M512 72c-242.617 0-440 197.383-440 440s197.383 440 440 440c242.617 0 440-197.383 440-440s-197.383-440-440-440zM512 138c91.519 0 174.114 33.962 239.037 88.303l-524.727 524.689c-54.329-64.918-88.303-147.483-88.303-238.997 0-206.939 167.060-374 374-374zM797.697 272.963c54.347 64.922 88.303 147.518 88.303 239.037 0 206.939-167.060 374-374 374-91.503 0-174.078-33.963-238.997-88.303l524.689-524.728z"],"attrs":[{"fill":"rgb(91, 91, 91)"}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-single"]},"attrs":[{"fill":"rgb(91, 91, 91)"}],"properties":{"order":876,"id":40,"name":"single","prevSize":32,"code":59673},"setIdx":0,"setId":3,"iconIdx":7},{"icon":{"paths":["M197.733 16.079c-57.158 2.263-109.626 48.892-109.626 111.719v768.402c0 83.768 93.326 138.729 166.607 98.131l693.403-384.201c75.389-41.772 75.389-154.491 0-196.264l-693.403-384.201c-18.321-10.148-37.927-14.342-56.98-13.588zM198.61 89.763c6.448-0.029 13.207 1.643 19.82 5.308l693.452 384.201c27.392 15.178 27.392 50.275 0 65.453l-693.452 384.201c-26.458 14.659-55.52-2.494-55.52-32.727v-768.402c0-15.116 7.249-26.935 17.825-33.165 5.288-3.117 11.426-4.843 17.874-4.87z"],"attrs":[{"fill":"rgb(91, 91, 91)"}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-play-outline"]},"attrs":[{"fill":"rgb(91, 91, 91)"}],"properties":{"order":872,"id":37,"name":"play-outline","prevSize":32,"code":59681},"setIdx":0,"setId":3,"iconIdx":8},{"icon":{"paths":["M469.685 572.65v-572.65h84.628v572.65zM511.999 1023.998q-104.374 0-196.76-40.198t-161.498-109.312-109.312-161.498-40.198-196.76q0-112.837 47.956-210.865t135.405-174.192l59.24 59.24q-74.754 60.651-116.364 144.573t-41.609 181.246q0 176.308 123.416 299.724t299.724 123.416 299.724-123.416 123.416-299.724q0-97.322-41.609-182.655t-113.543-143.163l60.651-59.24q84.628 71.934 131.878 172.077t47.25 212.981q0 104.374-40.198 196.76t-108.606 161.498-160.793 109.312-198.171 40.198z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-exit"]},"attrs":[{}],"properties":{"order":868,"id":35,"name":"exit2","prevSize":32,"code":59679},"setIdx":0,"setId":3,"iconIdx":9},{"icon":{"paths":["M86.515 1024.001q-34.039 0-59.568-25.529t-25.529-59.568v-297.839h85.097v297.839h850.97v-853.806h-850.97v300.676h-85.097v-300.676q0-34.039 25.529-59.568t59.568-25.529h850.97q34.039 0 59.568 25.529t25.529 59.568v853.806q0 34.039-25.529 59.568t-59.568 25.529zM416.975 787.148l-63.823-63.823 167.358-167.358h-519.092v-85.097h519.092l-167.358-167.358 63.823-63.823 273.729 273.729z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-exit"]},"attrs":[{}],"properties":{"order":867,"id":34,"name":"exit","prevSize":32,"code":59678},"setIdx":0,"setId":3,"iconIdx":10},{"icon":{"paths":["M465.902 1.102c-44.961-7.649-81.748 25.464-81.748 71.063v471.297c-26.614-9.764-55.241-15.373-85.225-15.373-136.943 0-247.961 111.022-247.961 247.97 0 136.939 111.018 247.942 247.961 247.942 78.047 0 147.539-36.165 192.953-92.542l-113.518-113.532c-34.555-34.546-26.765-66.068-21.813-78.044 4.951-11.963 21.749-39.776 70.599-39.776h41.336v-130.039c0-48.308 33.415-88.839 78.332-100.001 0.073-101.437 0.073-187.014 0.073-187.014 320.377 0 301.122 191.965 263.634 302.201-14.676 43.169-5.946 50.406 24.901 16.811 390.955-425.798-153.327-564.193-369.524-600.961z","M688.227 511.782h-116.573c-8.941 0-17.314 2.172-24.892 5.768-19.696 9.35-33.41 29.256-33.41 52.516v174.902h-86.201c-32.192 0-39.84 18.45-17.067 41.214l178.635 178.638c11.393 11.396 26.319 17.086 41.224 17.086 14.912 0 29.837-5.678 41.214-17.086l178.656-178.64c22.748-22.764 15.106-41.214-17.076-41.214h-86.205v-174.902c0.002-32.182-26.106-58.282-58.305-58.282z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-logo"]},"attrs":[{},{}],"properties":{"order":865,"id":33,"name":"logo","prevSize":32,"code":59669},"setIdx":0,"setId":3,"iconIdx":11},{"icon":{"paths":["M56.89 113.778h910.221c31.418 0 56.89 25.471 56.89 56.89s-25.471 56.89-56.89 56.89v0h-910.221c-31.418 0-56.89-25.471-56.89-56.89s25.471-56.89 56.89-56.89v0zM56.89 455.11h910.221c31.418 0 56.89 25.471 56.89 56.89s-25.471 56.89-56.89 56.89v0h-910.221c-31.418 0-56.89-25.471-56.89-56.89s25.471-56.89 56.89-56.89v0zM56.89 796.443h910.221c31.418 0 56.89 25.471 56.89 56.89s-25.471 56.89-56.89 56.89v0h-910.221c-31.418 0-56.89-25.471-56.89-56.89s25.471-56.89 56.89-56.89v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-menu"]},"attrs":[{}],"properties":{"order":866,"id":32,"name":"menu","prevSize":32,"code":59677},"setIdx":0,"setId":3,"iconIdx":12},{"icon":{"paths":["M181.333 170.667c-52.928 0-96 43.072-96 96v490.667c0 52.928 43.072 96 96 96h309.417c-8.448-20.203-14.314-41.707-17.792-64h-291.625c-17.643 0-32-14.357-32-32v-490.667c0-17.643 14.357-32 32-32h161.125c12.459 0 24.567 4.376 34.167 12.333l104.25 86.917c5.739 4.8 12.97 7.417 20.458 7.417h341.333c17.643 0 32 14.357 32 32v127.542c23.531 12.309 45.035 27.885 64 46.125v-173.667c0-52.928-43.072-96-96-96h-329.75l-95.375-79.5c-21.056-17.515-47.713-27.167-75.083-27.167h-161.125zM746.667 512c-129.6 0-234.667 105.067-234.667 234.667s105.067 234.667 234.667 234.667c129.6 0 234.667-105.067 234.667-234.667s-105.067-234.667-234.667-234.667zM746.667 576c11.776 0 21.333 9.557 21.333 21.333v128h128c11.776 0 21.333 9.557 21.333 21.333s-9.557 21.333-21.333 21.333h-128v128c0 11.776-9.557 21.333-21.333 21.333s-21.333-9.557-21.333-21.333v-128h-128c-11.776 0-21.333-9.557-21.333-21.333s9.557-21.333 21.333-21.333h128v-128c0-11.776 9.557-21.333 21.333-21.333z"],"attrs":[{"fill":"rgb(91, 91, 91)"}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["iocn-add_folder"]},"attrs":[{"fill":"rgb(91, 91, 91)"}],"properties":{"order":884,"id":47,"name":"add_folder","prevSize":32,"code":59666},"setIdx":0,"setId":3,"iconIdx":13},{"icon":{"paths":["M1024 103.129l-103.129-103.129-408.871 408.871-408.871-408.871-103.129 103.129 408.871 408.871-408.871 408.871 103.129 103.129 408.871-408.871 408.871 408.871 103.129-103.129-408.871-408.871 408.871-408.871z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-remove"]},"attrs":[{}],"properties":{"order":828,"id":17,"prevSize":32,"code":59663,"name":"remove"},"setIdx":0,"setId":3,"iconIdx":14},{"icon":{"paths":["M0.001 107.79v161.684h269.473v646.736h161.684v-646.736h269.473v-161.684h-700.631zM1024 377.263h-485.052v161.684h161.684v377.263h161.684v-377.263h161.684v-161.684z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-font-size"]},"attrs":[{}],"properties":{"order":852,"id":30,"name":"font-size","prevSize":32,"code":59676},"setIdx":0,"setId":3,"iconIdx":15},{"icon":{"paths":["M964.54 573.38c17.54-29.7 27.46-61.38 27.46-99.68 0-88.030-74.436-171.16-171.64-171.16h-72.96c9.84-25.62 17.7-56.26 17.7-93.080 0-145.588-75.38-209.46-190.54-209.46-123.214 0-116.186 189.866-143.52 217.2-45.494 45.494-99.23 132.894-137.52 166.8h-197.52c-35.346 0-64 28.654-64 64v480c0 35.346 28.654 64 64 64h128c29.786 0 54.816-20.348 61.956-47.9 89.018 2.002 150.12 79.88 355.604 79.88 14.44 0 30.44 0.020 44.44 0.020 154.234 0 223.972-78.846 225.88-190.66 26.638-36.85 40.598-86.244 34.68-133.98 19.708-36.904 27.328-80.686 17.98-125.98zM841.040 681.040c25.12 42.26 2.52 98.82-27.88 115.14 15.4 97.56-35.216 131.8-106.24 131.8h-75.64c-143.278 0-236.058-75.64-343.28-75.64v-372.34h21.84c56.72 0 135.96-141.78 189.080-194.92 56.72-56.72 37.82-151.26 75.64-189.080 94.54 0 94.54 65.96 94.54 113.46 0 78.34-56.72 113.44-56.72 189.080h207.98c42.22 0 75.46 37.82 75.64 75.64 0.18 37.8-25.64 75.62-44.54 75.62 26.978 29.11 32.742 90.472-10.42 131.24zM208 864c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-thumbs-up"]},"attrs":[{}],"properties":{"order":851,"id":29,"name":"thumbs-up","prevSize":32,"code":59675},"setIdx":0,"setId":3,"iconIdx":16},{"icon":{"paths":["M509.38 291.64s-129.324-159.008-291.904-49.688c-145.41 159.044-62.294 370.737 291.904 556.885 44.177-17.309 91.090-35.192 91.090-35.192 39.332-13.236 58.285 42.941 33.123 53.828-57.118 24.711 12.369-8.571-124.212 57.967-603.515-286.001-438.9-627.212-333.305-693.525 179.695-136.405 335.375 20.705 335.375 20.705s120.398-125.299 289.831-47.618c215.371 121.163 132.491 335.166 93.159 405.759-18.946 31.369-81.899-8.607-66.246-33.123 42.11-78.433 94.243-222.233-51.758-310.531-145.081-62.275-267.060 74.525-267.060 74.525z","M772.301 701.539c-16.767 0.024-51.283-0.318-82.811 0-32.526 0.33-31.638 72.384 0 72.455 31.262 0.072 82.811 0 82.811 0s-0.14 88.606 0 99.368c0.43 33.045 66.788 32.69 66.246-2.070-0.15-9.621 0-97.299 0-97.299s78.683-0.067 89.020 0c32.572 0.095 30.941-70.345-2.070-70.385-10.108 0.192-86.95 0-86.95 0s-0.112-58.67 0-95.229c0.095-31.445-66.305-32.113-66.246 0 0.057 30.514-0.454 87.238 0 93.159z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-add-music"]},"attrs":[{},{}],"properties":{"order":843,"id":25,"name":"add-music","prevSize":32,"code":59670},"setIdx":0,"setId":3,"iconIdx":17},{"icon":{"paths":["M512 768.001c70.692 0 128 57.308 128 128v0c0 70.692-57.308 128-128 128v0c-70.692 0-128-57.308-128-128v0c0-70.692 57.308-128 128-128v0zM512 384c70.692 0 128 57.308 128 128v0c0 70.692-57.308 128-128 128v0c-70.692 0-128-57.308-128-128v0c0-70.692 57.308-128 128-128v0zM512 0c70.692 0 128 57.308 128 128v0c0 70.692-57.308 128-128 128v0c-70.692 0-128-57.308-128-128v0c0-70.692 57.308-128 128-128v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-dots-vertical"]},"attrs":[{}],"properties":{"order":833,"id":21,"name":"dots-vertical","prevSize":32,"code":59667},"setIdx":0,"setId":3,"iconIdx":18},{"icon":{"paths":["M69.048 478.058l388.688-388.686c18.746-18.746 49.138-18.746 67.882 0l45.334 45.334c18.714 18.714 18.75 49.044 0.080 67.802l-308.042 309.492 308.042 309.49c18.67 18.758 18.634 49.088-0.080 67.802l-45.334 45.334c-18.746 18.746-49.138 18.746-67.882 0l-388.686-388.686c-18.746-18.744-18.746-49.136-0.002-67.882z"],"attrs":[{}],"width":640,"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-chevron-left"]},"attrs":[{}],"properties":{"order":854,"id":18,"name":"chevron-left","prevSize":32,"code":59664},"setIdx":0,"setId":3,"iconIdx":19},{"icon":{"paths":["M570.952 545.942l-388.688 388.686c-18.746 18.746-49.138 18.746-67.882 0l-45.334-45.334c-18.714-18.714-18.75-49.044-0.080-67.802l308.042-309.492-308.042-309.49c-18.67-18.758-18.634-49.088 0.080-67.802l45.334-45.334c18.746-18.746 49.138-18.746 67.882 0l388.686 388.686c18.746 18.744 18.746 49.136 0.002 67.882z"],"attrs":[{}],"width":640,"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-chevron-right"]},"attrs":[{}],"properties":{"order":869,"id":36,"prevSize":32,"code":59680,"name":"chevron-right"},"setIdx":0,"setId":3,"iconIdx":20},{"icon":{"paths":["M633.703 512l365.094-365.094c33.607-33.607 33.607-88.095 0-121.698-33.607-33.607-88.091-33.607-121.698 0l-365.099 365.099-365.099-365.104c-33.607-33.607-88.091-33.607-121.698 0-33.603 33.607-33.603 88.095 0 121.698l365.099 365.094-365.099 365.099c-33.603 33.607-33.603 88.095 0 121.698 33.607 33.607 88.091 33.607 121.698 0l365.099-365.099 365.099 365.099c33.603 33.607 88.091 33.607 121.698 0s33.607-88.091 0-121.698l-365.094-365.094z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-close"]},"attrs":[{}],"properties":{"order":826,"id":15,"name":"close","prevSize":32,"code":59662},"setIdx":0,"setId":3,"iconIdx":21},{"icon":{"paths":["M52.504 168.606v686.806c0 93.13 61.701 168.588 137.82 168.588 76.127 0 137.865-75.462 137.865-168.588v-686.806c0-93.085-61.738-168.577-137.865-168.577-76.119-0.030-137.82 75.492-137.82 168.577z","M833.635 0c-76.112 0-137.813 75.492-137.813 168.577v686.806c0 93.13 61.701 168.558 137.813 168.558s137.861-75.433 137.861-168.558v-686.776c-0.033-93.085-61.749-168.606-137.861-168.606z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-pause"]},"attrs":[{},{}],"properties":{"order":808,"id":1,"name":"pause","prevSize":32,"code":59661},"setIdx":0,"setId":3,"iconIdx":22},{"icon":{"paths":["M217.83 22.578c-92.32-52.955-167.165-9.574-167.165 96.819v785.129c0 106.499 74.847 149.824 167.165 96.919l686.242-393.555c92.351-52.974 92.351-138.801 0-191.763l-686.242-393.549z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-play"],"defaultCode":59653},"attrs":[{}],"properties":{"order":814,"id":7,"name":"play","prevSize":32,"code":59653},"setIdx":0,"setId":3,"iconIdx":23},{"icon":{"paths":["M96.898 152.171c-53.489 0-96.898 64.037-96.898 143.006v433.653c0 78.944 43.432 143.001 96.898 143.001 53.545 0 96.902-64.056 96.902-143.001v-119.627l352.204 201.971c67.023 38.471 121.477 8.351 123.795-67l-225.15-129.124c-44.415-25.451-69.917-63.036-69.917-103.083 0-40.084 25.502-77.637 69.917-103.134l225.15-129.073c-2.318-75.295-56.772-105.452-123.795-66.986l-352.204 201.92v-119.515c0.023-78.995-43.358-143.006-96.902-143.006z","M502.254 583.092l397.714 228.080c68.475 39.291 124.032 7.103 124.032-71.883v-454.686c0-78.94-55.557-111.137-124.032-71.832l-397.742 228.020c-68.452 39.301-68.452 103.009 0.028 142.301z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-prevMusic"],"defaultCode":59654},"attrs":[{},{}],"properties":{"order":860,"id":22,"prevSize":32,"code":59668,"name":"prevMusic"},"setIdx":0,"setId":3,"iconIdx":24},{"icon":{"paths":["M927.102 871.83c53.489 0 96.898-64.037 96.898-143.006v-433.653c0-78.944-43.432-143.001-96.898-143.001-53.545 0-96.902 64.056-96.902 143.001v119.627l-352.204-201.971c-67.023-38.471-121.477-8.351-123.795 67l225.15 129.123c44.415 25.451 69.917 63.036 69.917 103.083 0 40.084-25.502 77.637-69.917 103.134l-225.15 129.072c2.318 75.295 56.772 105.452 123.795 66.986l352.204-201.92v119.515c-0.023 78.995 43.358 143.006 96.902 143.006z","M521.746 440.909l-397.714-228.080c-68.475-39.291-124.032-7.103-124.032 71.883v454.686c0 78.94 55.557 111.137 124.032 71.832l397.742-228.020c68.452-39.301 68.452-103.009-0.028-142.301z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-nextMusic"],"defaultCode":59654},"attrs":[{},{}],"properties":{"order":836,"id":8,"name":"nextMusic","prevSize":32,"code":59654},"setIdx":0,"setId":3,"iconIdx":25},{"icon":{"paths":["M578.472 732.037c-121.522 0-220.036-98.514-220.036-220.036s98.514-220.036 220.036-220.036c121.522 0 220.036 98.514 220.036 220.036v0c-0.146 121.464-98.572 219.891-220.023 220.036h-0.014zM578.472 384.418c-70.462 0-127.583 57.121-127.583 127.583s57.12 127.583 127.583 127.583c70.462 0 127.583-57.12 127.583-127.583v0c-0.079-70.43-57.152-127.503-127.574-127.583h-0.008z","M1145.056 469.341l-246.423-426.682c-15.048-25.628-42.44-42.579-73.799-42.659h-492.694c-31.404 0.050-58.837 17.009-73.685 42.258l-0.218 0.401-246.329 426.682c-7.162 12.244-11.391 26.957-11.391 42.659s4.229 30.416 11.61 43.065l-0.219-0.406 246.423 426.682c15.063 25.643 42.485 42.601 73.871 42.659h492.621c31.397-0.054 58.822-17.012 73.662-42.258l0.218-0.401 246.423-426.682c7.14-12.229 11.357-26.921 11.357-42.599 0-15.727-4.242-30.462-11.645-43.125l0.219 0.405zM341.627 922.223l-236.844-410.223 236.844-410.247h473.712l236.844 410.247-236.844 410.223z"],"attrs":[{},{}],"width":1157,"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-setting"],"defaultCode":59655},"attrs":[{},{}],"properties":{"order":816,"id":9,"name":"setting","prevSize":32,"code":59655},"setIdx":0,"setId":3,"iconIdx":26},{"icon":{"paths":["M974.751 1023.699h-925.525c-27.228-0.19-49.226-22.307-49.226-49.561 0-0.119 0-0.238 0.001-0.357v0.018-414.489c-0.001-0.1-0.001-0.219-0.001-0.338 0-27.254 21.999-49.371 49.208-49.561h0.018c27.228 0.19 49.226 22.307 49.226 49.561 0 0.119 0 0.238-0.001 0.357v-0.018 364.613h827.075v-365.504c0-27.193 22.044-49.237 49.237-49.237s49.237 22.044 49.237 49.237v0 415.38c0 0.007 0 0.016 0 0.025 0 13.741-5.516 26.193-14.456 35.262l0.006-0.006c-8.86 9.010-21.175 14.599-34.796 14.618h-0.004z","M512 582.502c-25.964-0.191-46.938-21.283-46.938-47.273 0-0.102 0-0.204 0.001-0.306v0.016-487.676c0-25.936 21.025-46.961 46.961-46.961s46.961 21.025 46.961 46.961v0 487.58c0.001 0.115 0.002 0.25 0.002 0.386 0 26.008-21.002 47.111-46.972 47.274h-0.016z","M512 658.628c-0.024 0-0.052 0-0.080 0-13.966 0-26.633-5.558-35.912-14.582l0.012 0.012-193.361-186.497c-8.999-8.738-14.582-20.95-14.582-34.466 0-12.694 4.925-24.238 12.969-32.824l-0.025 0.027c8.515-9.098 20.596-14.768 34.002-14.768 12.587 0 24.006 4.998 32.382 13.118l164.57 158.742 164.582-158.754c8.364-8.108 19.783-13.106 32.37-13.106 13.406 0 25.487 5.67 33.978 14.742l0.024 0.026c8.019 8.56 12.945 20.104 12.945 32.798 0 13.516-5.584 25.728-14.571 34.454l-0.012 0.011-193.385 186.521c-9.268 8.998-21.928 14.546-35.885 14.546-0.008 0-0.016 0-0.024 0h0.001zM540.755 575.109v0z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-download-2"],"defaultCode":59656},"attrs":[{},{},{}],"properties":{"order":817,"id":10,"name":"download-2","prevSize":32,"code":59656},"setIdx":0,"setId":3,"iconIdx":27},{"icon":{"paths":["M582.103 1023.979c-0.017 0-0.037 0-0.057 0-9.91 0-19.135-2.929-26.858-7.969l0.189 0.116-0.366-0.236c-37.014-20.47-322.334-182.265-474.13-387.408-50.491-68.21-80.819-154.003-80.819-246.879 0-19.704 1.365-39.089 4.006-58.067l-0.25 2.192c14.344-104.705 67.037-196.32 148.366-258.045 92.559-70.283 201.609-86.225 315.345-45.86 43.791 16.083 81.683 36.31 116.21 60.947l-1.48-1.003c33.048-23.634 70.939-43.86 111.372-58.853l3.359-1.091c113.788-40.337 222.838-24.422 315.37 45.86 81.33 61.829 134.022 153.471 148.366 258.045 2.401 16.818 3.771 36.242 3.771 55.986 0 92.851-30.314 178.622-81.584 247.955l0.802-1.136c-152.712 206.19-440.415 368.797-474.783 387.643-7.598 4.895-16.869 7.819-26.821 7.853h-0.009zM347.59 105.694c-43.425 0-89.994 12.46-135.593 47.117-59.054 44.892-97.349 111.588-107.794 187.813-1.757 12.365-2.76 26.646-2.76 41.16 0 68.639 22.431 132.040 60.363 183.271l-0.591-0.835c123.421 166.664 348.143 304.769 421.071 347.018 73.005-42.169 297.65-180.354 421.071-347.018 37.342-50.393 59.773-113.792 59.773-182.429 0-14.517-1.004-28.801-2.945-42.783l0.184 1.616c-10.471-76.199-48.74-142.895-107.82-187.813-159.125-120.933-330.108 28.27-337.384 34.684-8.691 7.859-20.268 12.668-32.969 12.668s-24.278-4.809-33.012-12.706l0.043 0.038c-5.052-4.555-93.553-81.801-201.634-81.801z"],"attrs":[{}],"width":1165,"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-love"],"defaultCode":59657},"attrs":[{}],"properties":{"order":818,"id":11,"name":"love","prevSize":32,"code":59657},"setIdx":0,"setId":3,"iconIdx":28},{"icon":{"paths":["M968.343 913.191h-912.975c-30.592 0-55.393 24.8-55.393 55.393s24.8 55.393 55.393 55.393v0h912.975c30.592 0 55.393-24.8 55.393-55.393s-24.8-55.393-55.393-55.393v0z","M931.085 848.958c30.592 0 55.393-24.8 55.393-55.393v0-738.197c0-30.592-24.8-55.393-55.393-55.393s-55.393 24.8-55.393 55.393v0 738.173c0 0.007 0 0.016 0 0.024 0 30.592 24.8 55.393 55.393 55.393v0z","M511.735 848.958c30.592 0 55.393-24.8 55.393-55.393v0-504.921c0-30.592-24.8-55.393-55.393-55.393s-55.393 24.8-55.393 55.393v0 504.896c0 0.007 0 0.016 0 0.024 0 30.592 24.8 55.393 55.393 55.393v0z","M92.386 848.958c30.592 0 55.393-24.8 55.393-55.393v0-331.636c0-30.592-24.8-55.393-55.393-55.393s-55.393 24.8-55.393 55.393v0 331.612c0 0.007 0 0.016 0 0.024 0 30.592 24.8 55.393 55.393 55.393v0z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-leaderboard"],"defaultCode":59658},"attrs":[{},{},{},{}],"properties":{"order":819,"id":12,"name":"leaderboard","prevSize":32,"code":59658},"setIdx":0,"setId":3,"iconIdx":29},{"icon":{"paths":["M48.166 895.662c-26.601 0-48.166-21.564-48.166-48.166v0-799.331c0-26.601 21.564-48.166 48.166-48.166v0h755.983c26.601 0 48.166 21.564 48.166 48.166s-21.564 48.166-48.166 48.166v0h-707.816v751.165c0 26.601-21.564 48.166-48.166 48.166v0z","M975.834 1024h-736.932c-26.601 0-48.166-21.564-48.166-48.166v0-354.499c0-26.601 21.564-48.166 48.166-48.166s48.166 21.564 48.166 48.166v0 306.333h640.602v-633.858h-515.371c-26.601 0-48.166-21.564-48.166-48.166s21.564-48.166 48.166-48.166v0h563.537c26.601 0 48.166 21.564 48.166 48.166v0 730.19c0 26.601-21.564 48.166-48.166 48.166v0z","M623.744 786.76c-23.941 0-43.349-19.408-43.349-43.349v0-346.046c0-23.941 19.408-43.349 43.349-43.349s43.349 19.408 43.349 43.349v0 345.828c0 0.064 0.001 0.141 0.001 0.217 0 23.941-19.408 43.349-43.349 43.349 0 0 0 0-0.001 0v0z","M764.001 581.238c-0.010 0-0.022 0-0.034 0-11.992 0-22.847-4.869-30.695-12.739l-140.307-140.307c-7.864-7.864-12.729-18.729-12.729-30.73 0-24.001 19.457-43.458 43.458-43.458 12 0 22.865 4.864 30.73 12.729l140.306 140.33c7.964 7.864 12.896 18.781 12.896 30.851 0 23.941-19.408 43.349-43.349 43.349-0.097 0-0.195 0-0.292-0.001h0.015z","M537.239 867.414c-0.021 0-0.047 0-0.072 0-71.756 0-129.927-58.17-129.927-129.927s58.17-129.927 129.927-129.927c71.756 0 129.927 58.17 129.927 129.927v0c-0.068 71.704-58.157 129.817-129.844 129.927h-0.010zM537.239 694.498c-23.741 0-42.988 19.246-42.988 42.988s19.246 42.988 42.988 42.988c23.741 0 42.988-19.246 42.988-42.988v0c-0.027-23.73-19.257-42.96-42.985-42.988h-0.003z"],"attrs":[{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-album"],"defaultCode":59659},"attrs":[{},{},{},{},{}],"properties":{"order":820,"id":13,"name":"album","prevSize":32,"code":59659},"setIdx":0,"setId":3,"iconIdx":30},{"icon":{"paths":["M744.005 130.752c-78.812-80.698-188.704-130.742-310.286-130.742-239.452 0-433.565 194.114-433.565 433.565s194.114 433.565 433.565 433.565c117.797 0 224.623-46.978 302.762-123.221l-0.089 0.086c81.089-78.675 131.413-188.664 131.413-310.409 0-117.972-47.254-224.906-123.865-302.909l0.063 0.064zM669.119 675.117c-60.686 59.116-143.692 95.577-235.214 95.577-186.24 0-337.217-150.977-337.217-337.217 0-186.089 150.733-336.972 336.765-337.217h0.023c0.077 0 0.168 0 0.258 0 186.24 0 337.217 150.977 337.217 337.217 0 94.682-39.020 180.25-101.858 241.499l-0.071 0.069z","M1007.3 928.945l-159.527-163.792c-10.072-10.318-24.118-16.717-39.659-16.717-30.597 0-55.4 24.804-55.4 55.4 0 15.056 6.006 28.709 15.753 38.694l-0.011-0.011 160.564 164.851c10.026 10.27 24.010 16.639 39.481 16.639 2.35 0 4.667-0.147 6.941-0.432l-0.271 0.028c10.466-1.218 19.816-5.232 27.505-11.266l-0.118 0.089c13.153-10.193 21.538-25.994 21.538-43.752 0-0.259-0.002-0.517-0.005-0.775v0.039c-0.431-15.268-6.764-28.978-16.788-38.997v0z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["icon-search-2"],"defaultCode":59660},"attrs":[{},{}],"properties":{"order":821,"id":14,"name":"search-2","prevSize":32,"code":59660},"setIdx":0,"setId":3,"iconIdx":31}],"height":1024,"metadata":{"name":"icomoon"},"preferences":{"showGlyphs":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"icon-","metadata":{"fontFamily":"icomoon","majorVersion":1,"minorVersion":0},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"autoHost":false,"noie8":true,"ie7":false,"showSelector":false,"showMetrics":false,"showMetadata":false,"showVersion":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon","name":"icomoon"},"historySize":50,"showCodes":true,"gridSize":16,"showGrid":false,"quickUsageToken":{"UntitledProject":"N2VjNTI2ODAzZWI0N2M1NzhlMjNhYzY3OTEwMWRiMDEjMSMxNjA0MzkyNDUxIyMj"},"showLiga":false}} \ No newline at end of file diff --git a/src/screens/Comment/CommentHot.js b/src/screens/Comment/CommentHot.js deleted file mode 100644 index b75a02cd2..000000000 --- a/src/screens/Comment/CommentHot.js +++ /dev/null @@ -1,196 +0,0 @@ -import React, { memo, useState, useMemo, useCallback, useEffect, useRef } from 'react' -import { View, Text, StyleSheet, FlatList, RefreshControl } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import music from '@/utils/music' -import CommentFloor from './components/CommentFloor' -import { useTranslation } from '@/plugins/i18n' -const limit = 15 - -const getComment = async(musicInfo, page, limit, retryNum = 0) => { - let resp - try { - resp = await music[musicInfo.source].comment.getHotComment(musicInfo, page, limit) - } catch (error) { - console.log(error.message) - if (error.message == '取消请求' || ++retryNum > 2) throw error - resp = await getComment(musicInfo, page, limit, retryNum) - } - return resp -} -const filterList = list => { - let keys = [] - return list.filter(c => { - let id = String(c.id) - if (keys.includes(id)) return false - keys.push(id) - return true - }) -} - -export default memo(({ musicInfo, setTotal }) => { - const [isListRefreshing, setIsListRefreshing] = useState(false) - const [isLoadError, setIsLoadError] = useState(false) - // const [isLoading, setIsLoading] = useState(false) - const [isEnd, setIsEnd] = useState(false) - const [commentList, setCommentList] = useState([]) - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - const scrollViewRef = useRef() - const listInfo = useRef({ page: 1, total: 0, maxPage: 1, isEnd: false, isLoading: false, isLoadError: false }) - const handleGetComment = (musicInfo, page) => { - // setIsLoading(true) - listInfo.current.isLoading = true - return getComment(musicInfo, page, limit).then(commentInfo => { - listInfo.current.page = page - listInfo.current.isLoading = false - // setIsLoading(false) - if (listInfo.current.isLoadError) { - listInfo.current.isLoadError = false - setIsLoadError(false) - } - return commentInfo - }).catch(err => { - console.log(err) - if (err.message != '取消请求') { - listInfo.current.isLoading = false - // setIsLoading(false) - listInfo.current.isLoadError = true - setIsLoadError(true) - } - return Promise.reject(err) - }) - } - const handleListLoadMore = useCallback(() => { - if (listInfo.current.isLoading || listInfo.current.isEnd) return - const page = listInfo.current.page + 1 - handleGetComment(musicInfo, page).then(({ comments }) => { - let isEnd = page >= listInfo.current.maxPage - if (listInfo.current.isEnd != isEnd) { - listInfo.current.isEnd = isEnd - setIsEnd(isEnd) - } - setCommentList(commentList => { - return filterList([...commentList, ...comments]) - }) - }) - }, [musicInfo]) - - const handleListRefresh = useCallback(() => { - setIsListRefreshing(true) - handleGetComment(musicInfo, 1).then(({ comments, maxPage, total }) => { - listInfo.current.total = total - listInfo.current.maxPage = maxPage - setTotal(total) - let isEnd = maxPage === 1 - if (listInfo.current.isEnd != isEnd) { - listInfo.current.isEnd = isEnd - setIsEnd(isEnd) - } - setCommentList(filterList(comments)) - }).finally(() => { - setIsListRefreshing(false) - }) - }, [musicInfo, setTotal]) - - const handleShowComment = useCallback(musicInfo => { - listInfo.current.page = 1 - listInfo.current.total = 0 - listInfo.current.maxPage = 1 - listInfo.current.isEnd = false - listInfo.current.isLoading = false - listInfo.current.isLoadError = false - setCommentList([]) - if (!musicInfo.songmid || !music[musicInfo.source]?.comment) return setIsEnd(true) - handleGetComment(musicInfo, 1).then(({ comments, maxPage, total }) => { - listInfo.current.total = total - listInfo.current.maxPage = maxPage - setTotal(total) - let isEnd = maxPage === 1 - if (listInfo.current.isEnd != isEnd) { - listInfo.current.isEnd = isEnd - setIsEnd(isEnd) - } - setCommentList(filterList(comments)) - }) - }, []) - - useEffect(() => { - handleShowComment(musicInfo) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [handleShowComment, musicInfo.songmid]) - - - const footerStatus = isEnd - ? 'list_end' - : isLoadError - ? 'list_error' - : 'list_loading' - - const handleRenderItem = ({ item }) => { - return ( - <CommentFloor comment={item} /> - ) - } - - const refreshControl = useMemo(() => ( - <RefreshControl - colors={[theme.secondary]} - progressBackgroundColor={theme.primary} - refreshing={isListRefreshing} - onRefresh={handleListRefresh} /> - ), [isListRefreshing, handleListRefresh, theme]) - - return ( - <FlatList - data={commentList} - renderItem={handleRenderItem} - keyExtractor={item => item.id} - style={styles.container} - ref={scrollViewRef} - onEndReached={handleListLoadMore} - onEndReachedThreshold={0.6} - refreshControl={refreshControl} - ListFooterComponent={ - footerStatus ? <View style={{ alignItems: 'center', padding: 10 }}><Text style={{ color: theme.normal30 }}>{t(footerStatus)}</Text></View> : null - } - // Fix Text in FlatList is not selectable on Android - // https://github.com/facebook/react-native/issues/26264#issuecomment-559986861 - removeClippedSubviews={false} - maxToRenderPerBatch={8} - updateCellsBatchingPeriod={80} - windowSize={16} - /> - ) -}) - -const styles = StyleSheet.create({ - container: { - flex: 1, - paddingLeft: 15, - paddingRight: 15, - // backgroundColor: 'rgba(0,0,0,0.1)', - }, - space: { - paddingTop: '80%', - }, - line: { - paddingTop: 8, - paddingBottom: 8, - // opacity: 0, - }, - lineText: { - // textAlign: 'center', - fontSize: 16, - lineHeight: 20, - // paddingTop: 5, - // paddingBottom: 5, - // opacity: 0, - }, - lineTranslationText: { - textAlign: 'center', - fontSize: 13, - lineHeight: 17, - paddingTop: 5, - // paddingBottom: 5, - }, -}) diff --git a/src/screens/Comment/CommentHot.tsx b/src/screens/Comment/CommentHot.tsx new file mode 100644 index 000000000..c4ba8c7a6 --- /dev/null +++ b/src/screens/Comment/CommentHot.tsx @@ -0,0 +1,103 @@ +import React, { useEffect, useRef } from 'react' +import { filterList, getHotComment } from './utils' +import music from '@/utils/musicSdk' +import List, { ListType } from './components/List' +const limit = 15 + +export default ({ musicInfo, onUpdateTotal }: { + musicInfo: LX.Music.MusicInfoOnline + onUpdateTotal: (total: number) => void +}) => { + // const [isLoading, setIsLoading] = useState(false) + const listRef = useRef<ListType>(null) + const listInfo = useRef({ page: 1, total: 0, maxPage: 1, isEnd: false, isLoading: false, isLoadError: false }) + const handleGetComment = async(musicInfo: LX.Music.MusicInfoOnline, page: number) => { + // setIsLoading(true) + listInfo.current.isLoading = true + return getHotComment(musicInfo, page, limit).then(commentInfo => { + listInfo.current.page = page + listInfo.current.isLoading = false + // setIsLoading(false) + if (listInfo.current.isLoadError) { + listInfo.current.isLoadError = false + } + return commentInfo + }).catch(async err => { + console.log(err) + if (err.message != '取消请求') { + listInfo.current.isLoading = false + // setIsLoading(false) + listInfo.current.isLoadError = true + } + throw err + }) + } + const updateStatus = () => { + if (listInfo.current.isLoadError) { + listRef.current?.setStatus('error') + } else if (listInfo.current.isEnd) { + listRef.current?.setStatus('end') + } else if (!listInfo.current.isLoading) { + listRef.current?.setStatus('idle') + } + } + const handleListLoadMore = () => { + if (listInfo.current.isLoading || listInfo.current.isEnd) return + const page = listInfo.current.page + 1 + listRef.current?.setStatus('loading') + void handleGetComment(musicInfo, page).then(({ comments }) => { + let isEnd = page >= listInfo.current.maxPage + if (listInfo.current.isEnd != isEnd) listInfo.current.isEnd = isEnd + listRef.current?.setList(filterList([...listRef.current.getList(), ...comments])) + }).finally(updateStatus) + } + + const handleListRefresh = () => { + listRef.current?.setStatus('refreshing') + void handleGetComment(musicInfo, 1).then(({ comments, maxPage, total }) => { + listInfo.current.total = total + listInfo.current.maxPage = maxPage + onUpdateTotal(total) + let isEnd = maxPage === 1 + if (listInfo.current.isEnd != isEnd) listInfo.current.isEnd = isEnd + listRef.current?.setList(filterList(comments)) + }).finally(updateStatus) + } + + const handleShowComment = (musicInfo: LX.Music.MusicInfoOnline) => { + if (!musicInfo.id || !music[musicInfo.source].comment) return + listInfo.current.page = 1 + listInfo.current.total = 0 + listInfo.current.maxPage = 1 + listInfo.current.isEnd = false + listInfo.current.isLoading = false + listInfo.current.isLoadError = false + listRef.current?.setList([]) + listRef.current?.setStatus('loading') + void handleGetComment(musicInfo, 1).then(({ comments, maxPage, total }) => { + listInfo.current.total = total + listInfo.current.maxPage = maxPage + onUpdateTotal(total) + let isEnd = maxPage === 1 + if (listInfo.current.isEnd != isEnd) listInfo.current.isEnd = isEnd + setTimeout(() => { + listRef.current?.setList(filterList(comments)) + setTimeout(updateStatus, 300) + }, 300) + }) + } + + useEffect(() => { + handleShowComment(musicInfo) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [musicInfo.id]) + + + return ( + <List + ref={listRef} + onLoadMore={handleListLoadMore} + onRefresh={handleListRefresh} + /> + ) +} diff --git a/src/screens/Comment/CommentNew.js b/src/screens/Comment/CommentNew.js deleted file mode 100644 index 6170b283d..000000000 --- a/src/screens/Comment/CommentNew.js +++ /dev/null @@ -1,196 +0,0 @@ -import React, { memo, useState, useMemo, useCallback, useEffect, useRef } from 'react' -import { View, Text, StyleSheet, FlatList, RefreshControl } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import music from '@/utils/music' -import CommentFloor from './components/CommentFloor' -import { useTranslation } from '@/plugins/i18n' -const limit = 15 - -const getComment = async(musicInfo, page, limit, retryNum = 0) => { - let resp - try { - resp = await music[musicInfo.source].comment.getComment(musicInfo, page, limit) - } catch (error) { - console.log(error.message) - if (error.message == '取消请求' || ++retryNum > 2) throw error - resp = await getComment(musicInfo, page, limit, retryNum) - } - return resp -} -const filterList = list => { - let keys = [] - return list.filter(c => { - let id = String(c.id) - if (keys.includes(id)) return false - keys.push(id) - return true - }) -} - -export default memo(({ musicInfo, setTotal }) => { - const [isListRefreshing, setIsListRefreshing] = useState(false) - const [isLoadError, setIsLoadError] = useState(false) - // const [isLoading, setIsLoading] = useState(false) - const [isEnd, setIsEnd] = useState(false) - const [commentList, setCommentList] = useState([]) - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - const scrollViewRef = useRef() - const listInfo = useRef({ page: 1, total: 0, maxPage: 1, isEnd: false, isLoading: false, isLoadError: false }) - const handleGetComment = (musicInfo, page) => { - // setIsLoading(true) - listInfo.current.isLoading = true - return getComment(musicInfo, page, limit).then(commentInfo => { - listInfo.current.page = page - listInfo.current.isLoading = false - // setIsLoading(false) - if (listInfo.current.isLoadError) { - listInfo.current.isLoadError = false - setIsLoadError(false) - } - return commentInfo - }).catch(err => { - console.log(err) - if (err.message != '取消请求') { - listInfo.current.isLoading = false - // setIsLoading(false) - listInfo.current.isLoadError = true - setIsLoadError(true) - } - return Promise.reject(err) - }) - } - const handleListLoadMore = useCallback(() => { - if (listInfo.current.isLoading || listInfo.current.isEnd) return - const page = listInfo.current.page + 1 - handleGetComment(musicInfo, page).then(({ comments }) => { - let isEnd = page >= listInfo.current.maxPage - if (listInfo.current.isEnd != isEnd) { - listInfo.current.isEnd = isEnd - setIsEnd(isEnd) - } - setCommentList(commentList => { - return filterList([...commentList, ...comments]) - }) - }) - }, [musicInfo]) - - const handleListRefresh = useCallback(() => { - setIsListRefreshing(true) - handleGetComment(musicInfo, 1).then(({ comments, maxPage, total }) => { - listInfo.current.total = total - listInfo.current.maxPage = maxPage - setTotal(total) - let isEnd = maxPage === 1 - if (listInfo.current.isEnd != isEnd) { - listInfo.current.isEnd = isEnd - setIsEnd(isEnd) - } - setCommentList(filterList(comments)) - }).finally(() => { - setIsListRefreshing(false) - }) - }, [musicInfo, setTotal]) - - const handleShowComment = useCallback(musicInfo => { - listInfo.current.page = 1 - listInfo.current.total = 0 - listInfo.current.maxPage = 1 - listInfo.current.isEnd = false - listInfo.current.isLoading = false - listInfo.current.isLoadError = false - setCommentList([]) - if (!musicInfo.songmid || !music[musicInfo.source]?.comment) return setIsEnd(true) - handleGetComment(musicInfo, 1).then(({ comments, maxPage, total }) => { - listInfo.current.total = total - listInfo.current.maxPage = maxPage - setTotal(total) - let isEnd = maxPage === 1 - if (listInfo.current.isEnd != isEnd) { - listInfo.current.isEnd = isEnd - setIsEnd(isEnd) - } - setCommentList(filterList(comments)) - }) - }, []) - - useEffect(() => { - handleShowComment(musicInfo) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [handleShowComment, musicInfo.songmid]) - - - const footerStatus = isEnd - ? 'list_end' - : isLoadError - ? 'list_error' - : 'list_loading' - - const handleRenderItem = ({ item }) => { - return ( - <CommentFloor comment={item} /> - ) - } - - const refreshControl = useMemo(() => ( - <RefreshControl - colors={[theme.secondary]} - progressBackgroundColor={theme.primary} - refreshing={isListRefreshing} - onRefresh={handleListRefresh} /> - ), [isListRefreshing, handleListRefresh, theme]) - - return ( - <FlatList - data={commentList} - renderItem={handleRenderItem} - keyExtractor={item => item.id} - style={styles.container} - ref={scrollViewRef} - onEndReached={handleListLoadMore} - onEndReachedThreshold={0.6} - refreshControl={refreshControl} - ListFooterComponent={ - footerStatus ? <View style={{ alignItems: 'center', padding: 10 }}><Text style={{ color: theme.normal30 }}>{t(footerStatus)}</Text></View> : null - } - // Fix Text in FlatList is not selectable on Android - // https://github.com/facebook/react-native/issues/26264#issuecomment-559986861 - removeClippedSubviews={false} - maxToRenderPerBatch={8} - updateCellsBatchingPeriod={80} - windowSize={16} - /> - ) -}) - -const styles = StyleSheet.create({ - container: { - flex: 1, - paddingLeft: 15, - paddingRight: 15, - // backgroundColor: 'rgba(0,0,0,0.1)', - }, - space: { - paddingTop: '80%', - }, - line: { - paddingTop: 8, - paddingBottom: 8, - // opacity: 0, - }, - lineText: { - // textAlign: 'center', - fontSize: 16, - lineHeight: 20, - // paddingTop: 5, - // paddingBottom: 5, - // opacity: 0, - }, - lineTranslationText: { - textAlign: 'center', - fontSize: 13, - lineHeight: 17, - paddingTop: 5, - // paddingBottom: 5, - }, -}) diff --git a/src/screens/Comment/CommentNew.tsx b/src/screens/Comment/CommentNew.tsx new file mode 100644 index 000000000..9130b652b --- /dev/null +++ b/src/screens/Comment/CommentNew.tsx @@ -0,0 +1,104 @@ +import React, { useEffect, useRef } from 'react' +import { filterList, getNewComment } from './utils' +import music from '@/utils/musicSdk' +import List, { ListType } from './components/List' +const limit = 15 + +export default ({ musicInfo, onUpdateTotal }: { + musicInfo: LX.Music.MusicInfoOnline + onUpdateTotal: (total: number) => void +}) => { + // const [isLoading, setIsLoading] = useState(false) + const listRef = useRef<ListType>(null) + const listInfo = useRef({ page: 1, total: 0, maxPage: 1, isEnd: false, isLoading: false, isLoadError: false }) + const handleGetComment = async(musicInfo: LX.Music.MusicInfoOnline, page: number) => { + // setIsLoading(true) + listInfo.current.isLoading = true + return getNewComment(musicInfo, page, limit).then(commentInfo => { + listInfo.current.page = page + listInfo.current.isLoading = false + // setIsLoading(false) + if (listInfo.current.isLoadError) { + listInfo.current.isLoadError = false + } + return commentInfo + }).catch(async err => { + console.log(err) + if (err.message != '取消请求') { + listInfo.current.isLoading = false + // setIsLoading(false) + listInfo.current.isLoadError = true + } + throw err + }) + } + const updateStatus = () => { + if (listInfo.current.isLoadError) { + listRef.current?.setStatus('error') + } else if (listInfo.current.isEnd) { + listRef.current?.setStatus('end') + } else if (!listInfo.current.isLoading) { + listRef.current?.setStatus('idle') + } + } + const handleListLoadMore = () => { + console.log('load') + if (listInfo.current.isLoading || listInfo.current.isEnd) return + const page = listInfo.current.page + 1 + listRef.current?.setStatus('loading') + void handleGetComment(musicInfo, page).then(({ comments }) => { + let isEnd = page >= listInfo.current.maxPage + if (listInfo.current.isEnd != isEnd) listInfo.current.isEnd = isEnd + listRef.current?.setList(filterList([...listRef.current.getList(), ...comments])) + }).finally(updateStatus) + } + + const handleListRefresh = () => { + listRef.current?.setStatus('refreshing') + void handleGetComment(musicInfo, 1).then(({ comments, maxPage, total }) => { + listInfo.current.total = total + listInfo.current.maxPage = maxPage + onUpdateTotal(total) + let isEnd = maxPage === 1 + if (listInfo.current.isEnd != isEnd) listInfo.current.isEnd = isEnd + listRef.current?.setList(filterList(comments)) + }).finally(updateStatus) + } + + const handleShowComment = (musicInfo: LX.Music.MusicInfoOnline) => { + if (!musicInfo.id || !music[musicInfo.source].comment) return + listInfo.current.page = 1 + listInfo.current.total = 0 + listInfo.current.maxPage = 1 + listInfo.current.isEnd = false + listInfo.current.isLoading = false + listInfo.current.isLoadError = false + listRef.current?.setList([]) + listRef.current?.setStatus('loading') + void handleGetComment(musicInfo, 1).then(({ comments, maxPage, total }) => { + listInfo.current.total = total + listInfo.current.maxPage = maxPage + onUpdateTotal(total) + let isEnd = maxPage === 1 + if (listInfo.current.isEnd != isEnd) listInfo.current.isEnd = isEnd + setTimeout(() => { + listRef.current?.setList(filterList(comments)) + setTimeout(updateStatus, 300) + }, 300) + }) + } + + useEffect(() => { + handleShowComment(musicInfo) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [musicInfo.id]) + + + return ( + <List + ref={listRef} + onLoadMore={handleListLoadMore} + onRefresh={handleListRefresh} + /> + ) +} diff --git a/src/screens/Comment/components/CommentFloor.js b/src/screens/Comment/components/CommentFloor.js deleted file mode 100644 index 2436c9b56..000000000 --- a/src/screens/Comment/components/CommentFloor.js +++ /dev/null @@ -1,129 +0,0 @@ -import React, { memo, useState, useMemo, useCallback } from 'react' -import { View, Text, StyleSheet, Image } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import { BorderWidths } from '@/theme' -import defaultUser from '@/resources/images/defaultUser.jpg' -import { Icon } from '@/components/common/Icon' - -const GAP = 12 - -const CommentFloor = memo(({ comment, isLast }) => { - const theme = useGetter('common', 'theme') - const [isAvatarError, setIsAvatarError] = useState(false) - - const handleAvatarError = useCallback(() => { - setIsAvatarError(true) - }, []) - - const replyComments = useMemo(() => { - if (!comment.reply || !comment.reply.length) return null - const endIndex = comment.reply.length - 1 - return ( - <View style={{ ...styles.replyFloor, borderTopColor: theme.borderColor }}> - { - comment.reply.map((c, index) => ( - <CommentFloor comment={c} isLast={index === endIndex} key={`${comment.id}_${c.id}`} /> - )) - } - </View> - ) - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - const likedCount = useMemo(() => { - if (comment.likedCount == null) return null - return ( - <View style={styles.like}> - <Icon name="thumbs-up" style={{ color: theme.normal50 }} size={12} /> - <Text style={{ ...styles.likedCount, color: theme.normal50 }}>{comment.likedCount}</Text> - </View> - ) - }, []) - - return ( - <View style={{ ...styles.container, borderBottomColor: theme.borderColor, borderBottomWidth: isLast ? 0 : BorderWidths.normal, paddingBottom: isLast ? 0 : GAP }}> - <View style={styles.comment}> - <View style={styles.left}> - <Image source={comment.avatar && !isAvatarError ? { uri: comment.avatar } : defaultUser} onError={handleAvatarError} progressiveRenderingEnabled={true} borderRadius={4} style={styles.avatar} /> - </View> - <View style={styles.right}> - <View style={styles.info}> - <View> - <Text selectable numberOfLines={1} style={{ ...styles.userName, color: theme.normal }}>{comment.userName}</Text> - <Text numberOfLines={1} style={{ ...styles.time, color: theme.normal30 }}>{comment.timeStr}</Text> - </View> - {likedCount} - </View> - <Text selectable style={{ ...styles.text, color: theme.normal }}>{comment.text}</Text> - </View> - </View> - {replyComments} - </View> - ) -}) - -const styles = StyleSheet.create({ - container: { - flex: 1, - // backgroundColor: 'rgba(0,0,0,0.1)', - marginTop: GAP, - paddingBottom: GAP, - borderBottomWidth: BorderWidths.normal, - borderStyle: 'dashed', - }, - comment: { - flex: 1, - // backgroundColor: 'rgba(0,0,0,0.1)', - flexDirection: 'row', - }, - avatar: { - width: 36, - height: 36, - }, - right: { - flex: 1, - paddingLeft: 10, - }, - info: { - flex: 1, - flexDirection: 'row', - // backgroundColor: 'rgba(0,0,0,0.1)', - justifyContent: 'space-between', - alignItems: 'center', - }, - userName: { - fontSize: 14, - // lineHeight: 16, - }, - time: { - fontSize: 12, - marginTop: 2, - }, - like: { - flexDirection: 'row', - alignItems: 'center', - }, - likedCount: { - marginLeft: 2, - fontSize: 12, - }, - text: { - // textAlign: 'center', - marginTop: 5, - fontSize: 14, - lineHeight: 20, - // paddingTop: 5, - // paddingBottom: 5, - // opacity: 0, - }, - replyFloor: { - marginTop: GAP, - marginLeft: 20, - borderTopWidth: BorderWidths.normal, - // backgroundColor: 'rgba(0,0,0,0.1)', - borderStyle: 'dashed', - }, -}) - -export default CommentFloor diff --git a/src/screens/Comment/components/CommentFloor.tsx b/src/screens/Comment/components/CommentFloor.tsx new file mode 100644 index 000000000..fc0e4e9be --- /dev/null +++ b/src/screens/Comment/components/CommentFloor.tsx @@ -0,0 +1,161 @@ +import React, { memo, useState, useMemo, useCallback } from 'react' +import { View, Image } from 'react-native' +import { BorderWidths } from '@/theme' +import { Icon } from '@/components/common/Icon' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { type Comment } from '../utils' +import Text from '@/components/common/Text' +import { scaleSizeH, scaleSizeW } from '@/utils/pixelRatio' +import ScaledImage from '@/components/common/ScaledImage' +import { useLayout } from '@/utils/hooks' +// eslint-disable-next-line @typescript-eslint/no-var-requires +const defaultUser = require('@/resources/images/defaultUser.jpg') + +const GAP = 12 +const avatarWidth = scaleSizeW(36) +const MAX_IMAGE_HEIGHT = scaleSizeH(260) + +const CommentFloor = memo(({ comment, isLast }: { + comment: Comment + isLast?: boolean +}) => { + const theme = useTheme() + const [isAvatarError, setIsAvatarError] = useState(false) + const { onLayout, width } = useLayout() + + const handleAvatarError = useCallback(() => { + setIsAvatarError(true) + }, []) + + const replyComments = useMemo(() => { + if (!comment.reply?.length) return null + const endIndex = comment.reply.length - 1 + return ( + <View style={{ ...styles.replyFloor, borderTopColor: theme['c-list-header-border-bottom'] }}> + { + comment.reply.map((c, index) => ( + <CommentFloor comment={c} isLast={index === endIndex} key={`${comment.id}_${c.id}`} /> + )) + } + </View> + ) + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + const likedCount = useMemo(() => { + if (comment.likedCount == null) return null + return ( + <View style={styles.like}> + <Icon name="thumbs-up" style={{ color: theme['c-450'] }} size={12} /> + <Text style={styles.likedCount} size={12} color={ theme['c-450'] }>{comment.likedCount}</Text> + </View> + ) + }, []) + + return ( + <View style={{ ...styles.container, borderBottomColor: theme['c-list-header-border-bottom'], borderBottomWidth: isLast ? 0 : BorderWidths.normal, paddingBottom: isLast ? 0 : GAP }}> + <View style={styles.comment}> + <View> + <Image + source={comment.avatar && !isAvatarError ? { uri: comment.avatar } : defaultUser} + onError={handleAvatarError} + progressiveRenderingEnabled={true} + borderRadius={4} + style={{ height: avatarWidth, width: avatarWidth }} /> + </View> + <View style={styles.right}> + <View style={styles.info}> + <View> + <Text selectable numberOfLines={1} size={14}> + {comment.userName} + </Text> + <View style={styles.metaInfo}> + <Text numberOfLines={1} size={12} color={theme['c-450']}>{comment.timeStr}</Text> + { comment.location ? <Text numberOfLines={1} style={styles.location} size={12} color={theme['c-450']}>{comment.location}</Text> : null } + </View> + </View> + {likedCount} + </View> + <Text selectable style={styles.text}>{comment.text}</Text> + { + comment.images?.length + ? ( + <View style={styles.images} onLayout={onLayout}> + { + comment.images.map((url, index) => <ScaledImage key={String(index)} uri={url} maxWidth={width} maxHeight={MAX_IMAGE_HEIGHT} />) + } + </View> + ) + : null + } + </View> + </View> + {replyComments} + </View> + ) +}) + +const styles = createStyle({ + container: { + flex: 1, + // backgroundColor: 'rgba(0,0,0,0.1)', + marginTop: GAP, + paddingBottom: GAP, + borderBottomWidth: BorderWidths.normal, + borderStyle: 'dashed', + }, + comment: { + flex: 1, + // backgroundColor: 'rgba(0,0,0,0.1)', + flexDirection: 'row', + }, + right: { + flex: 1, + paddingLeft: 10, + }, + info: { + flex: 1, + flexDirection: 'row', + // backgroundColor: 'rgba(0,0,0,0.1)', + justifyContent: 'space-between', + alignItems: 'center', + }, + metaInfo: { + marginTop: 2, + flexDirection: 'row', + }, + location: { + marginLeft: 10, + }, + like: { + flexDirection: 'row', + alignItems: 'center', + }, + likedCount: { + marginLeft: 2, + }, + text: { + // textAlign: 'center', + marginTop: 5, + lineHeight: 19, + // paddingTop: 5, + // paddingBottom: 5, + // opacity: 0, + }, + images: { + paddingTop: 5, + width: '100%', + flexDirection: 'row', + }, + replyFloor: { + marginTop: GAP, + marginLeft: 20, + borderTopWidth: BorderWidths.normal, + // backgroundColor: 'rgba(0,0,0,0.1)', + borderStyle: 'dashed', + }, +}) + +export default CommentFloor diff --git a/src/screens/Comment/components/Header.js b/src/screens/Comment/components/Header.js deleted file mode 100644 index cab77c962..000000000 --- a/src/screens/Comment/components/Header.js +++ /dev/null @@ -1,67 +0,0 @@ -import React, { memo } from 'react' - -import { View, StyleSheet, TouchableOpacity, Text } from 'react-native' - -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import { pop } from '@/navigation' -import { useTranslation } from '@/plugins/i18n' -// import { AppColors } from '@/theme' -import StatusBar from '@/components/common/StatusBar' - - -export default memo(({ musicInfo }) => { - const theme = useGetter('common', 'theme') - const componentIds = useGetter('common', 'componentIds') - const { t } = useTranslation() - - const back = () => { - pop(componentIds.comment) - } - - return ( - <View style={{ ...styles.header, backgroundColor: theme.primary }} nativeID="header"> - <StatusBar /> - <View style={{ ...styles.container }}> - <TouchableOpacity onPress={back} style={{ ...styles.button }}> - <Icon name="chevron-left" style={{ color: theme.normal }} size={24} /> - </TouchableOpacity> - <Text numberOfLines={1} style={{ ...styles.title, color: theme.normal }}>{t('comment_title', { name: musicInfo.name, singer: musicInfo.singer })}</Text> - {/* <TouchableOpacity onPress={back} style={{ ...styles.button }}> - <Icon name="autorenew" style={{ color: theme.normal }} size={24} /> - </TouchableOpacity> */} - </View> - </View> - ) -}) - - -const styles = StyleSheet.create({ - header: { - height: 40 + StatusBar.currentHeight, - paddingTop: StatusBar.currentHeight, - }, - container: { - flexDirection: 'row', - // justifyContent: 'center', - height: 40, - paddingRight: 40, - }, - button: { - // paddingLeft: 10, - // paddingRight: 10, - width: 40, - justifyContent: 'center', - alignItems: 'center', - }, - title: { - flex: 1, - lineHeight: 40, - textAlign: 'center', - fontSize: 16, - }, - icon: { - paddingLeft: 4, - paddingRight: 4, - }, -}) diff --git a/src/screens/Comment/components/Header.tsx b/src/screens/Comment/components/Header.tsx new file mode 100644 index 000000000..2a0d4067b --- /dev/null +++ b/src/screens/Comment/components/Header.tsx @@ -0,0 +1,67 @@ +import React, { memo } from 'react' +import { View, TouchableOpacity } from 'react-native' + +import { Icon } from '@/components/common/Icon' +import { pop } from '@/navigation' +// import { AppColors } from '@/theme' +import StatusBar from '@/components/common/StatusBar' +import { useComponentIds } from '@/store/common/hook' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' +import { HEADER_HEIGHT as _HEADER_HEIGHT } from '@/config/constant' +import { scaleSizeH } from '@/utils/pixelRatio' + +const HEADER_HEIGHT = scaleSizeH(_HEADER_HEIGHT) + +export default memo(({ musicInfo }: { + musicInfo: LX.Music.MusicInfo +}) => { + const componentIds = useComponentIds() + const t = useI18n() + + const back = () => { + void pop(componentIds.comment as string) + } + + return ( + <View style={{ height: HEADER_HEIGHT + StatusBar.currentHeight, paddingTop: StatusBar.currentHeight }}> + <StatusBar /> + <View style={{ ...styles.container }}> + <TouchableOpacity onPress={back} style={{ ...styles.button, width: HEADER_HEIGHT }}> + <Icon name="chevron-left" size={18} /> + </TouchableOpacity> + <Text numberOfLines={1} size={16} style={styles.title}>{t('comment_title', { name: musicInfo.name, singer: musicInfo.singer })}</Text> + {/* <TouchableOpacity onPress={back} style={{ ...styles.button }}> + <Icon name="available_updates" style={{ color: theme.normal }} size={24} /> + </TouchableOpacity> */} + </View> + </View> + ) +}) + + +const styles = createStyle({ + container: { + flexDirection: 'row', + alignItems: 'center', + height: '100%', + paddingRight: 40, + // backgroundColor: 'rgba(255, 255, 255, 0.5)', + }, + button: { + // paddingLeft: 10, + // paddingRight: 10, + width: '100%', + justifyContent: 'center', + alignItems: 'center', + }, + title: { + flex: 1, + textAlign: 'center', + }, + icon: { + paddingLeft: 4, + paddingRight: 4, + }, +}) diff --git a/src/screens/Comment/components/List.tsx b/src/screens/Comment/components/List.tsx new file mode 100644 index 000000000..ea2b71112 --- /dev/null +++ b/src/screens/Comment/components/List.tsx @@ -0,0 +1,142 @@ +import React, { useMemo, useRef, useState, forwardRef, useImperativeHandle } from 'react' +import { FlatList, type FlatListProps, RefreshControl, View } from 'react-native' + +// import { useMusicList } from '@/store/list/hook' +import CommentFloor from './CommentFloor' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { type Comment } from '../utils' +import { useI18n } from '@/lang' +import Text from '@/components/common/Text' + +type FlatListType = FlatListProps<Comment> + +export interface ListProps { + onRefresh: () => void + onLoadMore: () => void +} +export interface ListType { + setList: (list: Comment[]) => void + getList: () => Comment[] + setStatus: (val: Status) => void +} +export type Status = 'loading' | 'refreshing' | 'end' | 'error' | 'idle' + +const List = forwardRef<ListType, ListProps>(({ + onRefresh, + onLoadMore, +}, ref) => { + // const t = useI18n() + const theme = useTheme() + const flatListRef = useRef<FlatList>(null) + const [currentList, setList] = useState<Comment[]>([]) + const [status, setStatus] = useState<Status>('idle') + // const currentListIdRef = useRef('') + // console.log('render comment list') + + useImperativeHandle(ref, () => ({ + setList(list) { + setList(list) + }, + getList() { + return currentList + }, + setStatus(val) { + setStatus(val) + }, + })) + + const handleLoadMore = () => { + switch (status) { + case 'loading': + case 'refreshing': return + } + onLoadMore() + } + + const renderItem: FlatListType['renderItem'] = ({ item }) => <CommentFloor comment={item} /> + + const getkey: FlatListType['keyExtractor'] = item => item.id + + const refreshControl = useMemo(() => ( + <RefreshControl + colors={[theme['c-primary']]} + // progressBackgroundColor={theme.primary} + refreshing={status == 'refreshing'} + onRefresh={onRefresh} /> + ), [status, onRefresh, theme]) + const footerComponent = useMemo(() => { + let label: FooterLabel + switch (status) { + case 'refreshing': return null + case 'idle': + case 'loading': + label = 'list_loading' + break + case 'end': + label = 'list_end' + break + case 'error': + label = 'list_error' + break + } + return <Footer label={label} onLoadMore={onLoadMore} /> + }, [onLoadMore, status]) + + return ( + <FlatList + ref={flatListRef} + style={styles.list} + data={currentList} + onEndReachedThreshold={0.6} + maxToRenderPerBatch={4} + // updateCellsBatchingPeriod={80} + windowSize={8} + removeClippedSubviews={true} + initialNumToRender={12} + renderItem={renderItem} + keyExtractor={getkey} + // onRefresh={onRefresh} + // refreshing={refreshing} + onEndReached={handleLoadMore} + refreshControl={refreshControl} + ListFooterComponent={footerComponent} + /> + ) +}) + +type FooterLabel = 'list_loading' | 'list_end' | 'list_error' +const Footer = ({ label, onLoadMore }: { + label: FooterLabel + onLoadMore: () => void +}) => { + const theme = useTheme() + const t = useI18n() + const handlePress = () => { + if (label != 'list_error') return + onLoadMore() + } + return ( + <View> + <Text onPress={handlePress} style={styles.footer} color={theme['c-font-label']}>{t(label)}</Text> + </View> + ) +} + +const styles = createStyle({ + container: { + flex: 1, + }, + list: { + flexGrow: 1, + flexShrink: 1, + paddingLeft: 15, + paddingRight: 15, + }, + footer: { + textAlign: 'center', + padding: 10, + }, +}) + +export default List diff --git a/src/screens/Comment/index.js b/src/screens/Comment/index.js deleted file mode 100644 index ba950d32e..000000000 --- a/src/screens/Comment/index.js +++ /dev/null @@ -1,167 +0,0 @@ -import React, { memo, useMemo, useCallback, useEffect, useRef, useState } from 'react' -import { View, Text, StyleSheet, TouchableOpacity } from 'react-native' -import PagerView from 'react-native-pager-view' -import Header from './components/Header' -import { useTranslation } from '@/plugins/i18n' -import { useGetter, useDispatch } from '@/store' -import { Icon } from '@/components/common/Icon' -import CommentHot from './CommentHot' -import CommentNew from './CommentNew' -import { toast } from '@/utils/tools' - -const HeaderItem = ({ id, label, isActive, onPress }) => { - const theme = useGetter('common', 'theme') - // console.log(theme) - const components = useMemo(() => ( - <TouchableOpacity style={styles.btn} onPress={() => !isActive && onPress(id)}> - <Text style={{ ...styles.btnText, color: isActive ? theme.secondary : theme.normal10 }}>{label}</Text> - </TouchableOpacity> - ), [isActive, theme, label, onPress, id]) - - return components -} - -const HotCommentPage = ({ activeId, musicInfo, setTotal }) => { - const initedRef = useRef(false) - const comment = useMemo(() => <CommentHot musicInfo={musicInfo} setTotal={setTotal} />, [musicInfo, setTotal]) - switch (activeId) { - // case 3: - case 'hot': - if (!initedRef.current) initedRef.current = true - return comment - default: - return initedRef.current ? comment : null - } - // return activeId == 0 || activeId == 1 ? setting : null -} -const NewCommentPage = ({ activeId, musicInfo, setTotal }) => { - const initedRef = useRef(false) - const comment = useMemo(() => <CommentNew musicInfo={musicInfo} setTotal={setTotal} />, [musicInfo, setTotal]) - switch (activeId) { - // case 3: - case 'new': - if (!initedRef.current) initedRef.current = true - return comment - default: - return initedRef.current ? comment : null - } - // return activeId == 0 || activeId == 1 ? setting : null -} - -export default memo(({ componentId, animated }) => { - const pagerViewRef = useRef() - const [activeId, setActiveId] = useState('hot') - const [musicInfo, setMusicInfo] = useState({}) - const { t } = useTranslation() - const theme = useGetter('common', 'theme') - const [total, setTotal] = useState({ hot: 0, new: 0 }) - const setComponentId = useDispatch('common', 'setComponentId') - - useEffect(() => { - setComponentId({ name: 'comment', id: componentId }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - const tabs = useMemo(() => { - return [ - { id: 'hot', label: t('comment_tab_hot', { total: total.hot ? `(${total.hot})` : '' }) }, - { id: 'new', label: t('comment_tab_new', { total: total.new ? `(${total.new})` : '' }) }, - ] - }, [total, t]) - - const toggleTab = useCallback(id => { - setActiveId(id) - pagerViewRef.current.setPage(tabs.findIndex(tab => tab.id == id)) - }, [tabs]) - - const onPageSelected = useCallback(({ nativeEvent }) => { - setActiveId(tabs[nativeEvent.position].id) - }, [tabs]) - - const refreshComment = useCallback(() => { - setMusicInfo(musicInfo => { - if (musicInfo.songmid == global.playInfo.currentPlayMusicInfo.songmid) { - toast(t('comment_refresh', { name: musicInfo.name })) - } - return global.playInfo.currentPlayMusicInfo - }) - }, [t]) - - const setHotTotal = useCallback(total => { - setTotal(totalInfo => ({ ...totalInfo, hot: total })) - }, []) - const setNewTotal = useCallback(total => { - setTotal(totalInfo => ({ ...totalInfo, new: total })) - }, []) - - useEffect(() => { - setMusicInfo(global.playInfo.currentPlayMusicInfo) - }, []) - - return ( - <View style={{ flex: 1 }}> - <Header musicInfo={musicInfo} /> - <View style={{ ...styles.container, backgroundColor: theme.primary }}> - <View style={styles.tabHeader}> - <View style={styles.left}> - {tabs.map(({ id, label }) => <HeaderItem id={id} label={label} key={id} isActive={activeId == id} onPress={toggleTab} />)} - </View> - <View style={styles.right}> - <TouchableOpacity onPress={refreshComment} style={{ ...styles.button }}> - <Icon name="autorenew" style={{ color: theme.normal20 }} size={24} /> - </TouchableOpacity> - </View> - </View> - <PagerView - ref={pagerViewRef} - onPageSelected={onPageSelected} - // onPageScrollStateChanged={onPageScrollStateChanged} - style={styles.pagerView} - > - <View collapsable={false} style={styles.pageStyle}> - <HotCommentPage activeId={activeId} musicInfo={musicInfo} setTotal={setHotTotal} /> - </View> - <View collapsable={false} style={styles.pageStyle}> - <NewCommentPage activeId={activeId} musicInfo={musicInfo} setTotal={setNewTotal} /> - </View> - </PagerView> - </View> - </View> - ) -}) - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - tabHeader: { - flexDirection: 'row', - // paddingLeft: 10, - paddingRight: 10, - // justifyContent: 'center', - }, - left: { - flex: 1, - flexDirection: 'row', - paddingLeft: 5, - }, - btn: { - // flex: 1, - paddingLeft: 10, - paddingRight: 10, - backgroundColor: 'rgba(0,0,0,0)', - alignItems: 'center', - justifyContent: 'center', - height: 36, - }, - btnText: { - fontSize: 16, - // color: 'white', - }, - pagerView: { - flex: 1, - }, - pageStyle: { - overflow: 'hidden', - }, -}) diff --git a/src/screens/Comment/index.tsx b/src/screens/Comment/index.tsx new file mode 100644 index 000000000..3e2412974 --- /dev/null +++ b/src/screens/Comment/index.tsx @@ -0,0 +1,214 @@ +import React, { memo, useMemo, useEffect, useRef, useState, useCallback } from 'react' +import { View, TouchableOpacity } from 'react-native' +import PagerView, { type PagerViewOnPageSelectedEvent } from 'react-native-pager-view' +import Header from './components/Header' +import { Icon } from '@/components/common/Icon' +import CommentHot from './CommentHot' +import CommentNew from './CommentNew' +import { createStyle, toast } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import Text from '@/components/common/Text' +import { useI18n } from '@/lang' +import { COMPONENT_IDS } from '@/config/constant' +import { setComponentId } from '@/core/common' +import PageContent from '@/components/PageContent' +import playerState from '@/store/player/state' +import { scaleSizeH } from '@/utils/pixelRatio' +import { BorderWidths } from '@/theme' + +type ActiveId = 'hot' | 'new' + +const BAR_HEIGHT = scaleSizeH(34) + +const HeaderItem = ({ id, label, isActive, onPress }: { + id: ActiveId + label: string + isActive: boolean + onPress: (id: ActiveId) => void +}) => { + const theme = useTheme() + // console.log(theme) + const components = useMemo(() => ( + <TouchableOpacity style={styles.tabBtn} onPress={() => { !isActive && onPress(id) }}> + <Text color={isActive ? theme['c-primary-font-active'] : theme['c-font']}>{label}</Text> + </TouchableOpacity> + ), [isActive, theme, label, onPress, id]) + + return components +} + +const HotCommentPage = memo(({ activeId, musicInfo, onUpdateTotal }: { + activeId: ActiveId + musicInfo: LX.Music.MusicInfoOnline + onUpdateTotal: (total: number) => void +}) => { + const initedRef = useRef(false) + const comment = useMemo(() => <CommentHot musicInfo={musicInfo} onUpdateTotal={onUpdateTotal} />, [musicInfo, onUpdateTotal]) + switch (activeId) { + case 'hot': + if (!initedRef.current) initedRef.current = true + return comment + default: + return initedRef.current ? comment : null + } +}) + +const NewCommentPage = memo(({ activeId, musicInfo, onUpdateTotal }: { + activeId: ActiveId + musicInfo: LX.Music.MusicInfoOnline + onUpdateTotal: (total: number) => void +}) => { + const initedRef = useRef(false) + const comment = useMemo(() => <CommentNew musicInfo={musicInfo} onUpdateTotal={onUpdateTotal} />, [musicInfo, onUpdateTotal]) + switch (activeId) { + case 'new': + if (!initedRef.current) initedRef.current = true + return comment + default: + return initedRef.current ? comment : null + } +}) + +export default memo(({ componentId }: { + componentId: string +}) => { + const pagerViewRef = useRef<PagerView>(null) + const [activeId, setActiveId] = useState<ActiveId>('hot') + const [musicInfo, setMusicInfo] = useState<LX.Music.MusicInfo | null>(null) + const t = useI18n() + const theme = useTheme() + const [total, setTotal] = useState({ hot: 0, new: 0 }) + + useEffect(() => { + setComponentId(COMPONENT_IDS.comment, componentId) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + const tabs = useMemo(() => { + return [ + { id: 'hot', label: t('comment_tab_hot', { total: total.hot ? `(${total.hot})` : '' }) }, + { id: 'new', label: t('comment_tab_new', { total: total.new ? `(${total.new})` : '' }) }, + ] as const + }, [total, t]) + + const toggleTab = (id: ActiveId) => { + setActiveId(id) + pagerViewRef.current?.setPage(tabs.findIndex(tab => tab.id == id)) + } + + const onPageSelected = ({ nativeEvent }: PagerViewOnPageSelectedEvent) => { + setActiveId(tabs[nativeEvent.position].id) + } + + const refreshComment = () => { + if (!playerState.playMusicInfo.musicInfo) return + let playerMusicInfo = playerState.playMusicInfo.musicInfo + if ('progress' in playerMusicInfo) playerMusicInfo = playerMusicInfo.metadata.musicInfo + + if (musicInfo && musicInfo.id == playerMusicInfo.id) { + toast(t('comment_refresh', { name: musicInfo.name })) + return + } + setMusicInfo(playerMusicInfo) + } + + const setHotTotal = useCallback((total: number) => { + setTotal(totalInfo => ({ ...totalInfo, hot: total })) + }, []) + const setNewTotal = useCallback((total: number) => { + setTotal(totalInfo => ({ ...totalInfo, new: total })) + }, []) + + useEffect(() => { + if (!playerState.playMusicInfo.musicInfo) return + let playerMusicInfo = playerState.playMusicInfo.musicInfo + if ('progress' in playerMusicInfo) playerMusicInfo = playerMusicInfo.metadata.musicInfo + setMusicInfo(playerMusicInfo) + }, []) + + return ( + <PageContent> + { + musicInfo == null + ? null + : <> + <Header musicInfo={musicInfo} /> + { + musicInfo.source == 'local' + ? ( + <View style={{ ...styles.container, alignItems: 'center', justifyContent: 'center' }}> + <Text>{t('comment_not support')}</Text> + </View> + ) + : ( + <View style={styles.container}> + <View style={{ ...styles.tabHeader, borderBottomColor: theme['c-border-background'], height: BAR_HEIGHT }}> + <View style={styles.left}> + {tabs.map(({ id, label }) => <HeaderItem id={id} label={label} key={id} isActive={activeId == id} onPress={toggleTab} />)} + </View> + <View> + <TouchableOpacity onPress={refreshComment} style={{ ...styles.btn, width: BAR_HEIGHT }}> + <Icon name="available_updates" size={20} color={theme['c-600']} /> + </TouchableOpacity> + </View> + </View> + <PagerView + ref={pagerViewRef} + onPageSelected={onPageSelected} + // onPageScrollStateChanged={onPageScrollStateChanged} + style={styles.pagerView} + > + <View collapsable={false} style={styles.pageStyle}> + <HotCommentPage activeId={activeId} musicInfo={musicInfo} onUpdateTotal={setHotTotal} /> + </View> + <View collapsable={false} style={styles.pageStyle}> + <NewCommentPage activeId={activeId} musicInfo={musicInfo} onUpdateTotal={setNewTotal} /> + </View> + </PagerView> + </View> + ) + } + </> + } + + </PageContent> + ) +}) + +const styles = createStyle({ + container: { + flex: 1, + }, + tabHeader: { + flexDirection: 'row', + // paddingLeft: 10, + paddingRight: 10, + // justifyContent: 'center', + borderBottomWidth: BorderWidths.normal, + }, + left: { + flex: 1, + flexDirection: 'row', + paddingLeft: 5, + }, + tabBtn: { + // flex: 1, + paddingLeft: 10, + paddingRight: 10, + alignItems: 'center', + justifyContent: 'center', + height: '100%', + }, + btn: { + // flex: 1, + alignItems: 'center', + justifyContent: 'center', + height: '100%', + }, + pagerView: { + flex: 1, + }, + pageStyle: { + overflow: 'hidden', + }, +}) diff --git a/src/screens/Comment/utils.ts b/src/screens/Comment/utils.ts new file mode 100644 index 000000000..fe6ff8104 --- /dev/null +++ b/src/screens/Comment/utils.ts @@ -0,0 +1,58 @@ +import { toOldMusicInfo } from '@/utils' +import music from '@/utils/musicSdk' + +export interface Comment { + id: string + text: string + images?: string[] + location?: string + timeStr?: string + userName: string + avatar?: string + userId?: string + likedCount?: number + replyNum?: number + reply: Comment[] +} +export interface CommentInfo { + source: LX.OnlineSource + comments: Comment[] + total: number + page: number + limit: number + maxPage: number +} + +export const getNewComment = async(musicInfo: LX.Music.MusicInfoOnline, page: number, limit: number, retryNum = 0): Promise<CommentInfo> => { + let resp + try { + resp = await (music[musicInfo.source].comment.getComment(toOldMusicInfo(musicInfo), page, limit) as Promise<CommentInfo>) + } catch (error: any) { + console.log(error.message) + if (error.message == '取消请求' || ++retryNum > 2) throw error + resp = await getNewComment(musicInfo, page, limit, retryNum) + } + return resp +} + +export const getHotComment = async(musicInfo: LX.Music.MusicInfoOnline, page: number, limit: number, retryNum = 0): Promise<CommentInfo> => { + let resp + try { + resp = await (music[musicInfo.source].comment.getHotComment(toOldMusicInfo(musicInfo), page, limit) as Promise<CommentInfo>) + } catch (error: any) { + console.log(error.message) + if (error.message == '取消请求' || ++retryNum > 2) throw error + resp = await getHotComment(musicInfo, page, limit, retryNum) + } + return resp +} + +export const filterList = (list: Comment[]) => { + const set = new Set() + return list.filter(c => { + let id = String(c.id) + if (set.has(id)) return false + set.add(id) + return true + }) +} diff --git a/src/screens/Home/Horizontal/Aside.tsx b/src/screens/Home/Horizontal/Aside.tsx new file mode 100644 index 000000000..3dd3077f2 --- /dev/null +++ b/src/screens/Home/Horizontal/Aside.tsx @@ -0,0 +1,129 @@ +import React, { memo } from 'react' +import { ScrollView, StatusBar, TouchableOpacity, View } from 'react-native' +import { useNavActiveId } from '@/store/common/hook' +import { useTheme } from '@/store/theme/hook' +import { Icon } from '@/components/common/Icon' +import { createStyle } from '@/utils/tools' +import { NAV_MENUS } from '@/config/constant' +import type { InitState } from '@/store/common/state' +// import commonState from '@/store/common/state' +import { exitApp, setNavActiveId } from '@/core/common' +import { BorderWidths } from '@/theme' + +const NAV_WIDTH = 68 + +const styles = createStyle({ + container: { + flexGrow: 0, + // flex: 1, + // alignItems: 'center', + // justifyContent: 'center', + // padding: 10, + borderRightWidth: BorderWidths.normal, + paddingBottom: 10, + width: NAV_WIDTH, + }, + header: { + paddingTop: 15, + paddingBottom: 15, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + }, + headerText: { + textAlign: 'center', + marginLeft: 16, + }, + menus: { + flex: 1, + }, + list: { + // paddingTop: 10, + paddingBottom: 15, + }, + menuItem: { + flexDirection: 'row', + paddingTop: 15, + paddingBottom: 15, + // paddingLeft: 25, + // paddingRight: 25, + justifyContent: 'center', + alignItems: 'center', + // backgroundColor: 'rgba(0, 0, 0, 0.2)', + }, + iconContent: { + // width: 24, + // backgroundColor: 'rgba(0, 0, 0, 0.2)', + alignItems: 'center', + }, + text: { + paddingLeft: 15, + // fontWeight: '500', + }, +}) + +const Header = () => { + const theme = useTheme() + return ( + <View style={{ paddingTop: StatusBar.currentHeight }}> + <View style={styles.header}> + <Icon name="logo" color={theme['c-primary-dark-100-alpha-300']} size={22} /> + {/* <Text style={styles.headerText} size={16} color={theme['c-primary-dark-100-alpha-300']}>LX Music</Text> */} + </View> + </View> + ) +} + +type IdType = InitState['navActiveId'] | 'nav_exit' + +const MenuItem = ({ id, icon, onPress }: { + id: IdType + icon: string + onPress: (id: IdType) => void +}) => { + // const t = useI18n() + const activeId = useNavActiveId() + const theme = useTheme() + + return activeId == id + ? <View style={styles.menuItem}> + <View style={styles.iconContent}> + <Icon name={icon} size={20} color={theme['c-primary-font-active']} /> + </View> + {/* <Text style={styles.text} size={14} color={theme['c-primary-font']}>{t(id)}</Text> */} + </View> + : <TouchableOpacity style={styles.menuItem} onPress={() => { onPress(id) }}> + <View style={styles.iconContent}> + <Icon name={icon} size={20} color={theme['c-font-label']} /> + </View> + {/* <Text style={styles.text} size={14}>{t(id)}</Text> */} + </TouchableOpacity> +} + +export default memo(() => { + const theme = useTheme() + // console.log('render drawer nav') + + const handlePress = (id: IdType) => { + if (id == 'nav_exit') { + exitApp() + return + } + + global.app_event.changeMenuVisible(false) + setNavActiveId(id) + } + + return ( + <View style={{ ...styles.container, borderRightColor: theme['c-border-background'] }}> + <Header /> + <ScrollView style={styles.menus}> + <View style={styles.list}> + {NAV_MENUS.map(menu => <MenuItem key={menu.id} id={menu.id} icon={menu.icon} onPress={handlePress} />)} + </View> + </ScrollView> + <MenuItem id="nav_exit" icon="exit2" onPress={handlePress} /> + </View> + ) +}) + diff --git a/src/screens/Home/Horizontal/Header.tsx b/src/screens/Home/Horizontal/Header.tsx new file mode 100644 index 000000000..7c11721b4 --- /dev/null +++ b/src/screens/Home/Horizontal/Header.tsx @@ -0,0 +1,138 @@ +import React from 'react' +import { View } from 'react-native' +// import Button from '@/components/common/Button' +// import { navigations } from '@/navigation' +// import { BorderWidths } from '@/theme' +import { useNavActiveId } from '@/store/common/hook' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' +import StatusBar from '@/components/common/StatusBar' +import { useSettingValue } from '@/store/setting/hook' +import { scaleSizeH } from '@/utils/pixelRatio' +import { HEADER_HEIGHT as _HEADER_HEIGHT } from '@/config/constant' +import { type InitState as CommonState } from '@/store/common/state' +import SearchTypeSelector from '@/screens/Home/Views/Search/SearchTypeSelector' + +const headerComponents: Partial<Record<CommonState['navActiveId'], React.ReactNode>> = { + nav_search: <SearchTypeSelector />, +} + +const HEADER_HEIGHT = _HEADER_HEIGHT * 0.8 + + +// const LeftTitle = () => { +// const id = useNavActiveId() +// const t = useI18n() + +// return <Text style={styles.leftTitle} size={18}>{t(id)}</Text> +// } +const LeftHeader = () => { + const id = useNavActiveId() + const t = useI18n() + + return ( + <View style={{ + ...styles.container, + height: scaleSizeH(HEADER_HEIGHT) + StatusBar.currentHeight, + paddingTop: StatusBar.currentHeight, + }}> + <View style={styles.left}> + <Text style={styles.leftTitle} size={18}>{t(id)}</Text> + </View> + {headerComponents[id] ?? null} + + {/* <TouchableOpacity style={styles.btn} onPress={openSetting}> + <Icon style={{ ...styles.btnText, color: theme['c-font'] }} name="setting" size={styles.btnText.fontSize} /> + </TouchableOpacity> */} + </View> + ) +} + + +// const RightTitle = () => { +// const id = useNavActiveId() +// const t = useI18n() + +// return <Text style={styles.rightTitle} size={18}>{t(id)}</Text> +// } +const RightHeader = () => { + const t = useI18n() + const id = useNavActiveId() + + return ( + <View style={{ + ...styles.container, + height: scaleSizeH(HEADER_HEIGHT) + StatusBar.currentHeight, + paddingTop: StatusBar.currentHeight, + }}> + <View style={styles.left}> + <Text style={styles.rightTitle} size={18}>{t(id)}</Text> + </View> + {headerComponents[id] ?? null} + {/* <TouchableOpacity style={styles.btn} onPress={openSetting}> + <Icon style={{ ...styles.btnText, color: theme['c-font'] }} name="setting" size={styles.btnText.fontSize} /> + </TouchableOpacity> */} + </View> + ) +} + +const Header = () => { + const drawerLayoutPosition = useSettingValue('common.drawerLayoutPosition') + + return ( + <> + <StatusBar /> + { + drawerLayoutPosition == 'left' + ? <LeftHeader /> + : <RightHeader /> + } + + </> + ) +} + + +const styles = createStyle({ + container: { + // width: '100%', + paddingRight: 5, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + // backgroundColor: 'rgba(0,0,0,0.1)', + zIndex: 10, + }, + left: { + flex: 1, + flexDirection: 'row', + paddingLeft: 5, + alignItems: 'center', + height: '100%', + }, + btn: { + // flex: 1, + width: HEADER_HEIGHT, + // backgroundColor: 'rgba(0,0,0,0.1)', + alignItems: 'center', + justifyContent: 'center', + height: '100%', + }, + titleBtn: { + flex: 1, + // backgroundColor: 'rgba(0,0,0,0.1)', + height: '100%', + justifyContent: 'center', + }, + leftTitle: { + paddingLeft: 14, + paddingRight: 16, + }, + rightTitle: { + paddingLeft: 16, + paddingRight: 16, + }, +}) + +export default Header diff --git a/src/screens/Home/Horizontal/index.tsx b/src/screens/Home/Horizontal/index.tsx new file mode 100644 index 000000000..b430362df --- /dev/null +++ b/src/screens/Home/Horizontal/index.tsx @@ -0,0 +1,35 @@ +import React from 'react' +import { View } from 'react-native' +import Aside from './Aside' +import PlayerBar from '../components/PlayerBar' +import StatusBar from '@/components/common/StatusBar' +import Header from './Header' +import Main from '../components/Main' +import { createStyle } from '@/utils/tools' + +const styles = createStyle({ + container: { + flex: 1, + flexDirection: 'row', + }, + content: { + flex: 1, + overflow: 'hidden', + }, +}) + +export default () => { + return ( + <> + <StatusBar /> + <View style={styles.container}> + <Aside /> + <View style={styles.content}> + <Header /> + <Main /> + <PlayerBar /> + </View> + </View> + </> + ) +} diff --git a/src/screens/Home/List/components/ExitMultipleModeBar.js b/src/screens/Home/List/components/ExitMultipleModeBar.js deleted file mode 100644 index 3e011d899..000000000 --- a/src/screens/Home/List/components/ExitMultipleModeBar.js +++ /dev/null @@ -1,142 +0,0 @@ -import React, { useState, useRef, useEffect, useCallback, useMemo, memo } from 'react' -import { Text, StyleSheet, Animated, View, TouchableOpacity } from 'react-native' -import { useTranslation } from '@/plugins/i18n' - -import Button from '@/components/common/Button' -import { useGetter } from '@/store' - - -export default memo(({ multipleMode, onCancel, onSelectAll, selectMode, onSwitchMode, isSelectAll }) => { - const { t } = useTranslation() - // const isGetDetailFailedRef = useRef(false) - const [visible, setVisible] = useState(false) - const [animatePlayed, setAnimatPlayed] = useState(true) - const animFade = useRef(new Animated.Value(0)).current - const animTranslateY = useRef(new Animated.Value(0)).current - - const theme = useGetter('common', 'theme') - - useEffect(() => { - setAnimatPlayed(true) - if (multipleMode) { - animFade.setValue(0.92) - animTranslateY.setValue(0) - setVisible(true) - } else { - animFade.setValue(0) - animTranslateY.setValue(-20) - setVisible(false) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - const showList = useCallback(() => { - // console.log('show List') - setVisible(true) - setAnimatPlayed(false) - animTranslateY.setValue(-20) - - Animated.parallel([ - Animated.timing(animFade, { - toValue: 0.92, - duration: 200, - useNativeDriver: true, - }), - Animated.timing(animTranslateY, { - toValue: 0, - duration: 200, - useNativeDriver: true, - }), - ]).start(() => { - setAnimatPlayed(true) - }) - }, [animFade, animTranslateY]) - - const hideList = useCallback(() => { - setAnimatPlayed(false) - Animated.parallel([ - Animated.timing(animFade, { - toValue: 0, - duration: 200, - useNativeDriver: true, - }), - Animated.timing(animTranslateY, { - toValue: -20, - duration: 200, - useNativeDriver: true, - }), - ]).start(finished => { - if (!finished) return - setVisible(false) - setAnimatPlayed(true) - }) - }, [animFade, animTranslateY]) - - useEffect(() => { - if (multipleMode) { - showList() - } else { - hideList() - } - }, [hideList, multipleMode, showList]) - - - const animaStyle = useMemo(() => StyleSheet.compose(styles.container, { - backgroundColor: theme.secondary45, - opacity: animFade, // Bind opacity to animated value - transform: [ - { translateY: animTranslateY }, - ], - }), [animFade, animTranslateY, theme]) - - const switchModeSingle = useCallback(() => { - onSwitchMode('single') - }, [onSwitchMode]) - const switchModeRange = useCallback(() => { - onSwitchMode('range') - }, [onSwitchMode]) - - const component = useMemo(() => ( - <Animated.View style={animaStyle}> - <View style={styles.switchBtn}> - <Button onPress={switchModeSingle} style={{ ...styles.btn, backgroundColor: selectMode == 'single' ? theme.secondary40 : 'rgba(0,0,0,0)' }}> - <Text style={{ color: theme.secondary }}>{t('list_select_single')}</Text> - </Button> - <Button onPress={switchModeRange} style={{ ...styles.btn, backgroundColor: selectMode == 'range' ? theme.secondary40 : 'rgba(0,0,0,0)' }}> - <Text style={{ color: theme.secondary }}>{t('list_select_range')}</Text> - </Button> - </View> - <TouchableOpacity onPress={onSelectAll} style={styles.btn}> - <Text style={{ color: theme.secondary }}>{t(isSelectAll ? 'list_select_unall' : 'list_select_all')}</Text> - </TouchableOpacity> - <TouchableOpacity onPress={onCancel} style={styles.btn}> - <Text style={{ color: theme.secondary }}>{t('list_select_cancel')}</Text> - </TouchableOpacity> - </Animated.View> - ), [animaStyle, isSelectAll, selectMode, onCancel, onSelectAll, switchModeRange, switchModeSingle, t, theme]) - - return !visible && animatePlayed ? null : component -}) - -const styles = StyleSheet.create({ - container: { - flex: 1, - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - flexDirection: 'row', - }, - switchBtn: { - flexDirection: 'row', - flex: 1, - }, - btn: { - // flex: 1, - paddingLeft: 15, - paddingRight: 15, - alignItems: 'center', - justifyContent: 'center', - }, -}) diff --git a/src/screens/Home/List/components/ListItem.js b/src/screens/Home/List/components/ListItem.js deleted file mode 100644 index d2ab8fc3e..000000000 --- a/src/screens/Home/List/components/ListItem.js +++ /dev/null @@ -1,121 +0,0 @@ -import React, { useMemo, useCallback, memo, useRef, useState, useEffect } from 'react' -import { View, Text, StyleSheet, TouchableOpacity } from 'react-native' -import { LIST_ITEM_HEIGHT } from '@/config/constant' -import { BorderWidths } from '@/theme' -import { useAssertApiSupport } from '@/utils/hooks' -import { useGetter, useDispatch } from '@/store' -import Button from '@/components/common/Button' -import { Icon } from '@/components/common/Icon' - -export default memo(({ item, index, activeIndex, onPress, showMenu, handleLongPress, selectedList }) => { - const theme = useGetter('common', 'theme') - - const isSelected = selectedList.indexOf(item) != -1 - // console.log(item.name, selectedList, selectedList.includes(item)) - const isSupported = useAssertApiSupport(item.source) - const moreButtonRef = useRef() - const handleShowMenu = useCallback(() => { - if (moreButtonRef.current && moreButtonRef.current.measure) { - moreButtonRef.current.measure((fx, fy, width, height, px, py) => { - // console.log(fx, fy, width, height, px, py) - showMenu(item, index, { x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }) - }) - } - }, [item, index, showMenu]) - - return ( - <View style={{ ...styles.listItem, backgroundColor: isSelected ? theme.secondary45 : theme.primary, borderBottomColor: theme.secondary45, opacity: isSupported ? 1 : 0.5 }}> - <TouchableOpacity style={styles.listItemLeft} onPress={() => { onPress(item, index) }} onLongPress={() => { handleLongPress(item, index) }}> - <Text style={{ ...styles.sn, color: theme.normal50 }}>{index + 1}</Text> - <View style={styles.itemInfo}> - <View style={styles.listItemTitle}> - <Text style={{ ...styles.listItemTitleText, color: activeIndex == index ? theme.secondary : theme.normal }} numberOfLines={1}>{item.name}</Text> - <Text style={{ ...styles.listItemBadge, color: theme.secondary20 }}>{item.source}</Text> - </View> - <View style={styles.row2}> - <Text style={{ ...styles.listItemSingle, color: activeIndex == index ? theme.secondary20 : theme.normal40 }} numberOfLines={1}>{item.singer}</Text> - </View> - </View> - </TouchableOpacity> - <View style={styles.listItemRight}> - <TouchableOpacity onPress={handleShowMenu} ref={moreButtonRef} style={styles.moreButton}> - <Icon name="dots-vertical" style={{ color: theme.normal35 }} size={16} /> - </TouchableOpacity> - </View> - </View> - ) -}, (prevProps, nextProps) => { - return !!(prevProps.item === nextProps.item && - prevProps.index === nextProps.index && - prevProps.activeIndex != nextProps.index && - nextProps.activeIndex != nextProps.index && - nextProps.selectedList.includes(nextProps.item) == prevProps.selectedList.includes(nextProps.item) - ) -}) - - -const styles = StyleSheet.create({ - listItem: { - width: '100%', - flexDirection: 'row', - flexWrap: 'nowrap', - // paddingLeft: 10, - paddingRight: 10, - height: LIST_ITEM_HEIGHT, - borderBottomWidth: BorderWidths.normal, - }, - listItemLeft: { - flex: 1, - flexGrow: 1, - flexShrink: 1, - flexDirection: 'row', - alignItems: 'center', - }, - sn: { - width: 32, - fontSize: 11, - textAlign: 'center', - // backgroundColor: 'rgba(0,0,0,0.2)', - paddingLeft: 3, - paddingRight: 3, - }, - itemInfo: { - flexGrow: 0, - flexShrink: 1, - paddingTop: 10, - paddingBottom: 10, - }, - listItemTitle: { - flexDirection: 'row', - alignItems: 'flex-end', - }, - listItemTitleText: { - // backgroundColor: 'rgba(0,0,0,0.2)', - flexGrow: 0, - flexShrink: 1, - fontSize: 14, - }, - listItemSingle: { - fontSize: 12, - paddingTop: 2, - }, - listItemBadge: { - fontSize: 10, - paddingLeft: 5, - paddingTop: 2, - alignSelf: 'flex-start', - }, - listItemRight: { - flexGrow: 0, - flexShrink: 0, - flexBasis: 'auto', - justifyContent: 'center', - }, - - moreButton: { - paddingLeft: 10, - paddingRight: 10, - paddingTop: 10, - paddingBottom: 10, - }, -}) diff --git a/src/screens/Home/List/components/ListSearchBar.js b/src/screens/Home/List/components/ListSearchBar.js deleted file mode 100644 index 550e42b81..000000000 --- a/src/screens/Home/List/components/ListSearchBar.js +++ /dev/null @@ -1,143 +0,0 @@ -import React, { useState, useRef, useEffect, useCallback, useMemo, memo } from 'react' -import { Text, StyleSheet, Animated, View, TouchableOpacity } from 'react-native' -import { useTranslation } from '@/plugins/i18n' - -import Input from '@/components/common/Input' - -import { useGetter } from '@/store' - -const Bar = memo(({ visible, onHide, children }) => { - const { t } = useTranslation() - // const isGetDetailFailedRef = useRef(false) - const [show, setShow] = useState(false) - const [animatePlayed, setAnimatPlayed] = useState(true) - const animFade = useRef(new Animated.Value(0)).current - const animTranslateY = useRef(new Animated.Value(0)).current - - const theme = useGetter('common', 'theme') - - useEffect(() => { - setAnimatPlayed(true) - if (visible) { - animFade.setValue(0.92) - animTranslateY.setValue(0) - setShow(true) - } else { - animFade.setValue(0) - animTranslateY.setValue(-20) - setShow(false) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - const showList = useCallback(() => { - // console.log('show List') - setShow(true) - setAnimatPlayed(false) - animTranslateY.setValue(-20) - - Animated.parallel([ - Animated.timing(animFade, { - toValue: 0.92, - duration: 200, - useNativeDriver: true, - }), - Animated.timing(animTranslateY, { - toValue: 0, - duration: 200, - useNativeDriver: true, - }), - ]).start(() => { - setAnimatPlayed(true) - }) - }, [animFade, animTranslateY]) - - const hideList = useCallback(() => { - setAnimatPlayed(false) - Animated.parallel([ - Animated.timing(animFade, { - toValue: 0, - duration: 200, - useNativeDriver: true, - }), - Animated.timing(animTranslateY, { - toValue: -20, - duration: 200, - useNativeDriver: true, - }), - ]).start(finished => { - if (!finished) return - setShow(false) - setAnimatPlayed(true) - }) - }, [animFade, animTranslateY]) - - useEffect(() => { - if (visible) { - showList() - } else { - hideList() - } - }, [hideList, visible, showList]) - - - const animaStyle = useMemo(() => StyleSheet.compose(styles.container, { - backgroundColor: theme.secondary45, - opacity: animFade, // Bind opacity to animated value - transform: [ - { translateY: animTranslateY }, - ], - }), [animFade, animTranslateY, theme]) - - const component = useMemo(() => ( - <Animated.View style={animaStyle}> - <View style={styles.content}> - {children} - </View> - <TouchableOpacity onPress={onHide} style={styles.btn}> - <Text style={{ color: theme.secondary }}>{t('list_select_cancel')}</Text> - </TouchableOpacity> - </Animated.View> - ), [animaStyle, children, onHide, t, theme]) - - return !show && animatePlayed ? null : component -}) - - -export default memo(({ visible, onHide, text, onChangeText }) => { - return ( - <Bar visible={visible} onHide={onHide}> - <Input - onChangeText={onChangeText} - placeholder="Find for something..." - value={text} - // onFocus={showTipList} - clearBtn - // ref={searchInputRef} - /> - </Bar> - ) -}) - -const styles = StyleSheet.create({ - container: { - flex: 1, - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - flexDirection: 'row', - }, - content: { - flexDirection: 'row', - flex: 1, - }, - btn: { - // flex: 1, - paddingLeft: 15, - paddingRight: 15, - alignItems: 'center', - justifyContent: 'center', - }, -}) diff --git a/src/screens/Home/List/components/MusicPositionModal.js b/src/screens/Home/List/components/MusicPositionModal.js deleted file mode 100644 index 02c6bddb8..000000000 --- a/src/screens/Home/List/components/MusicPositionModal.js +++ /dev/null @@ -1,92 +0,0 @@ -import React, { memo, useMemo, useEffect, useCallback, useState, useRef } from 'react' -import { StyleSheet, Text, View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' -import ConfirmAlert from '@/components/common/ConfirmAlert' -import Input from '@/components/common/Input' - -export default memo(({ visible, hideModal, onConfirm, selectedList, selectedData }) => { - const [text, setText] = useState('') - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - const inputRef = useRef() - - const title = useMemo(() => { - return selectedList.length - ? t('change_position_music_multi_title', { num: selectedList.length }) - : t('change_position_music_title', { name: selectedData ? selectedData.name : '' }) - }, [selectedData, selectedList, t]) - - const verify = useCallback(() => { - let num = /^[1-9]\d*/.exec(text) - num = num ? parseInt(num[0]) : '' - setText(num.toString()) - return num - }, [text]) - const handleSetMusicPosition = useCallback(() => { - let num = verify() - if (num == '') return - onConfirm(num) - }, [onConfirm, verify]) - useEffect(() => { - if (!visible) return - - setText('') - // inputRef.current.focus() - }, [visible]) - - - return ( - <ConfirmAlert - visible={visible} - onHide={hideModal} - onConfirm={handleSetMusicPosition} - > - <View style={styles.content}> - <Text style={{ color: theme.normal, marginBottom: 5 }}>{title}</Text> - <Input - placeholder={t('change_position_tip')} - value={text} - onChangeText={setText} - ref={inputRef} - style={{ ...styles.input, backgroundColor: theme.secondary40 }} - /> - </View> - </ConfirmAlert> - ) -}) - -const styles = StyleSheet.create({ - content: { - flexGrow: 1, - flexShrink: 1, - flexDirection: 'column', - }, - input: { - flexGrow: 1, - flexShrink: 1, - minWidth: 240, - borderRadius: 4, - paddingTop: 2, - paddingBottom: 2, - fontSize: 12, - }, - - // tagTypeList: { - // flexDirection: 'row', - // flexWrap: 'wrap', - // }, - // tagButton: { - // // marginRight: 10, - // borderRadius: 4, - // marginRight: 10, - // marginBottom: 10, - // }, - // tagButtonText: { - // paddingLeft: 12, - // paddingRight: 12, - // paddingTop: 8, - // paddingBottom: 8, - // }, -}) diff --git a/src/screens/Home/List/components/MyList.js b/src/screens/Home/List/components/MyList.js deleted file mode 100644 index 497326b14..000000000 --- a/src/screens/Home/List/components/MyList.js +++ /dev/null @@ -1,501 +0,0 @@ -import React, { memo, useMemo, useEffect, useCallback, useState, useRef } from 'react' -import { StyleSheet, Text, View, TouchableOpacity, ScrollView, InteractionManager } from 'react-native' - -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' -// import DorpDownPanel from '@/components/common/DorpDownPanel' -import { Icon } from '@/components/common/Icon' -// import Button from '@/components/common/Button' -import { BorderWidths } from '@/theme' -import Menu from '@/components/common/Menu' -import ConfirmAlert from '@/components/common/ConfirmAlert' -import Input from '@/components/common/Input' -import { filterFileName } from '@/utils' -import { getListScrollPosition, saveListScrollPosition, toast, handleSaveFile, handleReadFile, confirmDialog, showImportTip } from '@/utils/tools' -import { LIST_SCROLL_POSITION_KEY, LXM_FILE_EXT_RXP } from '@/config/constant' -import musicSdk from '@/utils/music' -import ChoosePath from '@/components/common/ChoosePath' -import { log } from '@/utils/log' -import Popup from '@/components/common/Popup' -import { toOldMusicInfo } from '@/utils/listData' - -const exportList = async(list, path) => { - const data = JSON.parse(JSON.stringify({ - type: 'playListPart', - data: list, - })) - for (const item of data.data.list) { - if (item.otherSource) delete item.otherSource - if (item.lrc) delete item.lrc - } - try { - await handleSaveFile(path + `/lx_list_part_${filterFileName(list.name)}.lxmc`, data) - } catch (error) { - log.error(error.stack) - } -} -const importList = async path => { - let listData - try { - listData = await handleReadFile(path) - } catch (error) { - log.error(error.stack) - return - } - console.log(listData.type) - return listData -} - -const ListItem = ({ onPress, name, id, showMenu, activeId, loading, index }) => { - const theme = useGetter('common', 'theme') - const moreButtonRef = useRef() - const handleShowMenu = useCallback(() => { - if (moreButtonRef.current && moreButtonRef.current.measure) { - moreButtonRef.current.measure((fx, fy, width, height, px, py) => { - // console.log(fx, fy, width, height, px, py) - showMenu(id, name, index, { x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }) - }) - } - }, [showMenu, id, name, index]) - - return ( - <View style={{ ...styles.listItem, borderBottomColor: theme.secondary45, opacity: loading ? 0.5 : 1 }}> - <TouchableOpacity style={styles.listName} onPress={onPress}> - <Text numberOfLines={1} style={{ color: theme.normal }}>{name}</Text> - </TouchableOpacity> - <TouchableOpacity onPress={handleShowMenu} ref={moreButtonRef} style={styles.listMoreBtn}> - <Icon name="dots-vertical" style={{ color: theme.normal35 }} size={16} /> - </TouchableOpacity> - </View> - ) -} - -const ImportExport = ({ actionType, visible, hide, selectedListRef }) => { - const [title, setTitle] = useState('') - const [dirOnly, setDirOnly] = useState(false) - const setList = useDispatch('list', 'setList') - const createUserList = useDispatch('list', 'createUserList') - const { t } = useTranslation() - useEffect(() => { - switch (actionType) { - case 'import': - setTitle(t('list_import_part_desc')) - setDirOnly(false) - break - case 'export': - default: - setTitle(t('list_export_part_desc')) - setDirOnly(true) - break - } - }, [actionType, t]) - - const onConfirmPath = useCallback(path => { - hide() - switch (actionType) { - case 'import': - toast(t('setting_backup_part_import_list_tip_unzip')) - importList(path).then(async listData => { - switch (listData.type) { - case 'playListPart': - case 'playListPart_v2': - break - default: return showImportTip(listData.type) - } - const isV2 = listData.type == 'playListPart_v2' - const targetList = global.allList[listData.data.id] - if (targetList) { - const confirm = await confirmDialog({ - message: t('list_import_part_confirm', { importName: listData.data.name, localName: targetList.name }), - cancelButtonText: t('list_import_part_button_cancel'), - confirmButtonText: t('list_import_part_button_confirm'), - bgClose: false, - }) - if (confirm) { - listData.data.name = targetList.name - setList({ - name: listData.data.name, - id: listData.data.id, - list: isV2 ? listData.data.list.map(m => toOldMusicInfo(m)) : listData.data.list, - source: listData.data.source, - sourceListId: listData.data.sourceListId, - }) - toast(t('setting_backup_part_import_list_tip_success')) - return - } - listData.data.id += `__${Date.now()}` - } - createUserList({ - name: listData.data.name, - id: listData.data.id, - list: isV2 ? listData.data.list.map(m => toOldMusicInfo(m)) : listData.data.list, - source: listData.data.source, - sourceListId: listData.data.sourceListId, - position: Math.max(selectedListRef.current.index, -1), - }) - toast(t('setting_backup_part_import_list_tip_success')) - }) - break - case 'export': - InteractionManager.runAfterInteractions(() => { - toast(t('setting_backup_part_export_list_tip_zip')) - exportList(selectedListRef.current.listInfo, path).then(() => { - toast(t('setting_backup_part_export_list_tip_success')) - }).catch(err => { - log.error(err.message) - toast(t('setting_backup_part_export_list_tip_failed') + ': ' + err.message) - }) - }) - break - } - }, [actionType, createUserList, hide, selectedListRef, setList, t]) - - return ( - <ChoosePath - visible={visible} - hide={hide} - title={title} - dirOnly={dirOnly} - filter={LXM_FILE_EXT_RXP} - onConfirm={onConfirmPath} /> - ) -} - -const List = memo(({ setVisiblePanel, currentList, handleCancelMultiSelect }) => { - const theme = useGetter('common', 'theme') - const defaultList = useGetter('list', 'defaultList') - const loveList = useGetter('list', 'loveList') - const userListRef = useRef([]) - const userList = useGetter('list', 'userList') - const setPrevSelectListId = useDispatch('common', 'setPrevSelectListId') - const setUserListName = useDispatch('list', 'setUserListName') - // const setUserListPosition = useDispatch('list', 'setUserListPosition') - const removeUserList = useDispatch('list', 'removeUserList') - const [visibleMenu, setVisibleMenu] = useState(false) - // const activeListId = useGetter('common', 'prevSelectListId') - const [selectedListIndex, setSelectedListIndex] = useState(-1) - const selectedListRef = useRef({}) - const { t } = useTranslation() - const [buttonPosition, setButtonPosition] = useState({ w: 0, h: 0, x: 0, y: 0 }) - const [visibleRename, setVisibleRename] = useState(false) - const [listNameText, setListNameText] = useState('') - const scrollViewRef = useRef() - const setList = useDispatch('list', 'setList') - const getBoardListAll = useDispatch('top', 'getListAll') - const getListDetailAll = useDispatch('songList', 'getListDetailAll') - const [fetchingListStatus, setFetchingListStatus] = useState({}) - const [isShowChoosePath, setShowChoosePath] = useState(false) - const [actionType, setActionType] = useState('') - - useEffect(() => { - userListRef.current = userList - }, [userList]) - - const handleToggleList = useCallback(({ id }) => { - setVisiblePanel(false) - setPrevSelectListId(id) - }, [setPrevSelectListId, setVisiblePanel]) - - const handleRemoveList = useCallback(id => { - removeUserList({ id }) - }, [removeUserList]) - - const getTargetListInfo = useCallback(index => { - let list - switch (index) { - case -2: - list = defaultList - break - case -1: - list = loveList - break - default: - list = userListRef.current[index] - break - } - return list - }, [defaultList, loveList]) - - const handleImportAndExportList = useCallback((type, index) => { - const list = getTargetListInfo(index) - if (!list) return - selectedListRef.current.listInfo = list - setActionType(type) - setShowChoosePath(true) - }, [getTargetListInfo]) - - const hideMenu = useCallback(() => { - setVisibleMenu(false) - }, [setVisibleMenu]) - const fetchList = useCallback((id, source, sourceListId) => { - setFetchingListStatus(fetchingListStatus => ({ ...fetchingListStatus, [id]: true })) - // console.log(sourceListId) - let promise - if (/board__/.test(sourceListId)) { - const id = sourceListId.replace(/board__/, '') - promise = getBoardListAll({ id, isRefresh: true }) - } else { - promise = getListDetailAll({ source, id: sourceListId, isRefresh: true }) - } - return promise.finally(() => { - setFetchingListStatus(fetchingListStatus => ({ ...fetchingListStatus, [id]: false })) - }) - }, [getBoardListAll, getListDetailAll]) - const handleSyncSourceList = useCallback(async index => { - const targetListInfo = userList[index] - const list = await fetchList(targetListInfo.id, targetListInfo.source, targetListInfo.sourceListId).catch(err => { - toast(t('list_update_error')) - return Promise.reject(err) - }) - // console.log(targetListInfo.list.length, list.length) - handleCancelMultiSelect() - setList({ - ...targetListInfo, - list, - }) - toast(t('list_update_success')) - }, [fetchList, handleCancelMultiSelect, setList, t, userList]) - const handleMenuPress = useCallback(({ action }) => { - switch (action) { - case 'rename': - setListNameText(selectedListRef.current.name) - setVisibleRename(true) - break - case 'import': - handleImportAndExportList('import', selectedListRef.current.index) - break - case 'export': - handleImportAndExportList('export', selectedListRef.current.index) - break - case 'sync': - confirmDialog({ - message: t('list_sync_confirm_tip', { name: selectedListRef.current.name }), - confirmButtonText: t('list_remove_tip_button'), - }).then(isSync => { - if (!isSync) return - handleSyncSourceList(selectedListRef.current.index) - }) - break - // case 'changePosition': - - // break - case 'remove': - confirmDialog({ - message: t('list_remove_tip', { name: selectedListRef.current.name }), - confirmButtonText: t('list_remove_tip_button'), - }).then(isRemove => { - if (!isRemove) return - handleRemoveList(selectedListRef.current.id) - }) - break - - default: - break - } - }, [handleImportAndExportList, handleRemoveList, handleSyncSourceList, t]) - - const menus = useMemo(() => { - let list - let rename = false - let sync = false - let remove = false - switch (selectedListIndex) { - case -2: - list = defaultList - break - case -1: - list = loveList - break - default: - list = userList[selectedListIndex] - if (!list) return [] - rename = true - remove = true - sync = list.source && !!musicSdk[list.source]?.songList - break - } - - return [ - { action: 'rename', disabled: !rename, label: t('list_rename') }, - { action: 'sync', disabled: !sync, label: t('list_sync') }, - { action: 'import', label: t('list_import') }, - { action: 'export', label: t('list_export') }, - // { action: 'changePosition', label: t('change_position') }, - { action: 'remove', disabled: !remove, label: t('list_remove') }, - ] - }, [selectedListIndex, t, defaultList, loveList, userList]) - - const handleCancelRename = useCallback(() => { - setVisibleRename(false) - }, []) - const handleRename = useCallback(() => { - if (!listNameText.length) return - setUserListName({ id: selectedListRef.current.id, name: listNameText }) - setVisibleRename(false) - }, [listNameText, setUserListName]) - - const handleScroll = useCallback(({ nativeEvent }) => { - saveListScrollPosition(LIST_SCROLL_POSITION_KEY, nativeEvent.contentOffset.y) - }, []) - - useEffect(() => { - const offset = getListScrollPosition(LIST_SCROLL_POSITION_KEY) - scrollViewRef.current.scrollTo({ x: 0, y: offset, animated: false }) - }) - const showMenu = useCallback((id, name, index, position) => { - // console.log(position) - // if (id == 'default' || id == 'love') return - setButtonPosition({ ...position }) - selectedListRef.current.id = id - selectedListRef.current.name = name - selectedListRef.current.index = index - setSelectedListIndex(index) - setVisibleMenu(true) - }, []) - return ( - <> - <ScrollView style={{ flexShrink: 1, flexGrow: 0 }} onScroll={handleScroll} ref={scrollViewRef} keyboardShouldPersistTaps={'always'}> - <View style={{ ...styles.listContainer, backgroundColor: theme.primary }} onStartShouldSetResponder={() => true}> - <ListItem name={defaultList.name} id={defaultList.id} index={-2} loading={false} onPress={() => handleToggleList(defaultList)} activeId={currentList.id} showMenu={showMenu} /> - <ListItem name={loveList.name} id={loveList.id} index={-1} loading={false} onPress={() => handleToggleList(loveList)} activeId={currentList.id} showMenu={showMenu} /> - {userList.map(({ id, name }, index) => <ListItem key={id} name={name} id={id} index={index} loading={fetchingListStatus[id]} onPress={() => handleToggleList({ id, name })} activeId={currentList.id} showMenu={showMenu} />)} - </View> - </ScrollView> - <Menu menus={menus} buttonPosition={buttonPosition} onPress={handleMenuPress} visible={visibleMenu} hideMenu={hideMenu} /> - <ConfirmAlert - visible={visibleRename} - onHide={handleCancelRename} - onConfirm={handleRename} - > - <View style={styles.renameContent}> - <Text style={{ color: theme.normal, marginBottom: 5 }}>{t('list_rename_title')}</Text> - <Input - placeholder={selectedListRef.current.name} - value={listNameText} - onChangeText={setListNameText} - style={{ ...styles.input, backgroundColor: theme.secondary40 }} - /> - </View> - </ConfirmAlert> - <ImportExport actionType={actionType} visible={isShowChoosePath} hide={() => setShowChoosePath(false)} selectedListRef={selectedListRef} /> - </> - ) -}) - - -export default memo(({ currentList, handleCancelMultiSelect, showListSearchBar }) => { - const theme = useGetter('common', 'theme') - const [visiblePanel, setVisiblePanel] = useState(false) - const { t } = useTranslation() - const showPopup = () => { - setVisiblePanel(true) - } - const hidePopup = () => { - setVisiblePanel(false) - } - - return ( - <View> - <TouchableOpacity onPress={showPopup} style={{ ...styles.currentList, borderBottomWidth: BorderWidths.normal, borderBottomColor: theme.borderColor }}> - <Icon style={{ ...styles.sourceMenuIcon, color: theme.secondary30, fontSize: 18 }} name="chevron-right" /> - <Text numberOfLines={1} style={{ ...styles.sourceMenu, color: theme.secondary, flex: 1 }}>{currentList.name}</Text> - <TouchableOpacity style={styles.btns} onPress={showListSearchBar}> - <Icon style={{ color: theme.secondary30, fontSize: 16 }} name="search-2" /> - </TouchableOpacity> - </TouchableOpacity> - <Popup visible={visiblePanel} hide={hidePopup} title={t('nav_my_list')}> - <List setVisiblePanel={setVisiblePanel} currentList={currentList} handleCancelMultiSelect={handleCancelMultiSelect} /> - </Popup> - </View> - ) -}) - - -const styles = StyleSheet.create({ - sourceMenuIcon: { - paddingLeft: 8, - paddingRight: 3, - paddingTop: 10, - paddingBottom: 0, - }, - sourceMenu: { - minWidth: 70, - // paddingLeft: 10, - paddingRight: 10, - paddingTop: 10, - paddingBottom: 10, - }, - - // container: { - // borderBottomWidth: BorderWidths.normal2, - // }, - listContainer: { - // borderBottomWidth: BorderWidths.normal2, - }, - listItem: { - flexDirection: 'row', - alignItems: 'center', - borderBottomWidth: BorderWidths.normal, - }, - listName: { - // height: 46, - paddingTop: 12, - paddingBottom: 12, - justifyContent: 'center', - flexGrow: 1, - flexShrink: 1, - paddingLeft: 10, - }, - listMoreBtn: { - width: 50, - // height: 46, - paddingTop: 12, - paddingBottom: 12, - justifyContent: 'center', - alignItems: 'center', - }, - - currentList: { - flexDirection: 'row', - paddingRight: 2, - }, - btns: { - width: 38, - justifyContent: 'center', - alignItems: 'center', - // backgroundColor: 'rgba(0,0,0,0.2)', - }, - - - renameContent: { - flexGrow: 1, - flexShrink: 1, - flexDirection: 'column', - }, - input: { - flexGrow: 1, - flexShrink: 1, - minWidth: 240, - borderRadius: 4, - paddingTop: 2, - paddingBottom: 2, - fontSize: 12, - }, - - // tagTypeList: { - // flexDirection: 'row', - // flexWrap: 'wrap', - // }, - // tagButton: { - // // marginRight: 10, - // borderRadius: 4, - // marginRight: 10, - // marginBottom: 10, - // }, - // tagButtonText: { - // paddingLeft: 12, - // paddingRight: 12, - // paddingTop: 8, - // paddingBottom: 8, - // }, -}) diff --git a/src/screens/Home/List/index.js b/src/screens/Home/List/index.js deleted file mode 100644 index 79127923f..000000000 --- a/src/screens/Home/List/index.js +++ /dev/null @@ -1,437 +0,0 @@ -import React, { useMemo, useCallback, useRef, useState, useEffect } from 'react' -import { View, Text, StyleSheet, FlatList } from 'react-native' - -import { useGetter, useDispatch } from '@/store' -import Menu from '@/components/common/Menu' -import MusicAddModal from '@/components/MusicAddModal' -import MusicMultiAddModal from '@/components/MusicMultiAddModal' -import SearchTipList from '@/components/searchTipList' -import Button from '@/components/common/Button' -import ExitMultipleModeBar from './components/ExitMultipleModeBar' -import MyList from './components/MyList' -import ListItem from './components/ListItem' -import { getListScrollPosition, saveListScrollPosition, shareMusic } from '@/utils/tools' -import { useTranslation } from '@/plugins/i18n' -import { LIST_ITEM_HEIGHT } from '@/config/constant' -import MusicPositionModal from './components/MusicPositionModal' -// import { BorderWidths } from '@/theme' -import ListSearchBar from './components/ListSearchBar' -import { debounceSearchList } from './utils' -import { useLayout } from '@/utils/hooks' -// const shadow = { -// shadowOffset: 2, -// shadowOpacity: 0.23, -// shadowRadius: 0, -// elevation: 4, -// } - - -const List = () => { - const allList = useGetter('list', 'allList') - const isJumpPosition = useGetter('list', 'isJumpPosition') - const playInfo = useGetter('player', 'playInfo') - const playListInfo = useGetter('player', 'listInfo') - const playListInfoRef = useRef(playListInfo) - const activeListId = useGetter('common', 'prevSelectListId') - const activeListIdRef = useRef(activeListId) - const downloadFileName = useGetter('common', 'downloadFileName') - const shareType = useGetter('common', 'shareType') - const [buttonPosition, setButtonPosition] = useState({ w: 0, h: 0, x: 0, y: 0 }) - const selectedDataRef = useRef({ data: null, index: -1 }) - const flatListRef = useRef() - const isMoveRef = useRef(false) - const [visibleMenu, setVisibleMenu] = useState(false) - const [isMultiSelectMode, setIsMultiSelectMode] = useState(false) - const isMultiSelectModeRef = useRef(false) - const [selectedList, setSelectedList] = useState([]) - const selectedListRef = useRef([]) - const [selectMode, setSelectMode] = useState('single') - const selectModeRef = useRef('single') - const prevSelectIndexRef = useRef(-1) - const activeIndexRef = useRef(-1) - const activeIndex = useMemo(() => { - const index = playInfo.listId === activeListId ? playInfo.playIndex : -1 - activeIndexRef.current = index - return index - }, [playInfo.listId, activeListId, playInfo.playIndex]) - const currentListRef = useRef({}) - const currentList = useMemo(() => currentListRef.current = (allList.find(l => l.id == activeListId) || allList[0]), [allList, activeListId]) - const activeItemId = useMemo(() => currentList.list && activeIndex > -1 && currentList.list[activeIndex] ? String(currentList.list[activeIndex].songmid) : null, [currentList, activeIndex]) - const setPlayList = useDispatch('player', 'setList') - // const playMusic = useDispatch('player', 'playMusic') - const setTempPlayList = useDispatch('player', 'setTempPlayList') - const removeListItem = useDispatch('list', 'listRemove') - const removeListMultiItem = useDispatch('list', 'listRemoveMultiple') - const setJumpPosition = useDispatch('list', 'setJumpPosition') - const { t } = useTranslation() - const [visibleMusicAddModal, setVisibleMusicAddModal] = useState(false) - const [visibleMusicMultiAddModal, setVisibleMusicMultiAddModal] = useState(false) - const [visibleMusicPosition, setVIsibleMusicPosition] = useState(false) - const setMusicPosition = useDispatch('list', 'setMusicPosition') - const [listSearchBarVisible, setListSearchBarVisible] = useState(false) - const [listSearchListVisible, setListSearchListVisible] = useState(false) - const [listSearchBarText, setListSearchBarText] = useState('') - const [listSearchList, setListSearchList] = useState([]) - const theme = useGetter('common', 'theme') - const { onLayout, ...listLayout } = useLayout() - - useEffect(() => { - activeListIdRef.current = activeListId - }, [activeListId]) - useEffect(() => { - playListInfoRef.current = playListInfo - }, [playListInfo]) - - const handlePlay = useCallback(async(data, index) => { - // if (playListInfoRef.current.id != activeListIdRef.current) { - setPlayList({ - list: currentListRef.current, - index, - }) - // } else { - // playMusic({ - // musicInfo: data, - // listId: activeListIdRef.current, - // }) - // } - }, [setPlayList]) - - const handleSelect = useCallback((item, index) => { - if (selectModeRef.current == 'single') { - const index = selectedListRef.current.indexOf(item) - if (index < 0) { - selectedListRef.current.push(item) - // setSelectedItem({ item, isChecked: true }) - } else { - selectedListRef.current.splice(index, 1) - // setSelectedItem({ item, isChecked: false }) - } - } else { - if (selectedListRef.current.length) { - const prevIndex = prevSelectIndexRef.current - const currentIndex = index - if (prevIndex == currentIndex) { - selectedListRef.current = [] - } else if (currentIndex > prevIndex) { - selectedListRef.current = currentListRef.current.list.slice(prevIndex, currentIndex + 1) - } else { - selectedListRef.current = currentListRef.current.list.slice(currentIndex, prevIndex + 1) - selectedListRef.current.reverse() - } - } else { - selectedListRef.current.push(item) - prevSelectIndexRef.current = index - } - } - setSelectedList([...selectedListRef.current]) - }, []) - const handleSelectAll = useCallback(() => { - if (!currentListRef.current.list.length) return - if (selectedListRef.current.length == currentListRef.current.list.length) { - selectedListRef.current = [] - } else { - selectedListRef.current = [...currentListRef.current.list] - } - setSelectedList([...selectedListRef.current]) - }, []) - - const handleSetSelectMode = useCallback(mode => { - setSelectMode(mode) - selectModeRef.current = mode - if (mode == 'range' && selectedListRef.current.length) { - prevSelectIndexRef.current = currentListRef.current.list.indexOf(selectedListRef.current[selectedListRef.current.length - 1]) - } - }, []) - - const handleCancelMultiSelect = useCallback(() => { - setIsMultiSelectMode(false) - isMultiSelectModeRef.current = false - selectedListRef.current = [] - setSelectedList([]) - }, []) - - const handlePress = useCallback((item, index) => { - if (isMultiSelectModeRef.current) { - handleSelect(item, index) - } else { - handlePlay(item, index) - } - }, [handlePlay, handleSelect]) - - const handleLongPress = useCallback((item, index) => { - setIsMultiSelectMode(true) - isMultiSelectModeRef.current = true - handleSelect(item, index) - }, [handleSelect]) - - const menus = useMemo(() => { - return [ - { action: 'play', label: t('play') }, - { action: 'playLater', label: t('play_later') }, - // { action: 'download', label: '下载' }, - { action: 'add', label: t('add_to') }, - { action: 'move', label: t('move_to') }, - { action: 'copyName', label: t('copy_name') }, - { action: 'changePosition', label: t('change_position') }, - { action: 'remove', label: t('delete') }, - ] - }, [t]) - - const showMenu = useCallback((item, index, position) => { - // console.log(position) - setButtonPosition({ ...position }) - selectedDataRef.current.data = item - selectedDataRef.current.index = index - setVisibleMenu(true) - }, [setButtonPosition]) - - const hideMenu = useCallback(() => { - setVisibleMenu(false) - }, [setVisibleMenu]) - - const handleMenuPress = useCallback(({ action }) => { - switch (action) { - case 'play': - handlePlay(selectedDataRef.current.data, selectedDataRef.current.index) - break - case 'playLater': - if (selectedListRef.current.length) { - setTempPlayList(selectedListRef.current.map(s => ({ listId: activeListIdRef.current, musicInfo: s }))) - handleCancelMultiSelect() - } else { - setTempPlayList([{ listId: activeListIdRef.current, musicInfo: selectedDataRef.current.data }]) - } - break - case 'add': - isMoveRef.current = false - selectedListRef.current.length - ? setVisibleMusicMultiAddModal(true) - : setVisibleMusicAddModal(true) - break - case 'move': - isMoveRef.current = true - selectedListRef.current.length - ? setVisibleMusicMultiAddModal(true) - : setVisibleMusicAddModal(true) - break - case 'copyName': - shareMusic(shareType, downloadFileName, selectedDataRef.current.data) - break - case 'changePosition': - setVIsibleMusicPosition(true) - break - case 'remove': - if (selectedListRef.current.length) { - removeListMultiItem({ listId: activeListIdRef.current, ids: selectedListRef.current.map(s => s.songmid) }) - handleCancelMultiSelect() - } else { - removeListItem({ listId: activeListIdRef.current, id: selectedDataRef.current.data.songmid }) - } - break - default: - break - } - }, [handlePlay, shareType, setTempPlayList, handleCancelMultiSelect, downloadFileName, removeListMultiItem, removeListItem]) - - const handleScroll = useCallback(({ nativeEvent }) => { - saveListScrollPosition(currentListRef.current.id, nativeEvent.contentOffset.y) - }, []) - - const hideMusicAddModal = useCallback(() => { - setVisibleMusicAddModal(false) - }, []) - - const hideMusicMultiAddModal = useCallback(() => { - setVisibleMusicMultiAddModal(false) - }, []) - - const jumpPosition = useCallback(() => { - if (activeIndexRef.current < 0) return - global.requestAnimationFrame(() => { - flatListRef.current.scrollToIndex({ index: activeIndexRef.current, viewPosition: 0.3, animated: true }) - setJumpPosition(false) - }) - }, [setJumpPosition]) - - const hideMusicPositionModal = useCallback(() => { - setVIsibleMusicPosition(false) - }, []) - const handleSetMusicPosition = useCallback(num => { - num = Math.min(parseInt(num), currentListRef.current.list.length) - setMusicPosition({ - id: activeListIdRef.current, - position: num, - list: selectedListRef.current.length ? [...selectedListRef.current] : [selectedDataRef.current.data], - }) - setVIsibleMusicPosition(false) - handleCancelMultiSelect() - }, [handleCancelMultiSelect, setMusicPosition]) - - const handleHideSearchBar = useCallback(() => { - setListSearchBarVisible(false) - setListSearchListVisible(false) - }, []) - - const handleSearchBarTextChange = useCallback(text => { - setListSearchBarText(text) - if (!text.length) setListSearchList([]) - debounceSearchList(text, currentList.list, list => { - setListSearchList(list) - }) - }, [currentList]) - const showListSearchBar = useCallback(() => { - setListSearchBarVisible(true) - }, []) - const handleSearchListItemPress = useCallback(item => { - const index = currentList.list.findIndex(s => s.songmid == item.songmid) - if (index < 0) return - flatListRef.current.scrollToIndex({ index, viewPosition: 0.3, animated: true }) - handleHideSearchBar() - }, [currentList, handleHideSearchBar]) - const handleRenderSearchListItem = useCallback((item, index) => { - return ( - <Button style={styles.searchListItem} onPress={() => handleSearchListItemPress(item)} key={index}> - <View style={styles.searchListItemName}> - <Text numberOfLines={1} style={{ ...styles.searchListItemNameText, color: theme.normal, fontSize: 14 }}>{item.name}</Text> - <Text numberOfLines={1} style={{ ...styles.searchListItemNameText, color: theme.normal30, fontSize: 11 }}>{item.singer} ({item.albumName})</Text> - </View> - <Text style={{ ...styles.searchListItemSource, color: theme.normal40 }}>{item.source}</Text> - </Button> - ) - }, [handleSearchListItemPress, theme]) - - useEffect(() => { - if (listSearchList.length && listSearchBarVisible) { - if (listSearchListVisible) return - setListSearchListVisible(true) - } else { - if (!listSearchListVisible) return - setListSearchListVisible(false) - } - }, [listSearchList.length, listSearchListVisible, listSearchBarVisible]) - - - useEffect(() => { - const offset = getListScrollPosition(currentList.id) - flatListRef.current.scrollToOffset({ offset, animated: false }) - // global.requestAnimationFrame(() => { - // flatListRef.current.scrollToOffset({ offset, animated: false }) - // }) - }, [currentList.id]) - useEffect(() => { - if (!isJumpPosition) return - jumpPosition() - }, [isJumpPosition, jumpPosition]) - - const renderItem = useCallback(({ item, index }) => ( - <ListItem - item={item} - index={index} - activeIndex={activeIndex} - onPress={handlePress} - showMenu={showMenu} - selectedList={selectedList} - handleLongPress={handleLongPress} /> - ), [activeIndex, handleLongPress, handlePress, selectedList, showMenu]) - - const listComponent = useMemo(() => ( - <FlatList - ref={flatListRef} - onScroll={handleScroll} - style={styles.list} - data={currentList.list} - maxToRenderPerBatch={8} - updateCellsBatchingPeriod={80} - windowSize={18} - removeClippedSubviews={true} - initialNumToRender={12} - renderItem={renderItem} - keyExtractor={item => String(item.songmid)} - extraData={activeItemId} - getItemLayout={(data, index) => ({ length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index })} /> - ), [activeItemId, currentList.list, handleScroll, renderItem]) - - return ( - <View style={styles.container}> - <View> - <MyList - currentList={currentList} - activeListIdRef={activeListIdRef} - handleCancelMultiSelect={handleCancelMultiSelect} - showListSearchBar={showListSearchBar} /> - <ExitMultipleModeBar - multipleMode={isMultiSelectMode} - onCancel={handleCancelMultiSelect} - onSwitchMode={handleSetSelectMode} - onSelectAll={handleSelectAll} - selectMode={selectMode} - isSelectAll={selectedList.length && currentList.list.length == selectedList.length} /> - <ListSearchBar - visible={listSearchBarVisible} - onHide={handleHideSearchBar} - text={listSearchBarText} - onChangeText={handleSearchBarTextChange} - /> - </View> - <View style={{ flex: 1 }} onLayout={onLayout}> - {listComponent} - <SearchTipList - list={listSearchList} - renderItem={handleRenderSearchListItem} - visible={listSearchListVisible} - height={listLayout.height} - /> - </View> - <Menu menus={menus} buttonPosition={buttonPosition} onPress={handleMenuPress} visible={visibleMenu} hideMenu={hideMenu} /> - <MusicPositionModal - selectedList={selectedListRef.current} - selectedData={selectedDataRef.current.data} - visible={visibleMusicPosition} - hideModal={hideMusicPositionModal} - onConfirm={handleSetMusicPosition} /> - <MusicAddModal - visible={visibleMusicAddModal} - listId={activeListIdRef.current} - isMove={isMoveRef.current} - hideModal={hideMusicAddModal} - musicInfo={selectedDataRef.current.data} /> - <MusicMultiAddModal - visible={visibleMusicMultiAddModal} - hideModal={hideMusicMultiAddModal} - list={selectedListRef.current} - listId={activeListIdRef.current} - isMove={isMoveRef.current} - excludeList={[activeListIdRef.current]} - onAdd={handleCancelMultiSelect} /> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - list: { - flexGrow: 1, - flexShrink: 1, - }, - searchListItem: { - padding: 10, - flexDirection: 'row', - alignItems: 'center', - }, - searchListItemName: { - flexGrow: 1, - flexShrink: 1, - }, - searchListItemNameText: { - fontSize: 14, - }, - searchListItemSource: { - flexGrow: 0, - flexShrink: 0, - fontSize: 11, - }, -}) - -export default List diff --git a/src/screens/Home/List/utils.js b/src/screens/Home/List/utils.js deleted file mode 100644 index b3b4f5518..000000000 --- a/src/screens/Home/List/utils.js +++ /dev/null @@ -1,74 +0,0 @@ -import { debounce } from '@/utils' - - -// https://blog.csdn.net/xcxy2015/article/details/77164126#comments -const similar = (a, b) => { - if (!a || !b) return 0 - if (a.length > b.length) { // 保证 a <= b - let t = b - b = a - a = t - } - let al = a.length - let bl = b.length - let mp = [] // 一个表 - let i, j, ai, lt, tmp // ai:字符串a的第i个字符。 lt:左上角的值。 tmp:暂存新的值。 - for (i = 0; i <= bl; i++) mp[i] = i - for (i = 1; i <= al; i++) { - ai = a.charAt(i - 1) - lt = mp[0] - mp[0] = mp[0] + 1 - for (j = 1; j <= bl; j++) { - tmp = Math.min(mp[j] + 1, mp[j - 1] + 1, lt + (ai == b.charAt(j - 1) ? 0 : 1)) - lt = mp[j] - mp[j] = tmp - } - } - return 1 - (mp[bl] / bl) -} - -const sortInsert = (arr, data) => { - let key = data.num - let left = 0 - let right = arr.length - 1 - - while (left <= right) { - let middle = parseInt((left + right) / 2) - if (key == arr[middle]) { - left = middle - break - } else if (key < arr[middle].num) { - right = middle - 1 - } else { - left = middle + 1 - } - } - while (left > 0) { - if (arr[left - 1].num != key) break - left-- - } - - arr.splice(left, 0, data) -} - -const handleSortList = (list, keyword) => { - let arr = [] - for (const item of list) { - sortInsert(arr, { - num: similar(keyword, `${item.name} ${item.singer} ${item.albumName || ''}`), - data: item, - }) - } - return arr.map(item => item.data).reverse() -} - -export const debounceSearchList = debounce((text, list, callback) => { - const reslutList = [] - if (!text.length) return - let rxp = new RegExp(text.split('').map(s => s.replace(/[.*+?^${}()|[\]\\]/, '\\$&')).join('.*') + '.*', 'i') - for (const item of list) { - if (rxp.test(`${item.name}${item.singer}${item.albumName ? item.albumName : ''}`)) reslutList.push(item) - } - // console.log(reslutList) - callback(handleSortList(reslutList, text)) -}, 200) diff --git a/src/screens/Home/Search/components/Input.js b/src/screens/Home/Search/components/Input.js deleted file mode 100644 index b7cabe1fa..000000000 --- a/src/screens/Home/Search/components/Input.js +++ /dev/null @@ -1,82 +0,0 @@ -import React, { useCallback, useRef, forwardRef, useImperativeHandle } from 'react' -// import { StyleSheet } from 'react-native' -import Input from '@/components/common/Input' - -import music from '@/utils/music' -import { useGetter, useDispatch } from '@/store' -import { debounce } from '@/utils' - -const debounceTipSearch = debounce((str, tempSearchSource, callback) => { - return music[tempSearchSource]?.tempSearch.search(str).then(callback) ?? Promise.reject(new Error('source not found')) -}, 200) - -export default forwardRef(({ onSetTipList, setPage }, ref) => { - const searchInputRef = useRef() - const text = useGetter('search', 'text') - - const tempSearchSource = useGetter('search', 'tempSearchSource') - // const searchSource = useGetter('search', 'searchSource') - const listInfo = useGetter('search', 'listInfo') - const setText = useDispatch('search', 'setText') - const search = useDispatch('search', 'search') - - const tipListVisible = useGetter('search', 'tipListVisible') - const setVisibleTipList = useDispatch('search', 'setVisibleTipList') - - - useImperativeHandle(ref, () => { - return { - blur() { - searchInputRef.current.blur() - }, - isFocused() { - return searchInputRef.current.isFocused() - }, - } - }) - - const showTipList = useCallback(() => { - if (tipListVisible || !text.length) return - setVisibleTipList(true) - }, [tipListVisible, setVisibleTipList, text]) - - const hideTipList = useCallback(() => { - if (!tipListVisible) return - setVisibleTipList(false) - }, [tipListVisible, setVisibleTipList]) - - const handleSearchInput = useCallback(str => { - setText(str) - if (str.length) { - debounceTipSearch(str, tempSearchSource, onSetTipList) - } else { - music[tempSearchSource]?.tempSearch.search('') - hideTipList() - } - }, [setText, hideTipList, tempSearchSource, onSetTipList]) - - const handleSearch = useCallback((text) => { - setText(text.trim()) - setPage(1) - return search({ page: 1, limit: listInfo.limit }) - }, [setText, setPage, search, listInfo.limit]) - - const onClearText = useCallback(() => { - handleSearchInput('') - handleSearch('') - }, [handleSearchInput, handleSearch]) - - return ( - <Input - onChangeText={handleSearchInput} - placeholder="Search for something..." - value={text} - // onFocus={showTipList} - clearBtn - ref={searchInputRef} - onBlur={hideTipList} - onSubmitEditing={ ({ nativeEvent: { text } }) => handleSearch(text) } - onClearText={onClearText} - onTouchStart={showTipList} /> - ) -}) diff --git a/src/screens/Home/Search/components/MusicList.js b/src/screens/Home/Search/components/MusicList.js deleted file mode 100644 index b3b8b05bc..000000000 --- a/src/screens/Home/Search/components/MusicList.js +++ /dev/null @@ -1,67 +0,0 @@ -import React, { useState, useCallback, memo, useEffect, useRef } from 'react' -import { InteractionManager } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import OnlineList from '@/components/OnlineList' - -export default memo(({ page, setPage }) => { - const [isListRefreshing, setIsListRefreshing] = useState(false) - const [visibleLoadingMask, setVisibleLoadingMask] = useState(false) - const text = useGetter('search', 'text') - const textRef = useRef(text) - const searchSource = useGetter('search', 'searchSource') - const listInfo = useGetter('search', 'listInfo') - const isLoading = useGetter('search', 'isLoading') - const isEnd = useGetter('search', 'isEnd') - const search = useDispatch('search', 'search') - const listInfoRef = useRef(listInfo) - - useEffect(() => { - textRef.current = text - }, [text]) - - const handleRefresh = useCallback(() => { - setIsListRefreshing(true) - setVisibleLoadingMask(true) - setPage(1) - search({ page: 1, limit: listInfoRef.current.limit }).finally(() => { - setIsListRefreshing(false) - setVisibleLoadingMask(false) - }) - }, [search, setPage]) - - const handleLoadMore = useCallback(() => { - if (isLoading || isEnd || !textRef.current.length) return - setPage(listInfoRef.current.page + 1) - search({ page: listInfoRef.current.page + 1, limit: listInfoRef.current.limit }) - }, [isLoading, isEnd, setPage, search]) - - useEffect(() => { - listInfoRef.current = listInfo - }, [listInfo]) - - useEffect(() => { - InteractionManager.runAfterInteractions(() => { - setVisibleLoadingMask(true) - setPage(1) - search({ page: 1, limit: listInfo.limit }).finally(() => { - setIsListRefreshing(false) - setVisibleLoadingMask(false) - }) - }) - }, [searchSource, search, setIsListRefreshing, listInfo.limit, setPage]) - - return ( - <OnlineList - list={listInfo.list} - isEnd={isEnd} - page={page} - isListRefreshing={isListRefreshing} - onRefresh={handleRefresh} - onLoadMore={handleLoadMore} - // progressViewOffset={20} - isLoading={isLoading} - visibleLoadingMask={isLoading && visibleLoadingMask} - /> - ) -}) - diff --git a/src/screens/Home/Search/components/SourceSelector.js b/src/screens/Home/Search/components/SourceSelector.js deleted file mode 100644 index f31f6a9b2..000000000 --- a/src/screens/Home/Search/components/SourceSelector.js +++ /dev/null @@ -1,47 +0,0 @@ -import React, { memo, useMemo } from 'react' -import { StyleSheet, Text, View } from 'react-native' - -import DorpDownMenu from '@/components/common/DorpDownMenu' -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' -import { useLayout } from '@/utils/hooks' - - -export default memo(() => { - const setSearchSource = useDispatch('common', 'setSearchSource') - const sourceList = useGetter('search', 'sources') - const searchSource = useGetter('search', 'searchSource') - const sourceNameType = useGetter('common', 'sourceNameType') - const theme = useGetter('common', 'theme') - // const currentSourceName = useGetter('search', 'currentSourceName') - const { t } = useTranslation() - const { onLayout, ...layout } = useLayout() - - const sourceList_t = useMemo(() => { - return sourceList.map(s => ({ label: t(`source_${sourceNameType}_${s.id}`), action: s.id })) - }, [sourceNameType, sourceList, t]) - - return ( - <DorpDownMenu - menus={sourceList_t} - width={layout.width} - onPress={({ action }) => setSearchSource({ searchSource: action })} - > - <View style={styles.sourceMenu} onLayout={onLayout}> - <Text style={{ color: theme.normal }}>{t(`source_${sourceNameType}_${searchSource}`)}</Text> - </View> - </DorpDownMenu> - ) -}) - - -const styles = StyleSheet.create({ - sourceMenu: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - paddingLeft: 12, - paddingRight: 12, - // width: 80, - }, -}) diff --git a/src/screens/Home/Search/components/TipList.js b/src/screens/Home/Search/components/TipList.js deleted file mode 100644 index 668b0b142..000000000 --- a/src/screens/Home/Search/components/TipList.js +++ /dev/null @@ -1,58 +0,0 @@ -import React, { useCallback, memo, useEffect, useState, useMemo } from 'react' -import { StyleSheet, Text } from 'react-native' - -import Button from '@/components/common/Button' -import SearchTipList from '@/components/searchTipList' -import { useGetter, useDispatch } from '@/store' - -export default memo(({ onTipPress, height }) => { - // const tipList = useGetter('search', 'tipList') - - const text = useGetter('search', 'text') - const list = useGetter('search', 'tipList') - const visible = useGetter('search', 'tipListVisible') - const setVisibleTipList = useDispatch('search', 'setVisibleTipList') - const theme = useGetter('common', 'theme') - - const hideTipList = useCallback(() => { - setVisibleTipList(false) - }, []) - - useEffect(() => { - if (visible && !text.length) hideTipList() - }, []) - - const handleTipPress = useCallback(text => { - hideTipList() - onTipPress(text) - }, [onTipPress, hideTipList]) - - const handleRenderItem = useCallback((item, index) => { - return ( - <Button onPress={() => handleTipPress(item)} key={index}> - <Text style={{ ...styles.text, color: theme.normal }}>{item}</Text> - </Button> - ) - }, [handleTipPress, theme]) - - // console.log(visible) - return ( - <SearchTipList - list={list} - visible={visible} - height={height} - hideList={hideTipList} - renderItem={handleRenderItem} - /> - ) -}) - -const styles = StyleSheet.create({ - text: { - paddingTop: 10, - paddingBottom: 10, - paddingLeft: 10, - paddingRight: 10, - // color: 'white', - }, -}) diff --git a/src/screens/Home/Search/index.js b/src/screens/Home/Search/index.js deleted file mode 100644 index 5dc8f23ab..000000000 --- a/src/screens/Home/Search/index.js +++ /dev/null @@ -1,87 +0,0 @@ -import React, { useCallback, useRef, useState, useEffect } from 'react' -import { StyleSheet, View } from 'react-native' - -import music from '@/utils/music' -import { useGetter, useDispatch } from '@/store' -import { BorderWidths } from '@/theme' -// import InsetShadow from 'react-native-inset-shadow' -import SourceSelector from './components/SourceSelector' -import Input from './components/Input' -import TipList from './components/TipList' -import MusicList from './components/MusicList' -import { useLayout } from '@/utils/hooks' - - -export default () => { - const searchInputRef = useRef() - const theme = useGetter('common', 'theme') - const tempSearchSource = useGetter('search', 'tempSearchSource') - const tempSearchSourceRef = useRef('') - const listInfo = useGetter('search', 'listInfo') - const listInfoRef = useRef({}) - const tipListVisible = useGetter('search', 'tipListVisible') - const tipListVisibleRef = useRef('') - const setText = useDispatch('search', 'setText') - const setTipList = useDispatch('search', 'setTipList') - const setVisibleTipList = useDispatch('search', 'setVisibleTipList') - const search = useDispatch('search', 'search') - const { onLayout, ...listLayout } = useLayout() - const [page, setPage] = useState(0) - - useEffect(() => { - listInfoRef.current = listInfo - }, [listInfo]) - useEffect(() => { - tempSearchSourceRef.current = tempSearchSource - }, [tempSearchSource]) - useEffect(() => { - tipListVisibleRef.current = tipListVisible - }, [tipListVisible]) - - const handleTipPress = useCallback(text => { - if (tipListVisibleRef.current) setVisibleTipList(false) - text = text.trim() - music[tempSearchSourceRef.current].tempSearch.search(text).then(tipList => setTipList(tipList)) - searchInputRef.current.blur() - setText(text) - setPage(1) - search({ page: 1, limit: listInfoRef.current.limit }) - }, []) - - const onSetTipList = list => { - setTipList(list) - if (list.length) { - if (tipListVisibleRef.current) return - } else if (!tipListVisibleRef.current) return - if (searchInputRef.current.isFocused()) setVisibleTipList(true) - } - - return ( - <View style={styles.container}> - <View style={{ ...styles.searchBar, backgroundColor: theme.primary, borderBottomColor: theme.borderColor, borderBottomWidth: BorderWidths.normal }}> - <SourceSelector /> - <Input ref={searchInputRef} onSetTipList={onSetTipList} setPage={setPage} /> - </View> - <View style={styles.content} onLayout={onLayout}> - <TipList onTipPress={handleTipPress} height={listLayout.height} /> - <MusicList page={page} setPage={setPage} /> - </View> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - width: '100%', - flex: 1, - }, - content: { - flex: 1, - }, - searchBar: { - flexDirection: 'row', - height: 38, - zIndex: 2, - paddingRight: 5, - }, -}) diff --git a/src/screens/Home/Setting/Backup/Part.js b/src/screens/Home/Setting/Backup/Part.js deleted file mode 100644 index 9890aca73..000000000 --- a/src/screens/Home/Setting/Backup/Part.js +++ /dev/null @@ -1,265 +0,0 @@ -import React, { memo, useCallback, useState, useRef } from 'react' -import { StyleSheet, View, InteractionManager } from 'react-native' -import { log } from '@/utils/log' -import { LXM_FILE_EXT_RXP } from '@/config/constant' - -import { useGetter, useDispatch } from '@/store' -// import { gzip, ungzip } from 'pako' - -import SubTitle from '../components/SubTitle' -import Button from '../components/Button' -import ChoosePath from '@/components/common/ChoosePath' -import { useTranslation } from '@/plugins/i18n' -import { toast, handleSaveFile, handleReadFile, confirmDialog, showImportTip } from '@/utils/tools' -import { toOldMusicInfo } from '@/utils/listData' - -const exportAllList = async(allList, path) => { - const data = JSON.parse(JSON.stringify({ - type: 'playList', - data: allList, - })) - for (const list of data.data) { - for (const item of list.list) { - if (item.otherSource) delete item.otherSource - } - } - try { - await handleSaveFile(path + '/lx_list.lxmc', data) - } catch (error) { - log.error(error.stack) - } -} -const importAllList = async path => { - let listData - try { - listData = await handleReadFile(path) - } catch (error) { - log.error(error.stack) - return - } - console.log(listData.type) - return listData -} - -const handleSetList = (setList, lists) => { - if (!lists.length) return Promise.resolve() - const list = lists.shift() - for (const item of list.list) { - if (item.otherSource) item.otherSource = null - if (item.typeUrl['128k']) delete item.typeUrl['128k'] - if (item.typeUrl['320k']) delete item.typeUrl['320k'] - if (item.typeUrl.flac) delete item.typeUrl.flac - if (item.typeUrl.wav) delete item.typeUrl.wav - - // PC v1.8.2以前的Lyric - if (item.lxlrc) delete item.lxlrc - if (item.lrc) delete item.lrc - if (item.tlrc) delete item.tlrc - } - return setList(list).then(() => handleSetList(setList, lists)).catch(err => { - toast(err.message) - log.error(err.message) - return handleSetList(setList, lists) - }) -} - -const handleSetListV2 = (setList, lists) => { - if (!lists.length) return Promise.resolve() - const list = lists.shift() - list.list = list.list.map(m => toOldMusicInfo(m)) - return setList(list).then(() => handleSetListV2(setList, lists)).catch(err => { - toast(err.message) - log.error(err.message) - return handleSetListV2(setList, lists) - }) -} - -export default memo(() => { - const { t } = useTranslation() - const [isShowChoosePath, setShowChoosePath] = useState(false) - const [title, setTitle] = useState('') - const [dirOnly, setDirOnly] = useState(false) - const actionTypeRef = useRef('') - // const setting = useGetter('common', 'setting') - const allList = useGetter('list', 'allList') - const setList = useDispatch('list', 'setList') - const createUserList = useDispatch('list', 'createUserList') - - const importAndExportData = useCallback(async(action, type) => { - setDirOnly(action == 'export') - actionTypeRef.current = `${action}_${type}` - switch (type) { - case 'list': - setTitle(t(`setting_backup_part_${action}_list_desc`)) - break - case 'setting': - setTitle(t(`setting_backup_part_${action}_setting_desc`)) - break - default: - setTitle(t(`setting_backup_all_${action}_desc`)) - break - } - - setShowChoosePath(true) - }, [t]) - - const handleImportPartList = useCallback(async(listData, isV2) => { - const targetList = global.allList[listData.data.id] - if (targetList) { - const confirm = await confirmDialog({ - message: t('list_import_part_confirm', { importName: listData.data.name, localName: targetList.name }), - cancelButtonText: t('list_import_part_button_cancel'), - confirmButtonText: t('list_import_part_button_confirm'), - bgClose: false, - }) - if (confirm) { - listData.data.name = targetList.name - setList({ - name: listData.data.name, - id: listData.data.id, - list: isV2 ? listData.data.list.map(m => toOldMusicInfo(m)) : listData.data.list, - source: listData.data.source, - sourceListId: listData.data.sourceListId, - }) - toast(t('setting_backup_part_import_list_tip_success')) - return - } - listData.data.id += `__${Date.now()}` - } - createUserList({ - name: listData.data.name, - id: listData.data.id, - list: isV2 ? listData.data.list.map(m => toOldMusicInfo(m)) : listData.data.list, - source: listData.data.source, - sourceListId: listData.data.sourceListId, - // position: Math.max(selectedListRef.current.index, -1), - }) - toast(t('setting_backup_part_import_list_tip_success')) - }, [createUserList, setList, t]) - - const onConfirmPath = useCallback(path => { - setShowChoosePath(false) - switch (actionTypeRef.current) { - case 'import_list': - InteractionManager.runAfterInteractions(() => { - toast(t('setting_backup_part_import_list_tip_unzip')) - importAllList(path).then(listData => { - // 兼容0.6.2及以前版本的列表数据 - if (listData.type === 'defautlList') { - handleSetList(setList, [ - { id: 'default', list: listData.data.list, name: '试听列表' }, - ]).then(() => { - toast(t('setting_backup_part_import_list_tip_success')) - }) - return - } - - switch (listData.type) { - case 'playList': - toast(t('setting_backup_part_import_list_tip_runing')) - handleSetList(setList, listData.data).then(() => { - toast(t('setting_backup_part_import_list_tip_success')) - }) - break - case 'allData': - toast(t('setting_backup_part_import_list_tip_runing')) - if (listData.defaultList) { // 兼容pc端 0.6.2及以前版本的列表数据 - handleSetList(setList, [ - { id: 'default', list: listData.defaultList.list, name: '试听列表' }, - ]).then(() => { - toast(t('setting_backup_part_import_list_tip_success')) - }) - } else { - handleSetList(setList, listData.playList).then(() => { - toast(t('setting_backup_part_import_list_tip_success')) - }) - } - toast(t('setting_backup_part_import_list_tip_success')) - break - - case 'playListPart': - handleImportPartList(listData, false) - break - case 'playList_v2': - toast(t('setting_backup_part_import_list_tip_runing')) - handleSetListV2(setList, listData.data).then(() => { - toast(t('setting_backup_part_import_list_tip_success')) - }) - break - case 'allData_v2': - toast(t('setting_backup_part_import_list_tip_runing')) - handleSetListV2(setList, listData.playList).then(() => { - toast(t('setting_backup_part_import_list_tip_success')) - }) - break - case 'playListPart_v2': - handleImportPartList(listData, true) - break - - default: return showImportTip(listData.type) - } - }) - }) - break - // case 'import_setting': - // setTitle(t('setting_backup_part_import_setting_desc')) - // break - // case 'import_all': - // setTitle(t('setting_backup_part_import_setting_desc')) - // break - case 'export_list': - InteractionManager.runAfterInteractions(() => { - toast(t('setting_backup_part_export_list_tip_zip')) - exportAllList(allList, path).then(() => { - toast(t('setting_backup_part_export_list_tip_success')) - }).catch(err => { - log.error(err.message) - toast(t('setting_backup_part_export_list_tip_failed') + ': ' + err.message) - }) - }) - break - // case 'export_setting': - // setTitle(t('setting_backup_part_import_setting_desc')) - // break - // case 'export_all': - // setTitle(t('setting_backup_part_import_setting_desc')) - // break - // default: - // setTitle(t('setting_backup_all_import_desc')) - // break - } - }, [allList, handleImportPartList, setList, t]) - - - return ( - <> - <SubTitle title={t('setting_backup_part')}> - <View style={styles.list}> - <Button onPress={() => importAndExportData('import', 'list')}>{t('setting_backup_part_import_list')}</Button> - <Button onPress={() => importAndExportData('export', 'list')}>{t('setting_backup_part_export_list')}</Button> - {/* <Button onPress={() => importAndExportData('import', 'setting')}>{t('setting_backup_part_import_setting')}</Button> - <Button onPress={() => importAndExportData('export', 'setting')}>{t('setting_backup_part_export_setting')}</Button> */} - </View> - </SubTitle> - {/* <SubTitle title={t('setting_backup_all')}> - <View style={styles.list}> - <Button onPress={() => importAndExportData('import', 'all')}>{t('setting_backup_all_import')}</Button> - <Button onPress={() => importAndExportData('export', 'all')}>{t('setting_backup_all_export')}</Button> - </View> - </SubTitle> */} - <ChoosePath - visible={isShowChoosePath} - hide={() => setShowChoosePath(false)} - title={title} - dirOnly={dirOnly} - filter={LXM_FILE_EXT_RXP} - onConfirm={onConfirmPath} /> - </> - ) -}) - -const styles = StyleSheet.create({ - list: { - flexDirection: 'row', - }, -}) diff --git a/src/screens/Home/Setting/Basic/IsAutoTheme.js b/src/screens/Home/Setting/Basic/IsAutoTheme.js deleted file mode 100644 index 62875acc0..000000000 --- a/src/screens/Home/Setting/Basic/IsAutoTheme.js +++ /dev/null @@ -1,27 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' -import { getIsSupportedAutoTheme } from '@/utils/tools' - -const isSupportedAutoTheme = getIsSupportedAutoTheme() - -export default memo(() => { - const { t } = useTranslation() - const isAutoTheme = useGetter('common', 'isAutoTheme') - const setIsAutoTheme = useDispatch('common', 'setIsAutoTheme') - - - return ( - isSupportedAutoTheme - ? ( - <View style={{ marginTop: 5, marginBottom: 15 }}> - <CheckBoxItem check={isAutoTheme} label={t('setting_basic_theme_auto_theme')} onChange={setIsAutoTheme} /> - </View> - ) - : null - ) -}) diff --git a/src/screens/Home/Setting/Basic/IsStartupAutoPlay.js b/src/screens/Home/Setting/Basic/IsStartupAutoPlay.js deleted file mode 100644 index caa79ae95..000000000 --- a/src/screens/Home/Setting/Basic/IsStartupAutoPlay.js +++ /dev/null @@ -1,20 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' - -export default memo(() => { - const { t } = useTranslation() - const startupAutoPlay = useGetter('common', 'startupAutoPlay') - const setStartupAutoPlay = useDispatch('common', 'setStartupAutoPlay') - - - return ( - <View style={{ marginTop: 5, marginBottom: 15 }}> - <CheckBoxItem check={startupAutoPlay} label={t('setting_basic_startup_auto_play')} onChange={setStartupAutoPlay} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/Basic/Language.js b/src/screens/Home/Setting/Basic/Language.js deleted file mode 100644 index dfc059181..000000000 --- a/src/screens/Home/Setting/Basic/Language.js +++ /dev/null @@ -1,47 +0,0 @@ -import React, { memo, useCallback, useMemo } from 'react' - -import { StyleSheet, View, InteractionManager } from 'react-native' -import { useGetter, useDispatch } from '@/store' - -import SubTitle from '../components/SubTitle' -import { useTranslation, langList } from '@/plugins/i18n' -import CheckBox from '@/components/common/CheckBox' - -const useActive = id => { - const activeLangId = useGetter('common', 'activeLangId') - const isActive = useMemo(() => activeLangId == id, [activeLangId, id]) - return isActive -} - -const Item = ({ id, name, setLang }) => { - const isActive = useActive(id) - // const [toggleCheckBox, setToggleCheckBox] = useState(false) - return <CheckBox marginRight={8} check={isActive} label={name} onChange={() => setLang(id)} need /> -} - -export default memo(() => { - const { t } = useTranslation() - const setLang = useDispatch('common', 'setLang') - const setLangId = useCallback((id) => { - InteractionManager.runAfterInteractions(() => { - setLang(id) - }) - }, [setLang]) - - return ( - <SubTitle title={t('setting_basic_lang')}> - <View style={styles.list}> - { - langList.map(({ id, name }) => <Item name={name} id={id} key={id} setLang={setLangId} />) - } - </View> - </SubTitle> - ) -}) - -const styles = StyleSheet.create({ - list: { - flexDirection: 'row', - flexWrap: 'wrap', - }, -}) diff --git a/src/screens/Home/Setting/Basic/ShareType.js b/src/screens/Home/Setting/Basic/ShareType.js deleted file mode 100644 index 42dbc1b1e..000000000 --- a/src/screens/Home/Setting/Basic/ShareType.js +++ /dev/null @@ -1,55 +0,0 @@ -import React, { memo, useMemo } from 'react' - -import { StyleSheet, View } from 'react-native' -import { useGetter, useDispatch } from '@/store' - -import SubTitle from '../components/SubTitle' -import { useTranslation } from '@/plugins/i18n' -import CheckBox from '@/components/common/CheckBox' - - -const useActive = id => { - const shareType = useGetter('common', 'shareType') - const isActive = useMemo(() => shareType == id, [shareType, id]) - return isActive -} - -const Item = ({ id, name, change }) => { - const isActive = useActive(id) - // const [toggleCheckBox, setToggleCheckBox] = useState(false) - return <CheckBox marginBottom={3} check={isActive} label={name} onChange={() => change(id)} need /> -} - -export default memo(() => { - const { t } = useTranslation() - const setShareType = useDispatch('common', 'setShareType') - const list = useMemo(() => [ - { - id: 'system', - name: t('setting_basic_share_type_system'), - }, - { - id: 'clipboard', - name: t('setting_basic_share_type_clipboard'), - }, - ], [t]) - - return ( - <SubTitle title={t('setting_basic_share_type')}> - <View style={styles.list}> - { - list.map(({ id, name }) => <Item name={name} id={id} key={id} change={setShareType} />) - } - </View> - </SubTitle> - ) -}) - -const styles = StyleSheet.create({ - list: { - flexGrow: 0, - flexShrink: 1, - flexDirection: 'row', - flexWrap: 'wrap', - }, -}) diff --git a/src/screens/Home/Setting/Basic/SourceName.js b/src/screens/Home/Setting/Basic/SourceName.js deleted file mode 100644 index e50f6096e..000000000 --- a/src/screens/Home/Setting/Basic/SourceName.js +++ /dev/null @@ -1,59 +0,0 @@ -import React, { memo, useCallback, useMemo } from 'react' - -import { StyleSheet, View, InteractionManager } from 'react-native' -import { useGetter, useDispatch } from '@/store' - -import SubTitle from '../components/SubTitle' -import { useTranslation } from '@/plugins/i18n' -import CheckBox from '@/components/common/CheckBox' - -const useActive = id => { - const activeId = useGetter('common', 'sourceNameType') - const isActive = useMemo(() => activeId == id, [activeId, id]) - return isActive -} - -const Item = ({ id, name, change }) => { - const isActive = useActive(id) - // const [toggleCheckBox, setToggleCheckBox] = useState(false) - return <CheckBox marginBottom={3} check={isActive} label={name} onChange={() => change(id)} need /> -} - -export default memo(() => { - const { t } = useTranslation() - const setSourceNameType = useDispatch('common', 'setSourceNameType') - const list = useMemo(() => [ - { - id: 'real', - name: t('setting_basic_sourcename_real'), - }, - { - id: 'alias', - name: t('setting_basic_sourcename_alias'), - }, - ], [t]) - const setSourceNameTypeId = useCallback((id) => { - InteractionManager.runAfterInteractions(() => { - setSourceNameType(id) - }) - }, [setSourceNameType]) - - return ( - <SubTitle title={t('setting_basic_sourcename')}> - <View style={styles.list}> - { - list.map(({ id, name }) => <Item name={name} id={id} key={id} change={setSourceNameTypeId} />) - } - </View> - </SubTitle> - ) -}) - -const styles = StyleSheet.create({ - list: { - flexGrow: 0, - flexShrink: 1, - flexDirection: 'row', - flexWrap: 'wrap', - }, -}) diff --git a/src/screens/Home/Setting/Basic/Theme.js b/src/screens/Home/Setting/Basic/Theme.js deleted file mode 100644 index d1b765dc8..000000000 --- a/src/screens/Home/Setting/Basic/Theme.js +++ /dev/null @@ -1,85 +0,0 @@ -import React, { memo, useCallback, useMemo } from 'react' - -import { StyleSheet, View, Text, ImageBackground, TouchableOpacity, InteractionManager } from 'react-native' -import { useGetter, useDispatch } from '@/store' - -import SubTitle from '../components/SubTitle' -import { useTranslation } from '@/plugins/i18n' - -const useActive = id => { - const activeThemeId = useGetter('common', 'activeThemeId') - const isActive = useMemo(() => activeThemeId == id, [activeThemeId, id]) - return isActive -} - -const ThemeItem = ({ id, color, image, setTheme }) => { - const theme = useGetter('common', 'theme') - const isActive = useActive(id) - const { t } = useTranslation() - return ( - <TouchableOpacity style={styles.item} activeOpacity={0.5} onPress={() => setTheme(id)}> - <View style={{ ...styles.colorContent, backgroundColor: theme.primary, borderColor: isActive ? color : 'transparent' }}> - { - image - ? <ImageBackground source={image} style={styles.image} /> - : <View style={{ ...styles.image, backgroundColor: color }}></View> - } - </View> - <Text style={{ ...styles.name, color: isActive ? color : theme.normal }} numberOfLines={1}>{t(`theme_${id}`)}</Text> - </TouchableOpacity> - ) -} - -export default memo(() => { - const { t } = useTranslation() - const themeList = useGetter('common', 'themeList') - const themes = useMemo(() => themeList.map(theme => ({ id: theme.id, color: theme.colors.secondary })), [themeList]) - const setTheme = useDispatch('common', 'setTheme') - const setThemeId = useCallback((id) => { - InteractionManager.runAfterInteractions(() => { - setTheme(id) - }) - }, [setTheme]) - - return ( - <SubTitle title={t('setting_basic_theme')}> - <View style={styles.list}> - { - themes.map(({ id, color, image }) => <ThemeItem key={id} color={color} image={image} id={id} setTheme={setThemeId} />) - } - </View> - </SubTitle> - ) -}) - -const styles = StyleSheet.create({ - list: { - flexDirection: 'row', - flexWrap: 'wrap', - }, - item: { - marginRight: 15, - alignItems: 'center', - width: 54, - marginTop: 5, - // backgroundColor: 'rgba(0,0,0,0.2)', - }, - colorContent: { - width: 32, - height: 32, - borderRadius: 4, - borderWidth: 1.6, - alignItems: 'center', - justifyContent: 'center', - }, - image: { - width: 26, - height: 26, - borderRadius: 4, - elevation: 1, - }, - name: { - marginTop: 2, - fontSize: 13, - }, -}) diff --git a/src/screens/Home/Setting/List/AddMusicLocationType.js b/src/screens/Home/Setting/List/AddMusicLocationType.js deleted file mode 100644 index 9e4152794..000000000 --- a/src/screens/Home/Setting/List/AddMusicLocationType.js +++ /dev/null @@ -1,43 +0,0 @@ -import React, { memo, useMemo } from 'react' -import { View, StyleSheet } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import SubTitle from '../components/SubTitle' -import { useTranslation } from '@/plugins/i18n' -import CheckBox from '@/components/common/CheckBox' - - -const useActive = id => { - const addMusicLocationType = useGetter('common', 'addMusicLocationType') - const isActive = useMemo(() => addMusicLocationType == id, [addMusicLocationType, id]) - return isActive -} - -const Item = ({ id, name, change }) => { - const isActive = useActive(id) - // const [toggleCheckBox, setToggleCheckBox] = useState(false) - return <CheckBox marginBottom={3} check={isActive} label={name} onChange={() => change(id)} need /> -} - - -export default memo(() => { - const { t } = useTranslation() - const setAddMusicLocationType = useDispatch('common', 'setAddMusicLocationType') - - return ( - <SubTitle title={t('setting_list_add_music_location_type')}> - <View style={styles.list}> - <Item id="top" change={setAddMusicLocationType} name={t('setting_list_add_music_location_type_top')} /> - <Item id="bottom" change={setAddMusicLocationType} name={t('setting_list_add_music_location_type_bottom')} /> - </View> - </SubTitle> - ) -}) - -const styles = StyleSheet.create({ - list: { - flexDirection: 'row', - flexWrap: 'wrap', - }, -}) diff --git a/src/screens/Home/Setting/List/IsClickPlayList.js b/src/screens/Home/Setting/List/IsClickPlayList.js deleted file mode 100644 index e24c9e66b..000000000 --- a/src/screens/Home/Setting/List/IsClickPlayList.js +++ /dev/null @@ -1,19 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' - -export default memo(() => { - const { t } = useTranslation() - const isClickPlayList = useGetter('common', 'isClickPlayList') - const setIsClickPlayList = useDispatch('common', 'setIsClickPlayList') - - return ( - <View style={{ marginTop: 5, marginBottom: 15 }}> - <CheckBoxItem check={isClickPlayList} onChange={setIsClickPlayList} label={t('setting_list_click_action')} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/LyricDesktop/IsLockLyric.js b/src/screens/Home/Setting/LyricDesktop/IsLockLyric.js deleted file mode 100644 index 755106a74..000000000 --- a/src/screens/Home/Setting/LyricDesktop/IsLockLyric.js +++ /dev/null @@ -1,19 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' - -export default memo(() => { - const { t } = useTranslation() - const isLockDesktopLyric = useGetter('common', 'isLockDesktopLyric') - const setIsLockDesktopLyric = useDispatch('common', 'setIsLockDesktopLyric') - - return ( - <View style={{ marginTop: 5, marginBottom: 15 }}> - <CheckBoxItem check={isLockDesktopLyric} label={t('setting_lyric_desktop_lock')} onChange={setIsLockDesktopLyric} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/LyricDesktop/IsShowLyric.js b/src/screens/Home/Setting/LyricDesktop/IsShowLyric.js deleted file mode 100644 index 278c913b0..000000000 --- a/src/screens/Home/Setting/LyricDesktop/IsShowLyric.js +++ /dev/null @@ -1,55 +0,0 @@ -import React, { memo, useCallback, useState } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import ConfirmAlert from '@/components/common/ConfirmAlert' -import CheckBoxItem from '../components/CheckBoxItem' - -import { useTranslation } from '@/plugins/i18n' -import { toast } from '@/utils/tools' -import { checkOverlayPermission, openOverlayPermissionActivity } from '@/utils/lyricDesktop' - -export default memo(() => { - const { t } = useTranslation() - const isEnableDesktopLyric = useGetter('common', 'isEnableDesktopLyric') - const setIsShowDesktopLyric = useDispatch('common', 'setIsShowDesktopLyric') - const [visibleTips, setVisibleTips] = useState(false) - - const handleChangeEnableDesktopLyric = useCallback(async isEnable => { - if (isEnable) { - try { - await checkOverlayPermission() - await setIsShowDesktopLyric(isEnable) - } catch (err) { - setVisibleTips(true) - return false - } - } else await setIsShowDesktopLyric(isEnable) - return true - }, [setIsShowDesktopLyric]) - - const handleTipsCancel = useCallback(() => { - toast(t('disagree_tip'), 'long') - setVisibleTips(false) - }, [t]) - const handleTipsConfirm = useCallback(() => { - setVisibleTips(false) - openOverlayPermissionActivity() - }, []) - - return ( - <View style={{ marginTop: 5, marginBottom: 15 }}> - <CheckBoxItem check={isEnableDesktopLyric} label={t('setting_lyric_desktop_enable')} onChange={handleChangeEnableDesktopLyric} /> - <ConfirmAlert - visible={visibleTips} - onHide={handleTipsCancel} - onConfirm={handleTipsConfirm} - bgHide={false} - closeBtn={false} - cancelText={t('disagree')} - confirmText={t('agree_go')} - text={t('setting_lyric_dektop_permission_tip')} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/LyricDesktop/IsShowToggleAnima.js b/src/screens/Home/Setting/LyricDesktop/IsShowToggleAnima.js deleted file mode 100644 index 1121c5771..000000000 --- a/src/screens/Home/Setting/LyricDesktop/IsShowToggleAnima.js +++ /dev/null @@ -1,19 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' - -export default memo(() => { - const { t } = useTranslation() - const desktopLyricShowToggleAnima = useGetter('common', 'desktopLyricShowToggleAnima') - const setDesktopLyricShowToggleAnima = useDispatch('common', 'setDesktopLyricShowToggleAnima') - - return ( - <View style={{ marginTop: 5, marginBottom: 15 }}> - <CheckBoxItem check={desktopLyricShowToggleAnima} label={t('setting_lyric_desktop_toggle_anima')} onChange={setDesktopLyricShowToggleAnima} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/LyricDesktop/IsSingleLine.js b/src/screens/Home/Setting/LyricDesktop/IsSingleLine.js deleted file mode 100644 index 95a6e90e2..000000000 --- a/src/screens/Home/Setting/LyricDesktop/IsSingleLine.js +++ /dev/null @@ -1,19 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' - -export default memo(() => { - const { t } = useTranslation() - const desktopLyricSingleLine = useGetter('common', 'desktopLyricSingleLine') - const setDesktopLyricSingleLine = useDispatch('common', 'setDesktopLyricSingleLine') - - return ( - <View style={{ marginTop: 5, marginBottom: 15 }}> - <CheckBoxItem check={desktopLyricSingleLine} label={t('setting_lyric_desktop_single_line')} onChange={setDesktopLyricSingleLine} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/LyricDesktop/MaxLineNum.js b/src/screens/Home/Setting/LyricDesktop/MaxLineNum.js deleted file mode 100644 index b6ea51e8c..000000000 --- a/src/screens/Home/Setting/LyricDesktop/MaxLineNum.js +++ /dev/null @@ -1,56 +0,0 @@ -import React, { memo, useCallback, useState } from 'react' - -import { StyleSheet, View, Text } from 'react-native' -import { useGetter, useDispatch } from '@/store' - -import SubTitle from '../components/SubTitle' -import Slider from '../components/Slider' -import { useTranslation } from '@/plugins/i18n' - - -export default memo(() => { - const { t } = useTranslation() - const maxLineNum = useGetter('common', 'desktopLyricMaxLineNum') - const setDesktopLyricMaxLineNum = useDispatch('common', 'setDesktopLyricMaxLineNum') - const theme = useGetter('common', 'theme') - const [sliderSize, setSliderSize] = useState(maxLineNum) - const [isSliding, setSliding] = useState(false) - const handleSlidingStart = useCallback(value => { - setSliding(true) - }, []) - const handleValueChange = useCallback(value => { - setSliderSize(value) - }, []) - const handleSlidingComplete = useCallback(value => { - if (maxLineNum == value) return - setDesktopLyricMaxLineNum(value) - setSliding(false) - }, [maxLineNum, setDesktopLyricMaxLineNum]) - - return ( - <SubTitle title={t('setting_lyric_desktop_maxlineNum')}> - <View style={styles.content}> - <Text style={{ color: theme.secondary10 }}>{isSliding ? sliderSize : maxLineNum}</Text> - <Slider - minimumValue={1} - maximumValue={8} - onSlidingComplete={handleSlidingComplete} - onValueChange={handleValueChange} - onSlidingStart={handleSlidingStart} - step={1} - value={maxLineNum} - /> - </View> - </SubTitle> - ) -}) - -const styles = StyleSheet.create({ - content: { - flexGrow: 0, - flexShrink: 1, - flexDirection: 'row', - flexWrap: 'wrap', - alignItems: 'center', - }, -}) diff --git a/src/screens/Home/Setting/LyricDesktop/TextOpacity.js b/src/screens/Home/Setting/LyricDesktop/TextOpacity.js deleted file mode 100644 index 862c8250e..000000000 --- a/src/screens/Home/Setting/LyricDesktop/TextOpacity.js +++ /dev/null @@ -1,56 +0,0 @@ -import React, { memo, useCallback, useState } from 'react' - -import { StyleSheet, View, Text } from 'react-native' -import { useGetter, useDispatch } from '@/store' - -import SubTitle from '../components/SubTitle' -import Slider from '../components/Slider' -import { useTranslation } from '@/plugins/i18n' - - -export default memo(() => { - const { t } = useTranslation() - const { opacity } = useGetter('common', 'desktopLyricStyle') - const setDesktopLyricStyle = useDispatch('common', 'setDesktopLyricStyle') - const theme = useGetter('common', 'theme') - const [sliderSize, setSliderSize] = useState(opacity) - const [isSliding, setSliding] = useState(false) - const handleSlidingStart = useCallback(value => { - setSliding(true) - }, []) - const handleValueChange = useCallback(value => { - setSliderSize(value) - }, []) - const handleSlidingComplete = useCallback(value => { - if (opacity == value) return - setDesktopLyricStyle({ opacity: value }) - setSliding(false) - }, [opacity, setDesktopLyricStyle]) - - return ( - <SubTitle title={t('setting_lyric_desktop_text_opacity')}> - <View style={styles.content}> - <Text style={{ color: theme.secondary10 }}>{isSliding ? sliderSize : opacity}</Text> - <Slider - minimumValue={10} - maximumValue={100} - onSlidingComplete={handleSlidingComplete} - onValueChange={handleValueChange} - onSlidingStart={handleSlidingStart} - step={2} - value={opacity} - /> - </View> - </SubTitle> - ) -}) - -const styles = StyleSheet.create({ - content: { - flexGrow: 0, - flexShrink: 1, - flexDirection: 'row', - flexWrap: 'wrap', - alignItems: 'center', - }, -}) diff --git a/src/screens/Home/Setting/LyricDesktop/TextPositionX.js b/src/screens/Home/Setting/LyricDesktop/TextPositionX.js deleted file mode 100644 index 56af568c5..000000000 --- a/src/screens/Home/Setting/LyricDesktop/TextPositionX.js +++ /dev/null @@ -1,48 +0,0 @@ -import React, { memo, useCallback, useMemo } from 'react' - -import { StyleSheet, View } from 'react-native' -import { useGetter, useDispatch } from '@/store' - -import SubTitle from '../components/SubTitle' -import { useTranslation } from '@/plugins/i18n' -import CheckBox from '@/components/common/CheckBox' -import { textPositionX } from '@/utils/lyricDesktop' - -const useActive = id => { - const { x } = useGetter('common', 'desktopLyricTextPosition') - const isActive = useMemo(() => x == id, [x, id]) - return isActive -} - -const Item = ({ id, name, change }) => { - const isActive = useActive(id) - // const [toggleCheckBox, setToggleCheckBox] = useState(false) - return <CheckBox marginBottom={3} check={isActive} label={name} onChange={() => change({ x: id })} need /> -} - -export default memo(() => { - const { t } = useTranslation() - const setDesktopLyricTextPosition = useDispatch('common', 'setDesktopLyricTextPosition') - const list = useMemo(() => { - return textPositionX.map(({ id, value }) => ({ id, name: t('setting_lyric_desktop_text_x_' + id) })) - }, [t]) - - return ( - <SubTitle title={t('setting_lyric_desktop_text_x')}> - <View style={styles.list}> - { - list.map(({ id, name }) => <Item name={name} id={id} key={id} change={setDesktopLyricTextPosition} />) - } - </View> - </SubTitle> - ) -}) - -const styles = StyleSheet.create({ - list: { - flexGrow: 0, - flexShrink: 1, - flexDirection: 'row', - flexWrap: 'wrap', - }, -}) diff --git a/src/screens/Home/Setting/LyricDesktop/TextPositionY.js b/src/screens/Home/Setting/LyricDesktop/TextPositionY.js deleted file mode 100644 index 15996adbb..000000000 --- a/src/screens/Home/Setting/LyricDesktop/TextPositionY.js +++ /dev/null @@ -1,48 +0,0 @@ -import React, { memo, useCallback, useMemo } from 'react' - -import { StyleSheet, View } from 'react-native' -import { useGetter, useDispatch } from '@/store' - -import SubTitle from '../components/SubTitle' -import { useTranslation } from '@/plugins/i18n' -import CheckBox from '@/components/common/CheckBox' -import { textPositionY } from '@/utils/lyricDesktop' - -const useActive = id => { - const { y } = useGetter('common', 'desktopLyricTextPosition') - const isActive = useMemo(() => y == id, [y, id]) - return isActive -} - -const Item = ({ id, name, change }) => { - const isActive = useActive(id) - // const [toggleCheckBox, setToggleCheckBox] = useState(false) - return <CheckBox marginBottom={3} check={isActive} label={name} onChange={() => change({ y: id })} need /> -} - -export default memo(() => { - const { t } = useTranslation() - const setDesktopLyricTextPosition = useDispatch('common', 'setDesktopLyricTextPosition') - const list = useMemo(() => { - return textPositionY.map(({ id }) => ({ id, name: t('setting_lyric_desktop_text_y_' + id) })) - }, [t]) - - return ( - <SubTitle title={t('setting_lyric_desktop_text_y')}> - <View style={styles.list}> - { - list.map(({ id, name }) => <Item name={name} id={id} key={id} change={setDesktopLyricTextPosition} />) - } - </View> - </SubTitle> - ) -}) - -const styles = StyleSheet.create({ - list: { - flexGrow: 0, - flexShrink: 1, - flexDirection: 'row', - flexWrap: 'wrap', - }, -}) diff --git a/src/screens/Home/Setting/LyricDesktop/TextSize.js b/src/screens/Home/Setting/LyricDesktop/TextSize.js deleted file mode 100644 index 88e4bcc0a..000000000 --- a/src/screens/Home/Setting/LyricDesktop/TextSize.js +++ /dev/null @@ -1,56 +0,0 @@ -import React, { memo, useCallback, useState } from 'react' - -import { StyleSheet, View, Text } from 'react-native' -import { useGetter, useDispatch } from '@/store' - -import SubTitle from '../components/SubTitle' -import Slider from '../components/Slider' -import { useTranslation } from '@/plugins/i18n' - - -export default memo(() => { - const { t } = useTranslation() - const { fontSize } = useGetter('common', 'desktopLyricStyle') - const setDesktopLyricStyle = useDispatch('common', 'setDesktopLyricStyle') - const theme = useGetter('common', 'theme') - const [sliderSize, setSliderSize] = useState(fontSize) - const [isSliding, setSliding] = useState(false) - const handleSlidingStart = useCallback(value => { - setSliding(true) - }, []) - const handleValueChange = useCallback(value => { - setSliderSize(value) - }, []) - const handleSlidingComplete = useCallback(value => { - if (fontSize == value) return - setDesktopLyricStyle({ fontSize: value }) - setSliding(false) - }, [fontSize, setDesktopLyricStyle]) - - return ( - <SubTitle title={t('setting_lyric_desktop_text_size')}> - <View style={styles.content}> - <Text style={{ color: theme.secondary10 }}>{isSliding ? sliderSize : fontSize}</Text> - <Slider - minimumValue={100} - maximumValue={500} - onSlidingComplete={handleSlidingComplete} - onValueChange={handleValueChange} - onSlidingStart={handleSlidingStart} - step={2} - value={fontSize} - /> - </View> - </SubTitle> - ) -}) - -const styles = StyleSheet.create({ - content: { - flexGrow: 0, - flexShrink: 1, - flexDirection: 'row', - flexWrap: 'wrap', - alignItems: 'center', - }, -}) diff --git a/src/screens/Home/Setting/LyricDesktop/ViewWidth.js b/src/screens/Home/Setting/LyricDesktop/ViewWidth.js deleted file mode 100644 index dbd31540a..000000000 --- a/src/screens/Home/Setting/LyricDesktop/ViewWidth.js +++ /dev/null @@ -1,56 +0,0 @@ -import React, { memo, useCallback, useState } from 'react' - -import { StyleSheet, View, Text } from 'react-native' -import { useGetter, useDispatch } from '@/store' - -import SubTitle from '../components/SubTitle' -import Slider from '../components/Slider' -import { useTranslation } from '@/plugins/i18n' - - -export default memo(() => { - const { t } = useTranslation() - const width = useGetter('common', 'desktopLyricWidth') - const setDesktopLyricWidth = useDispatch('common', 'setDesktopLyricWidth') - const theme = useGetter('common', 'theme') - const [sliderSize, setSliderSize] = useState(width) - const [isSliding, setSliding] = useState(false) - const handleSlidingStart = useCallback(value => { - setSliding(true) - }, []) - const handleValueChange = useCallback(value => { - setSliderSize(value) - }, []) - const handleSlidingComplete = useCallback(value => { - if (width == value) return - setDesktopLyricWidth(value) - setSliding(false) - }, [width, setDesktopLyricWidth]) - - return ( - <SubTitle title={t('setting_lyric_desktop_view_width')}> - <View style={styles.content}> - <Text style={{ color: theme.secondary10 }}>{isSliding ? sliderSize : width}</Text> - <Slider - minimumValue={10} - maximumValue={100} - onSlidingComplete={handleSlidingComplete} - onValueChange={handleValueChange} - onSlidingStart={handleSlidingStart} - step={1} - value={width} - /> - </View> - </SubTitle> - ) -}) - -const styles = StyleSheet.create({ - content: { - flexGrow: 0, - flexShrink: 1, - flexDirection: 'row', - flexWrap: 'wrap', - alignItems: 'center', - }, -}) diff --git a/src/screens/Home/Setting/Player/IsHandleAudioFocus.js b/src/screens/Home/Setting/Player/IsHandleAudioFocus.js deleted file mode 100644 index a7041782e..000000000 --- a/src/screens/Home/Setting/Player/IsHandleAudioFocus.js +++ /dev/null @@ -1,25 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' -import { toast } from '@/utils/tools' - -export default memo(() => { - const { t } = useTranslation() - const isHandleAudioFocus = useGetter('common', 'isHandleAudioFocus') - const setIsHandleAudioFocus = useDispatch('common', 'setIsHandleAudioFocus') - - const handleSetAudioFocus = flag => { - setIsHandleAudioFocus(flag) - toast(t('setting_play_handle_audio_focus_tip')) - } - - return ( - <View style={{ marginTop: 15 }}> - <CheckBoxItem check={isHandleAudioFocus} label={t('setting_play_handle_audio_focus')} onChange={handleSetAudioFocus} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/Player/IsPlayHighQuality.js b/src/screens/Home/Setting/Player/IsPlayHighQuality.js deleted file mode 100644 index fa52990fe..000000000 --- a/src/screens/Home/Setting/Player/IsPlayHighQuality.js +++ /dev/null @@ -1,20 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' - -export default memo(() => { - const { t } = useTranslation() - const isPlayHighQuality = useGetter('common', 'isPlayHighQuality') - const setIsPlayHighQuality = useDispatch('common', 'setIsPlayHighQuality') - - - return ( - <View style={{ marginTop: 5 }}> - <CheckBoxItem check={isPlayHighQuality} label={t('setting_play_quality')} onChange={setIsPlayHighQuality} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/Player/IsS2T.js b/src/screens/Home/Setting/Player/IsS2T.js deleted file mode 100644 index d8e26938e..000000000 --- a/src/screens/Home/Setting/Player/IsS2T.js +++ /dev/null @@ -1,20 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' - -export default memo(() => { - const { t } = useTranslation() - const isS2t = useGetter('common', 'isS2t') - const setIsS2T = useDispatch('common', 'setIsS2T') - - - return ( - <View style={{ marginTop: 15 }}> - <CheckBoxItem check={isS2t} onChange={setIsS2T} label={t('setting_play_s2t')} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/Player/IsShowLyricRoma.js b/src/screens/Home/Setting/Player/IsShowLyricRoma.js deleted file mode 100644 index c13f84e43..000000000 --- a/src/screens/Home/Setting/Player/IsShowLyricRoma.js +++ /dev/null @@ -1,20 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' - -export default memo(() => { - const { t } = useTranslation() - const isShowLyricRoma = useGetter('common', 'isShowLyricRoma') - const setIsShowLyricRoma = useDispatch('common', 'setIsShowLyricRoma') - - - return ( - <View style={{ marginTop: 15 }}> - <CheckBoxItem check={isShowLyricRoma} onChange={setIsShowLyricRoma} label={t('setting_play_show_roma')} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/Player/IsShowLyricTranslation.js b/src/screens/Home/Setting/Player/IsShowLyricTranslation.js deleted file mode 100644 index 1a27857cb..000000000 --- a/src/screens/Home/Setting/Player/IsShowLyricTranslation.js +++ /dev/null @@ -1,20 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' - -export default memo(() => { - const { t } = useTranslation() - const isShowLyricTranslation = useGetter('common', 'isShowLyricTranslation') - const setIsShowLyricTranslation = useDispatch('common', 'setIsShowLyricTranslation') - - - return ( - <View style={{ marginTop: 15 }}> - <CheckBoxItem check={isShowLyricTranslation} onChange={setIsShowLyricTranslation} label={t('setting_play_show_translation')} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/Player/IsShowNotificationImage.js b/src/screens/Home/Setting/Player/IsShowNotificationImage.js deleted file mode 100644 index 4d3994b6f..000000000 --- a/src/screens/Home/Setting/Player/IsShowNotificationImage.js +++ /dev/null @@ -1,19 +0,0 @@ -import React, { memo } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import CheckBoxItem from '../components/CheckBoxItem' -import { useTranslation } from '@/plugins/i18n' - -export default memo(() => { - const { t } = useTranslation() - const isShowNotificationImage = useGetter('common', 'isShowNotificationImage') - const setIsShowNotificationImage = useDispatch('common', 'setIsShowNotificationImage') - - return ( - <View style={{ marginTop: 15 }}> - <CheckBoxItem check={isShowNotificationImage} onChange={setIsShowNotificationImage} label={t('setting_play_show_notification_image')} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/Player/MaxCache.js b/src/screens/Home/Setting/Player/MaxCache.js deleted file mode 100644 index 9d5ec9847..000000000 --- a/src/screens/Home/Setting/Player/MaxCache.js +++ /dev/null @@ -1,40 +0,0 @@ -import React, { memo, useMemo, useCallback } from 'react' -import { View } from 'react-native' - -import { useGetter, useDispatch } from '@/store' - -import InputItem from '../components/InputItem' -import { useTranslation } from '@/plugins/i18n' -import { toast } from '@/utils/tools' - -export default memo(() => { - const { t } = useTranslation() - const playerCacheSize = useGetter('common', 'playerCacheSize') - const setPlayerCacheSize = useDispatch('common', 'setPlayerCacheSize') - - const size = useMemo(() => { - let size = parseInt(playerCacheSize) - if (size == 0 || Number.isNaN(size)) size = '' - return size.toString() - }, [playerCacheSize]) - - const setSize = useCallback((value, callback) => { - let size = parseInt(value) - if (Number.isNaN(size)) size = 0 - callback(size) - if (playerCacheSize == size) return - setPlayerCacheSize(size) - toast(t('setting_play_cache_size_save_tip')) - }, [playerCacheSize, setPlayerCacheSize, t]) - - return ( - <View style={{ marginTop: 15 }} > - <InputItem - value={size} - label={t('setting_play_cache_size')} - onChange={setSize} - keyboardType="number-pad" - placeholder={t('setting_play_cache_size_no_cache')} /> - </View> - ) -}) diff --git a/src/screens/Home/Setting/Player/index.js b/src/screens/Home/Setting/Player/index.js deleted file mode 100644 index 8719e849b..000000000 --- a/src/screens/Home/Setting/Player/index.js +++ /dev/null @@ -1,57 +0,0 @@ -import React, { memo } from 'react' - -import Section from '../components/Section' -import IsPlayHighQuality from './IsPlayHighQuality' -import IsHandleAudioFocus from './IsHandleAudioFocus' -import IsShowNotificationImage from './IsShowNotificationImage' -import IsShowLyricTranslation from './IsShowLyricTranslation' -import IsShowLyricRoma from './IsShowLyricRoma' -import IsS2T from './IsS2T' -import MaxCache from './MaxCache' -import { useTranslation } from '@/plugins/i18n' - -// import DorpDownMenu from '@/components/common/DorpDownMenu' -// import { useGetter, useDispatch } from '@/store' - -// const playNextModes = [ -// { label: '列表循环', action: 'listLoop' }, -// { label: '列表随机', action: 'random' }, -// { label: '顺序播放', action: 'list' }, -// { label: '单曲循环', action: 'singleLoop' }, -// ] - -export default memo(() => { - const { t } = useTranslation() - - // const [isShowModal, setIsShowModal] = useState(false) - // const hideDialog = useCallback(() => setIsShowModal(false), [setIsShowModal]) - // const togglePlayMethod = useGetter('common', 'togglePlayMethod') - - // const togglePlayMethodName = useMemo(() => { - // const method = playNextModes.find(m => m.action == togglePlayMethod) - // return method ? method.label : '未知' - // }, [togglePlayMethod]) - // const setPlayNextMode = useDispatch('common', 'setPlayNextMode') - // console.log(themeList) - // const handlePress = id => { - // setTheme(id) - // // console.log(AppColors) - // } - // const handleToggleMethodPress = ({ action }) => setPlayNextMode(action) - - return ( - <Section title={t('setting_play')}> - <IsPlayHighQuality /> - <IsHandleAudioFocus /> - <IsShowNotificationImage /> - <IsShowLyricTranslation /> - <IsShowLyricRoma /> - <IsS2T /> - <MaxCache /> - {/* <View style={{ marginLeft: 15, marginBottom: 15 }}> - <Text>播放歌曲切换方式</Text> - <DorpDownMenu menus={playNextModes} onPress={handleToggleMethodPress}><Text style={{ padding: 10 }}>{togglePlayMethodName}</Text></DorpDownMenu> - </View> */} - </Section> - ) -}) diff --git a/src/screens/Home/Setting/Version.js b/src/screens/Home/Setting/Version.js deleted file mode 100644 index 4011dc5fb..000000000 --- a/src/screens/Home/Setting/Version.js +++ /dev/null @@ -1,79 +0,0 @@ -import React, { useMemo, memo, useState, useEffect } from 'react' -import { StyleSheet, View, Text } from 'react-native' - -import Section from './components/Section' -import SubTitle from './components/SubTitle' -import Button from './components/Button' -import { showVersionModal } from '@/navigation' - -import { useTranslation } from '@/plugins/i18n' -import { useGetter, useDispatch } from '@/store' -import { VERSION_STATUS } from '@/config/constant' - -const currentVer = process.versions.app -export default memo(() => { - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - const versionInfo = useGetter('common', 'versionInfo') - const setVersionInfo = useDispatch('common', 'setVersionInfo') - const [title, setTitle] = useState('') - const handleOpenVersionModal = () => { - setVersionInfo({ showModal: true }) - showVersionModal() - } - - useEffect(() => { - switch (versionInfo.status) { - case VERSION_STATUS.available: - setTitle(t('version_title_new')) - // setTip(t('version_btn_new')) - break - case VERSION_STATUS.downloading: - setTitle(t('version_title_new')) - break - case VERSION_STATUS.downloaded: - setTitle(t('version_title_update')) - break - case VERSION_STATUS.checking: - setTitle(t('version_title_checking')) - break - case VERSION_STATUS.failed: - setTitle(t('version_title_failed')) - break - case VERSION_STATUS.unknown: - setTitle(t('version_title_unknown')) - break - case VERSION_STATUS.latest: - default: - setTitle(t('version_tip_latest')) - break - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [t, versionInfo]) - - return ( - <Section title={t('setting_version')}> - <SubTitle title={title}> - <View style={styles.desc}> - <Text style={{ ...styles.label, color: theme.normal }}>{t('version_label_latest_ver')}{versionInfo.version}</Text> - <Text style={{ ...styles.label, color: theme.normal }}>{t('version_label_current_ver')}{currentVer}</Text> - </View> - <View style={styles.btn}> - <Button onPress={handleOpenVersionModal}>{t('setting_version_show_ver_modal')}</Button> - </View> - </SubTitle> - </Section> - ) -}) - -const styles = StyleSheet.create({ - desc: { - marginBottom: 5, - }, - label: { - fontSize: 14, - }, - btn: { - flexDirection: 'row', - }, -}) diff --git a/src/screens/Home/Setting/components/Button.js b/src/screens/Home/Setting/components/Button.js deleted file mode 100644 index 1e9f9a1c6..000000000 --- a/src/screens/Home/Setting/components/Button.js +++ /dev/null @@ -1,31 +0,0 @@ -import React, { memo } from 'react' - -import { StyleSheet, View, Text } from 'react-native' - -import Button from '@/components/common/Button' -import { useGetter } from '@/store' - - -export default memo(({ children, disabled, onPress }) => { - const theme = useGetter('common', 'theme') - - return ( - <Button style={{ ...styles.button, backgroundColor: theme.secondary40 }} onPress={onPress} disabled={disabled}> - <Text style={{ ...styles.text, color: theme.secondary_5 }}>{children}</Text> - </Button> - ) -}) - -const styles = StyleSheet.create({ - button: { - paddingLeft: 10, - paddingRight: 10, - paddingTop: 5, - paddingBottom: 5, - borderRadius: 4, - marginRight: 10, - }, - text: { - fontSize: 12, - }, -}) diff --git a/src/screens/Home/Setting/components/CheckBoxItem.js b/src/screens/Home/Setting/components/CheckBoxItem.js deleted file mode 100644 index 2c6c877b0..000000000 --- a/src/screens/Home/Setting/components/CheckBoxItem.js +++ /dev/null @@ -1,22 +0,0 @@ -import React, { memo } from 'react' - -import { StyleSheet, View } from 'react-native' - -import CheckBox from '@/components/common/CheckBox' - - -export default memo(({ check, label, onChange, disabled }) => { - return ( - <View style={styles.container}> - <CheckBox check={check} label={label} onChange={onChange} disabled={disabled} /> - </View> - ) -}) - -const styles = StyleSheet.create({ - container: { - paddingLeft: 25, - marginTop: -10, - marginBottom: -5, - }, -}) diff --git a/src/screens/Home/Setting/components/Section.js b/src/screens/Home/Setting/components/Section.js deleted file mode 100644 index 057e4ec44..000000000 --- a/src/screens/Home/Setting/components/Section.js +++ /dev/null @@ -1,32 +0,0 @@ -import React, { memo } from 'react' - -import { StyleSheet, View, Text } from 'react-native' -import { useGetter } from '@/store' - -export default memo(({ title, children }) => { - const theme = useGetter('common', 'theme') - - return ( - <View style={styles.container}> - <Text style={{ ...styles.title, borderLeftColor: theme.secondary, color: theme.normal }}>{title}</Text> - <View> - {children} - </View> - </View> - ) -}) - - -const styles = StyleSheet.create({ - container: { - // paddingLeft: 10, - // backgroundColor: 'rgba(0,0,0,0.2)', - }, - title: { - borderLeftWidth: 5, - fontSize: 16, - paddingLeft: 10, - marginBottom: 10, - // lineHeight: 16, - }, -}) diff --git a/src/screens/Home/Setting/components/SubTitle.js b/src/screens/Home/Setting/components/SubTitle.js deleted file mode 100644 index 82ee58d4d..000000000 --- a/src/screens/Home/Setting/components/SubTitle.js +++ /dev/null @@ -1,29 +0,0 @@ -import React, { memo } from 'react' - -import { StyleSheet, View, Text } from 'react-native' -import { useGetter } from '@/store' - -export default memo(({ title, children }) => { - const theme = useGetter('common', 'theme') - - return ( - <View style={styles.container}> - <Text style={{ ...styles.title, color: theme.normal }}>{title}</Text> - {children} - </View> - ) -}) - - -const styles = StyleSheet.create({ - container: { - paddingLeft: 25, - marginBottom: 20, - }, - title: { - fontSize: 14, - marginLeft: -10, - marginBottom: 6, - // lineHeight: 16, - }, -}) diff --git a/src/screens/Home/SongList/List.js b/src/screens/Home/SongList/List.js deleted file mode 100644 index 670408e19..000000000 --- a/src/screens/Home/SongList/List.js +++ /dev/null @@ -1,137 +0,0 @@ -import React, { useRef, useState, useEffect, useMemo, useCallback } from 'react' -import { Text, StyleSheet, FlatList, View, RefreshControl } from 'react-native' - -import ListItem from './ListItem' -import LoadingMask from '@/components/common/LoadingMask' -import { useTranslation } from '@/plugins/i18n' -import { useDispatch, useGetter, subscribe } from '@/store' -import { navigations } from '@/navigation' - -export default ({ width }) => { - const unSubscribeRef = useRef() - const initedRef = useRef(false) - const isLoading = useRef(false) - const [isListRefreshing, setIsListRefreshing] = useState(false) - const listInfo = useGetter('songList', 'listInfo') - const getList = useDispatch('songList', 'getList') - const setSelectListInfo = useDispatch('songList', 'setSelectListInfo') - const theme = useGetter('common', 'theme') - const songListSource = useGetter('songList', 'songListSource') - const songListSortId = useGetter('songList', 'songListSortId') - const songListTagInfo = useGetter('songList', 'songListTagInfo') - const [page, setPage] = useState(0) - const { t } = useTranslation() - const componentIds = useGetter('common', 'componentIds') - - useEffect(() => { - if (!initedRef.current) return - setPage(1) - getList({ page: 1 }) - }, [songListSource, songListSortId, songListTagInfo, getList]) - - useEffect(() => { - unSubscribeRef.current = subscribe('common.nav.navActiveIndex', () => { - if (!isListRefreshing) return - setIsListRefreshing(false) - }) - - setPage(1) - getList({ page: 1 }) - initedRef.current = true - return unSubscribeRef.current - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - - const handleListLoadMore = useCallback(() => { - if (listInfo.isLoading || listInfo.isEnd) return - isLoading.current = true - setPage(listInfo.page + 1) - getList({ page: listInfo.page + 1 }).finally(() => { - isLoading.current = false - }) - }, [getList, listInfo]) - - const handleListRefresh = useCallback(() => { - setIsListRefreshing(true) - setPage(1) - getList({ pahe: 1, isRefresh: true }).finally(() => { - setIsListRefreshing(false) - }) - }, [getList]) - - const handleListPress = useCallback((item, index) => { - // console.log(item) - setSelectListInfo(item) - navigations.pushSonglistDetailScreen(componentIds.home, item.id) - }, [componentIds.home, setSelectListInfo]) - - const itemWidth = useMemo(() => Math.max(parseInt(width * 0.125), 110), [width]) - const rowNum = useMemo(() => Math.floor(width / itemWidth), [itemWidth, width]) - const list = useMemo(() => { - const list = [...listInfo.list] - let whiteItemNum = (list.length % rowNum) - if (whiteItemNum > 0) whiteItemNum = rowNum - whiteItemNum - for (let i = 0; i < whiteItemNum; i++) list.push({ id: `white__${i}` }) - return list - }, [listInfo, rowNum]) - // console.log(listInfo.list.map((item) => item.id)) - - const renderItem = useCallback(data => ( - <ListItem data={data} width={itemWidth} onPress={handleListPress} /> - ), [handleListPress, itemWidth]) - - const refreshControl = useMemo(() => ( - <RefreshControl - colors={[theme.secondary]} - progressBackgroundColor={theme.primary} - refreshing={isListRefreshing} - onRefresh={handleListRefresh} /> - ), [isListRefreshing, handleListRefresh, theme]) - - const ListComponent = useMemo(() => <FlatList - style={styles.list} - columnWrapperStyle={{ justifyContent: 'space-evenly' }} - numColumns={rowNum} - data={list} - renderItem={renderItem} - keyExtractor={item => String(item.id)} - key={rowNum} - onEndReached={handleListLoadMore} - refreshControl={refreshControl} - // onEndReachedThreshold={0.5} - ListFooterComponent={ - listInfo.isEnd - ? null - : <View style={{ alignItems: 'center', padding: 10 }}><Text style={{ color: theme.normal30 }}>{t('loading')}</Text></View> - } - removeClippedSubviews={true} - />, [rowNum, list, renderItem, handleListLoadMore, refreshControl, listInfo.isEnd, theme, t]) - - const visibleLoadingMask = useMemo(() => page == 1 && listInfo.isLoading, [listInfo.isLoading, page]) - - const loadingMaskmomponent = useMemo(() => ( - <LoadingMask visible={visibleLoadingMask} /> - ), [visibleLoadingMask]) - - // console.log('render song list') - return ( - <View style={styles.container}> - { width == 0 ? null : ListComponent} - { loadingMaskmomponent } - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - overflow: 'hidden', - }, - list: { - flex: 1, - paddingLeft: 10, - paddingRight: 10, - }, -}) - diff --git a/src/screens/Home/SongList/ListItem.js b/src/screens/Home/SongList/ListItem.js deleted file mode 100644 index ed6bb69db..000000000 --- a/src/screens/Home/SongList/ListItem.js +++ /dev/null @@ -1,58 +0,0 @@ -import React, { memo } from 'react' -import { View, Text, Image, StyleSheet, Platform, TouchableOpacity } from 'react-native' -import { useGetter } from '@/store' - -export default memo(({ data: { index, item }, width, onPress = () => {} }) => { - const theme = useGetter('common', 'theme') - const handlePress = () => { - onPress(item, index) - } - return ( - item.source - ? ( - <View style={{ ...styles.listItem, width: width - 20 }}> - <View style={{ ...styles.listItemImg, backgroundColor: theme.primary }}> - <TouchableOpacity activeOpacity={0.5} onPress={handlePress}> - <Image source={{ uri: item.img }} nativeID={`pic${item.id}`} style={{ width: width - 20, height: width - 20 }} borderRadius={4} /> - </TouchableOpacity> - </View> - <TouchableOpacity activeOpacity={0.5} onPress={handlePress}> - <Text style={{ ...styles.listItemTitle, color: theme.normal }} nativeID={`title${item.id}`} numberOfLines={ 2 }>{item.name}</Text> - </TouchableOpacity> - {/* <Text>{JSON.stringify(item)}</Text> */} - </View> - ) - : <View style={styles.listItem} /> - ) -}) - -const styles = StyleSheet.create({ - listItem: { - width: 90, - margin: 10, - }, - listItemImg: { - backgroundColor: '#eee', - borderRadius: 4, - marginBottom: 5, - ...Platform.select({ - ios: { - shadowColor: '#000', - shadowOffset: { - width: 0, - height: 1, - }, - shadowOpacity: 0.20, - shadowRadius: 1.41, - }, - android: { - elevation: 2, - }, - }), - }, - listItemTitle: { - fontSize: 12, - // overflow: 'hidden', - marginBottom: 5, - }, -}) diff --git a/src/screens/Home/SongList/MenuBar.js b/src/screens/Home/SongList/MenuBar.js deleted file mode 100644 index c5349fd64..000000000 --- a/src/screens/Home/SongList/MenuBar.js +++ /dev/null @@ -1,33 +0,0 @@ -import React, { useCallback, useMemo } from 'react' -import { View, Text, StyleSheet } from 'react-native' - -// import { useGetter, useDispatch } from '@/store' -import SourceSelector from './SourceSelector' -import SortTab from './SortTab' -import Tag from './Tag' -import OpenList from './OpenList' -// import { BorderWidths } from '@/theme' - -export default () => { - // const theme = useGetter('common', 'theme') - - return ( - <View style={{ ...styles.container }}> - <SortTab /> - <Tag /> - <OpenList /> - <SourceSelector /> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - flexDirection: 'row', - width: '100%', - flexGrow: 0, - flexShrink: 0, - // borderBottomWidth: BorderWidths.normal, - }, -}) - diff --git a/src/screens/Home/SongList/OpenList.js b/src/screens/Home/SongList/OpenList.js deleted file mode 100644 index cdc7f6787..000000000 --- a/src/screens/Home/SongList/OpenList.js +++ /dev/null @@ -1,99 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect, useState, useRef } from 'react' -import { View, Text, StyleSheet, TouchableOpacity } from 'react-native' -// import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' -import Button from '@/components/common/Button' -import ConfirmAlert from '@/components/common/ConfirmAlert' -import Input from '@/components/common/Input' -import { navigations } from '@/navigation' - -export default memo(() => { - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - const [visibleAlert, setVisibleAlert] = useState(false) - const [text, setText] = useState('') - const setSelectListInfo = useDispatch('songList', 'setSelectListInfo') - const songListSource = useGetter('songList', 'songListSource') - const componentIds = useGetter('common', 'componentIds') - - const handleShowMusicAddModal = () => { - setText('') - setVisibleAlert(true) - } - - const handleCancelOpen = useCallback(() => { - setVisibleAlert(false) - }, []) - const handleOpen = useCallback(() => { - if (!text.length) return - setSelectListInfo({ - play_count: null, - id: text, - author: '', - name: '', - img: null, - desc: '', - source: songListSource, - }) - setVisibleAlert(false) - navigations.pushSonglistDetailScreen(componentIds.home) - }, [componentIds.home, setSelectListInfo, songListSource, text]) - - - return ( - <> - <Button style={{ ...styles.button }} onPress={handleShowMusicAddModal}> - <Text style={{ ...styles.buttonText, color: theme.normal }}>{t('songlist_open')}</Text> - </Button> - <ConfirmAlert - visible={visibleAlert} - onHide={handleCancelOpen} - onConfirm={handleOpen} - > - <View style={styles.alertContent}> - <Input - placeholder={t('songlist_open_input_placeholder')} - value={text} - onChangeText={setText} - style={{ ...styles.input, backgroundColor: theme.secondary40 }} - /> - <Text style={{ ...styles.inputTipText, color: theme.normal20 }}>{t('songlist_open_input_tip')}</Text> - </View> - </ConfirmAlert> - </> - ) -}) - -const styles = StyleSheet.create({ - button: { - // backgroundColor: '#ccc', - alignItems: 'center', - justifyContent: 'center', - paddingLeft: 12, - paddingRight: 12, - }, - buttonText: { - fontSize: 14, - }, - - alertContent: { - flexGrow: 1, - flexShrink: 1, - flexDirection: 'column', - }, - input: { - flexGrow: 1, - flexShrink: 1, - minWidth: 240, - borderRadius: 4, - paddingTop: 2, - paddingBottom: 2, - fontSize: 12, - }, - inputTipText: { - marginTop: 5, - fontSize: 12, - lineHeight: 18, - }, -}) diff --git a/src/screens/Home/SongList/SortTab.js b/src/screens/Home/SongList/SortTab.js deleted file mode 100644 index e8e21d848..000000000 --- a/src/screens/Home/SongList/SortTab.js +++ /dev/null @@ -1,79 +0,0 @@ -import React, { memo, useMemo } from 'react' -import { StyleSheet, Text, View, ScrollView, TouchableOpacity } from 'react-native' - -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' - - -export default memo(() => { - const setSongList = useDispatch('common', 'setSongList') - const sortList = useGetter('songList', 'sortList') - const songListSource = useGetter('songList', 'songListSource') - const songListSortId = useGetter('songList', 'songListSortId') - // const currentSourceName = useGetter('search', 'currentSourceName') - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - - const sorts = useMemo(() => { - const list = songListSource ? [...sortList[songListSource]] : [] - // switch (songListSource) { - // case 'wy': - // case 'kw': - // case 'tx': - // case 'mg': - // case 'kg': - // list.push({ - // name: t('view.song_list.open_list', { name: sources.find(s => s.id == songListSource).name }), - // id: 'importSongList', - // }) - // } - return list.map(s => ({ label: t(`songlist_${s.tid}`), id: s.id })) - }, [songListSource, sortList, t]) - - - return ( - <ScrollView style={styles.container} keyboardShouldPersistTaps={'always'} horizontal={true}> - { - sorts.map(s => ( - <TouchableOpacity style={styles.button} onPress={() => setSongList({ sortId: s.id })} key={s.id}> - <Text style={{ ...styles.buttonText, color: songListSortId == s.id ? theme.secondary : theme.normal }}>{s.label}</Text> - </TouchableOpacity> - )) - } - </ScrollView> - // <DorpDownMenu - // menus={sorts} - // width={80} - // onPress={({ id }) => setSongList({ sortId: id })} - // > - // <Text style={styles.sourceMenu}>{currentSortName}</Text> - // </DorpDownMenu> - ) -}) - - -const styles = StyleSheet.create({ - container: { - flexGrow: 1, - flexShrink: 1, - paddingLeft: 5, - paddingRight: 5, - }, - button: { - // height: 38, - // lineHeight: 38, - // textAlign: 'center', - // width: 80, - // backgroundColor: 'rgba(0,0,0,0.1)', - }, - buttonText: { - // height: 38, - // lineHeight: 38, - textAlign: 'center', - paddingLeft: 15, - paddingRight: 15, - paddingTop: 10, - paddingBottom: 10, - // width: 80, - }, -}) diff --git a/src/screens/Home/SongList/SourceSelector.js b/src/screens/Home/SongList/SourceSelector.js deleted file mode 100644 index 6fe59d9a7..000000000 --- a/src/screens/Home/SongList/SourceSelector.js +++ /dev/null @@ -1,52 +0,0 @@ -import React, { memo, useMemo, useCallback } from 'react' -import { StyleSheet, Text, View } from 'react-native' - -import DorpDownMenu from '@/components/common/DorpDownMenu' -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' -import { useLayout } from '@/utils/hooks' - - -export default memo(() => { - const setSongList = useDispatch('common', 'setSongList') - const sources = useGetter('songList', 'sources') - const songListSource = useGetter('songList', 'songListSource') - // const currentSourceName = useGetter('search', 'currentSourceName') - const { t } = useTranslation() - const sortList = useGetter('songList', 'sortList') - const sourceNameType = useGetter('common', 'sourceNameType') - const theme = useGetter('common', 'theme') - const { onLayout, ...layout } = useLayout() - - const sources_t = useMemo(() => { - return sources.map(s => ({ label: t(`source_${sourceNameType}_${s.id}`), action: s.id })) - }, [sourceNameType, sources, t]) - - const handleSetSource = useCallback(({ action }) => { - const sorts = sortList[action] - setSongList({ source: action, sortId: sorts ? sorts[0].id : '', tagInfo: { name: '默认', id: null } }) - }, [setSongList, sortList]) - - return ( - <DorpDownMenu - menus={sources_t} - width={layout.width} - onPress={handleSetSource} - > - <View style={styles.sourceMenu} onLayout={onLayout}> - <Text style={{ color: theme.normal }}>{t(`source_${sourceNameType}_${songListSource}`)}</Text> - </View> - </DorpDownMenu> - ) -}) - - -const styles = StyleSheet.create({ - sourceMenu: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - paddingLeft: 12, - paddingRight: 12, - }, -}) diff --git a/src/screens/Home/SongList/Tag.js b/src/screens/Home/SongList/Tag.js deleted file mode 100644 index 0b254f25b..000000000 --- a/src/screens/Home/SongList/Tag.js +++ /dev/null @@ -1,130 +0,0 @@ -import React, { memo, useMemo, useEffect, useCallback, useState } from 'react' -import { StyleSheet, Text, View, ScrollView, TouchableOpacity } from 'react-native' - -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' -import Popup from '@/components/common/Popup' -import Button from '@/components/common/Button' -// import { BorderWidths } from '@/theme' - -const TagType = ({ name, list, setTagInfo, activeId }) => { - const theme = useGetter('common', 'theme') - return ( - <View> - <Text style={{ ...styles.tagTypeTitle, color: theme.normal30 }}>{name}</Text> - <View style={styles.tagTypeList}> - {list.map(item => ( - <Button style={{ ...styles.tagButton, backgroundColor: theme.secondary45 }} key={item.id} onPress={() => setTagInfo(item.name, item.id)}> - <Text style={{ ...styles.tagButtonText, color: activeId == item.id ? theme.secondary : theme.normal10 }}>{item.name}</Text> - </Button> - ))} - </View> - </View> - ) -} - -const Tags = memo(({ setVisiblePanel }) => { - const theme = useGetter('common', 'theme') - const tags = useGetter('songList', 'tags') - const songListSource = useGetter('songList', 'songListSource') - const setSongList = useDispatch('common', 'setSongList') - const songListTagInfo = useGetter('songList', 'songListTagInfo') - // console.log('render') - const tagsList = useMemo(() => { - let tagInfo = tags[songListSource] - return tagInfo ? [{ name: '热门', list: [...tagInfo.hotTag] }, ...tagInfo.tags] : [] - }, [songListSource, tags]) - const setTagInfo = useCallback((name, id) => { - setVisiblePanel(false) - setSongList({ tagInfo: { name, id } }) - }, [setSongList, setVisiblePanel]) - return ( - <ScrollView style={{ flexShrink: 1, flexGrow: 0 }} keyboardShouldPersistTaps={'always'}> - <View style={{ ...styles.tagContainer, backgroundColor: theme.primary }} onStartShouldSetResponder={() => true}> - <View style={{ ...styles.tagTypeList, marginTop: 10 }}> - <Button style={{ ...styles.tagButton, backgroundColor: theme.secondary45 }} onPress={() => setTagInfo('默认', null)}> - <Text style={{ ...styles.tagButtonText, color: songListTagInfo.id == null ? theme.secondary : theme.normal10 }}>默认</Text> - </Button> - </View> - {tagsList.map((type, index) => <TagType key={index} name={type.name} list={type.list} activeId={songListTagInfo.id} setTagInfo={setTagInfo} />)} - </View> - </ScrollView> - ) -}) - - -export default memo(() => { - const songListSource = useGetter('songList', 'songListSource') - const songListTagInfo = useGetter('songList', 'songListTagInfo') - // const currentSourceName = useGetter('search', 'currentSourceName') - const theme = useGetter('common', 'theme') - const getTags = useDispatch('songList', 'getTags') - const [visiblePanel, setVisiblePanel] = useState(false) - const { t } = useTranslation() - - // useEffect(() => { - // getTags() - // // eslint-disable-next-line react-hooks/exhaustive-deps - // }, []) - useEffect(() => { - getTags() - }, [getTags, songListSource]) - - - // console.log('render tags') - - return ( - <> - <TouchableOpacity style={styles.listName} onPress={() => setVisiblePanel(true)}> - <Text style={{ ...styles.sourceMenu, color: theme.normal }}>{songListTagInfo.name}</Text> - </TouchableOpacity> - <Popup - visible={visiblePanel} - hide={() => setVisiblePanel(false)} - title={t('songlist_tags')} - > - <Tags setVisiblePanel={setVisiblePanel} /> - </Popup> - </> - ) -}) - - -const styles = StyleSheet.create({ - sourceMenu: { - // height: 38, - // lineHeight: 38, - textAlign: 'center', - // minWidth: 70, - paddingLeft: 12, - paddingRight: 12, - paddingTop: 10, - paddingBottom: 10, - }, - - tagContainer: { - paddingLeft: 15, - paddingBottom: 15, - }, - tagTypeTitle: { - marginTop: 15, - marginBottom: 10, - }, - tagTypeList: { - flexDirection: 'row', - flexWrap: 'wrap', - }, - tagButton: { - // marginRight: 10, - borderRadius: 4, - marginRight: 10, - marginBottom: 10, - }, - tagButtonText: { - fontSize: 13, - paddingLeft: 12, - paddingRight: 12, - paddingTop: 8, - paddingBottom: 8, - }, -}) diff --git a/src/screens/Home/SongList/index.js b/src/screens/Home/SongList/index.js deleted file mode 100644 index 519ba6a3a..000000000 --- a/src/screens/Home/SongList/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react' -import { StyleSheet, View } from 'react-native' - -import List from './List' -import MenuBar from './MenuBar' - -import { useLayout } from '@/utils/hooks' - -export default () => { - const { onLayout, ...layout } = useLayout() - return ( - <View style={styles.container} onLayout={onLayout}> - <MenuBar /> - <List width={layout.width} /> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - position: 'relative', - flex: 1, - }, -}) - diff --git a/src/screens/Home/Top/BoardsList.js b/src/screens/Home/Top/BoardsList.js deleted file mode 100644 index b473268f1..000000000 --- a/src/screens/Home/Top/BoardsList.js +++ /dev/null @@ -1,175 +0,0 @@ -import React, { memo, useMemo, useEffect, useCallback, useRef, useState } from 'react' -import { StyleSheet, View, Text, ScrollView } from 'react-native' - -import Menu from '@/components/common/Menu' - -import { useGetter, useDispatch } from '@/store' -import Button from '@/components/common/Button' -import { useTranslation } from '@/plugins/i18n' -import { LIST_ID_PLAY_TEMP } from '@/config/constant' -import { toast } from '@/utils/tools' - -const Item = ({ item, tabId, showMenu, setTop, index, longPressIndex }) => { - const theme = useGetter('common', 'theme') - const buttonRef = useRef() - - const setPosition = useCallback(() => { - if (buttonRef.current && buttonRef.current.measure) { - buttonRef.current.measure((fx, fy, width, height, px, py) => { - // console.log(fx, fy, width, height, px, py) - showMenu({ - position: { x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }, - index, - }) - }) - } - }, [index, showMenu]) - - return ( - <Button ref={buttonRef} style={{ ...styles.button, backgroundColor: index == longPressIndex ? theme.secondary40 : theme.primary }} key={item.id} onLongPress={setPosition} onPress={() => setTop({ tabId: item.id })}> - <Text style={{ ...styles.buttonText, color: tabId == item.id ? theme.secondary : theme.normal }} numberOfLines={1}>{item.name}</Text> - </Button> - ) -} - -const BoardMenu = ({ visible, buttonPosition, index, hideMenu }) => { - const { t } = useTranslation() - const getListAll = useDispatch('top', 'getListAll') - const createUserList = useDispatch('list', 'createUserList') - const boards = useGetter('top', 'boards') - const setPlayList = useDispatch('player', 'setList') - const sourceId = useGetter('top', 'sourceId') - - const menus = useMemo(() => { - return [ - { action: 'play', label: t('play') }, - { action: 'collect', label: t('collect') }, - ] - }, [t]) - - const handleMenuPress = useCallback(({ action }) => { - hideMenu() - if (action) { - const board = boards[sourceId][index] - getListAll({ id: board.id }).then(list => { - if (!list.length) return - - switch (action) { - case 'play': - setPlayList({ - list: { - list, - id: LIST_ID_PLAY_TEMP, - }, - index: 0, - }) - break - case 'collect': - createUserList({ - name: board.name, - id: `board__${sourceId}__${board.id}`, - list, - source: board.source, - sourceListId: `board__${board.id}`, - isShowToast: true, - }) - toast(t('collect_success')) - break - default: - break - } - }) - } - }, [boards, createUserList, getListAll, hideMenu, index, setPlayList, sourceId, t]) - - return ( - <Menu - menus={menus} - visible={visible} - buttonPosition={buttonPosition} - hideMenu={hideMenu} - onPress={handleMenuPress} - /> - ) -} - - -export default memo(() => { - const setTop = useDispatch('common', 'setTop') - const getBoardsList = useDispatch('top', 'getBoardsList') - const boards = useGetter('top', 'boards') - const sourceId = useGetter('top', 'sourceId') - const tabId = useGetter('top', 'tabId') - const [visible, setVisible] = useState(false) - const [longPressIndex, setLongPressIndex] = useState(-1) - const [buttonPosition, setButtonPosition] = useState({}) - - useEffect(() => { - const list = boards[sourceId] - if (list.length && !list.some(b => b.id == tabId)) { - setTop({ tabId: list[0].id }) - } - }, [boards]) - - useEffect(() => { - let list = boards[sourceId] - if (list.length) { - if (list.some(b => b.id == tabId)) return - setTop({ tabId: list[0].id }) - return - } - getBoardsList().then(() => { - list = boards[sourceId] - if (list.some(b => b.id == tabId)) return - setTop({ tabId: list.length ? list[0].id : null }) - }) - }, [sourceId]) - - const list = useMemo(() => sourceId ? [...boards[sourceId]] : [], [boards, sourceId]) - - const showMenu = useCallback(({ position, index }) => { - setLongPressIndex(index) - setButtonPosition(position) - setVisible(true) - }, []) - const hideMenu = useCallback(() => { - setVisible(false) - setLongPressIndex(-1) - }, [setVisible]) - - return ( - <View style={styles.container}> - <ScrollView style={styles.scrollView} keyboardShouldPersistTaps={'always'}> - <View style={styles.list}> - { - list.map((item, index) => (<Item key={item.id} item={item} index={index} longPressIndex={longPressIndex} tabId={tabId} showMenu={showMenu} setTop={setTop} />)) - } - </View> - </ScrollView> - <BoardMenu visible={visible} buttonPosition={buttonPosition} index={longPressIndex} hideMenu={hideMenu} /> - </View> - ) -}) - - -const styles = StyleSheet.create({ - container: { - flexGrow: 1, - flexShrink: 1, - }, - scrollView: { - flexShrink: 1, - }, - list: { - - }, - button: { - paddingLeft: 10, - paddingRight: 10, - paddingTop: 10, - paddingBottom: 10, - }, - buttonText: { - fontSize: 12, - }, -}) diff --git a/src/screens/Home/Top/LeftBar.js b/src/screens/Home/Top/LeftBar.js deleted file mode 100644 index 93fa56c48..000000000 --- a/src/screens/Home/Top/LeftBar.js +++ /dev/null @@ -1,33 +0,0 @@ -import React, { useCallback, useMemo } from 'react' -import { View, Text, StyleSheet } from 'react-native' - -import { useGetter, useDispatch } from '@/store' -import SourceSelector from './SourceSelector' -import BoardsList from './BoardsList' -import { BorderWidths } from '@/theme' -import { useLayout } from '@/utils/hooks' - - -export default () => { - const theme = useGetter('common', 'theme') - const { onLayout, ...layout } = useLayout() - - return ( - <View style={{ ...styles.container, borderRightColor: theme.borderColor }} onLayout={onLayout}> - <SourceSelector layout={layout} /> - <BoardsList /> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - flexDirection: 'column', - width: '26%', - maxWidth: 120, - flexGrow: 0, - flexShrink: 0, - borderRightWidth: BorderWidths.normal, - }, -}) - diff --git a/src/screens/Home/Top/MusicList.js b/src/screens/Home/Top/MusicList.js deleted file mode 100644 index 6cd591fef..000000000 --- a/src/screens/Home/Top/MusicList.js +++ /dev/null @@ -1,91 +0,0 @@ -import React, { useState, useCallback, memo, useEffect, useMemo } from 'react' -import { InteractionManager } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import OnlineList from '@/components/OnlineList' -import { LIST_ID_PLAY_TEMP } from '@/config/constant' - -export default memo(() => { - const [isListRefreshing, setIsListRefreshing] = useState(false) - const [visibleLoadingMask, setVisibleLoadingMask] = useState(false) - const listInfo = useGetter('top', 'listInfo') - const isLoading = useGetter('top', 'isLoading') - const isEnd = useGetter('top', 'isEnd') - const getList = useDispatch('top', 'getList') - const tabId = useGetter('top', 'tabId') - const [page, setPage] = useState(0) - const getListAll = useDispatch('top', 'getListAll') - const setPlayList = useDispatch('player', 'setList') - // const getListAll = useDispatch('top', 'getListAll') - // console.log(isLoading) - - const handleRefresh = useCallback(() => { - setIsListRefreshing(true) - setVisibleLoadingMask(true) - setPage(1) - getList({ page: 1, isRefresh: true }).finally(() => { - setVisibleLoadingMask(false) - setIsListRefreshing(false) - }) - }, [getList]) - - const handleLoadMore = useCallback(() => { - if (isLoading || isEnd) return - setPage(listInfo.page + 1) - getList({ page: listInfo.page + 1 }) - }, [isLoading, isEnd, getList, listInfo.page]) - - // useEffect(() => { - // console.log(tabId) - // InteractionManager.runAfterInteractions(() => { - // getList({ page: 1 }).finally(() => { - // setIsListRefreshing(false) - // }) - // }) - // }, [getList]) - - useEffect(() => { - InteractionManager.runAfterInteractions(() => { - setVisibleLoadingMask(true) - setPage(1) - getList({ page: 1 }).finally(() => { - setVisibleLoadingMask(false) - setIsListRefreshing(false) - }) - }) - }, [getList, tabId]) - - const visible = useMemo(() => isLoading && visibleLoadingMask, [isLoading, visibleLoadingMask]) - - const handlePlayList = useCallback(index => { - getListAll({ id: tabId }).then(list => { - if (!list.length) return - setPlayList({ - list: { - list, - id: LIST_ID_PLAY_TEMP, - }, - index, - }) - }) - }, [getListAll, setPlayList, tabId]) - - const listComponent = useMemo(() => { - return ( - <OnlineList - list={listInfo.list} - isEnd={isEnd} - page={page} - isListRefreshing={isListRefreshing} - onRefresh={handleRefresh} - onLoadMore={handleLoadMore} - onPlayList={handlePlayList} - // progressViewOffset={20} - visibleLoadingMask={visible} - isLoading={isLoading} - /> - ) - }, [handleLoadMore, handlePlayList, handleRefresh, isEnd, isListRefreshing, isLoading, listInfo.list, page, visible]) - - return listComponent -}) - diff --git a/src/screens/Home/Top/SourceSelector.js b/src/screens/Home/Top/SourceSelector.js deleted file mode 100644 index ac0a7c719..000000000 --- a/src/screens/Home/Top/SourceSelector.js +++ /dev/null @@ -1,44 +0,0 @@ -import React, { memo, useMemo } from 'react' -import { StyleSheet, Text, View } from 'react-native' - -import DorpDownMenu from '@/components/common/DorpDownMenu' -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' - - -export default memo(({ layout }) => { - const setTop = useDispatch('common', 'setTop') - const sourceNameType = useGetter('common', 'sourceNameType') - const sourceList = useGetter('top', 'sources') - const sourceId = useGetter('top', 'sourceId') - const theme = useGetter('common', 'theme') - // const currentSourceName = useGetter('search', 'currentSourceName') - const { t } = useTranslation() - - const sourceList_t = useMemo(() => { - return sourceList.map(s => ({ label: t(`source_${sourceNameType}_${s.id}`), action: s.id })) - }, [sourceNameType, sourceList, t]) - - return ( - <DorpDownMenu - menus={sourceList_t} - width={layout.width} - onPress={({ action }) => setTop({ source: action })} - > - <View style={styles.sourceMenu}> - <Text style={{ color: theme.normal }} numberOfLines={1}>{t(`source_${sourceNameType}_${sourceId}`)}</Text> - </View> - </DorpDownMenu> - ) -}) - - -const styles = StyleSheet.create({ - sourceMenu: { - justifyContent: 'center', - paddingTop: 12, - paddingBottom: 12, - paddingLeft: 10, - paddingRight: 10, - }, -}) diff --git a/src/screens/Home/Top/index.js b/src/screens/Home/Top/index.js deleted file mode 100644 index 245ac0ba8..000000000 --- a/src/screens/Home/Top/index.js +++ /dev/null @@ -1,26 +0,0 @@ -import React, { useCallback, useRef } from 'react' -import { StyleSheet, View } from 'react-native' - -import MusicList from './MusicList' -import LeftBar from './LeftBar' - - -export default () => { - return ( - <View style={styles.container}> - <LeftBar /> - <MusicList /> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - width: '100%', - flex: 1, - flexDirection: 'row', - }, - content: { - flex: 1, - }, -}) diff --git a/src/screens/Home/Vertical/Content.tsx b/src/screens/Home/Vertical/Content.tsx new file mode 100644 index 000000000..0936c67da --- /dev/null +++ b/src/screens/Home/Vertical/Content.tsx @@ -0,0 +1,61 @@ +import React, { useEffect, useRef } from 'react' +import { type DrawerLayoutAndroid } from 'react-native' +// import { getWindowSise, onDimensionChange } from '@/utils/tools' +import DrawerNav from './DrawerNav' +import Header from './Header' +import Main from '../components/Main' +import { useSettingValue } from '@/store/setting/hook' +import { COMPONENT_IDS } from '@/config/constant' +import DrawerLayoutFixed from '@/components/common/DrawerLayoutFixed' +import { scaleSizeW } from '@/utils/pixelRatio' + +const MAX_WIDTH = scaleSizeW(300) + +const Content = () => { + const drawer = useRef<DrawerLayoutAndroid>(null) + const drawerLayoutPosition = useSettingValue('common.drawerLayoutPosition') + + useEffect(() => { + const changeVisible = (visible: boolean) => { + if (visible) { + drawer.current?.openDrawer() + } else { + drawer.current?.closeDrawer() + } + } + + global.app_event.on('changeMenuVisible', changeVisible) + + return () => { + global.app_event.off('changeMenuVisible', changeVisible) + } + }, []) + + const navigationView = () => <DrawerNav /> + // console.log('render drawer content') + + return ( + <DrawerLayoutFixed + ref={drawer} + widthPercentage={0.7} + widthPercentageMax={MAX_WIDTH} + visibleNavNames={[COMPONENT_IDS.home]} + // drawerWidth={width} + drawerPosition={drawerLayoutPosition} + renderNavigationView={navigationView} + > + <Header /> + <Main /> + {/* <View style={styles.container}> + </View> */} + </DrawerLayoutFixed> + ) +} + +// const styles = createStyle({ +// container: { +// flex: 1, +// }, +// }) + +export default Content diff --git a/src/screens/Home/Vertical/DrawerNav.tsx b/src/screens/Home/Vertical/DrawerNav.tsx new file mode 100644 index 000000000..bf77dd3a6 --- /dev/null +++ b/src/screens/Home/Vertical/DrawerNav.tsx @@ -0,0 +1,137 @@ +import React, { memo } from 'react' +import { ScrollView, StatusBar, TouchableOpacity, View } from 'react-native' +import { useI18n } from '@/lang' +import { useNavActiveId } from '@/store/common/hook' +import { useTheme } from '@/store/theme/hook' +import { Icon } from '@/components/common/Icon' +import { createStyle } from '@/utils/tools' +import { NAV_MENUS } from '@/config/constant' +import type { InitState } from '@/store/common/state' +// import { navigations } from '@/navigation' +// import commonState from '@/store/common/state' +import { exitApp, setNavActiveId } from '@/core/common' +import Text from '@/components/common/Text' + +const styles = createStyle({ + container: { + flex: 1, + // alignItems: 'center', + // justifyContent: 'center', + // padding: 10, + }, + header: { + paddingTop: 40, + paddingBottom: 50, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + }, + headerText: { + textAlign: 'center', + marginLeft: 16, + }, + menus: { + flex: 1, + }, + list: { + paddingTop: 10, + paddingBottom: 10, + }, + menuItem: { + flexDirection: 'row', + paddingTop: 13, + paddingBottom: 13, + paddingLeft: 25, + paddingRight: 25, + alignItems: 'center', + // backgroundColor: 'rgba(0, 0, 0, 0.2)', + }, + iconContent: { + width: 24, + alignItems: 'center', + }, + text: { + paddingLeft: 20, + // fontWeight: '500', + }, +}) + +const Header = () => { + const theme = useTheme() + return ( + <View style={{ paddingTop: StatusBar.currentHeight, backgroundColor: theme['c-primary-light-700-alpha-500'] }}> + <View style={styles.header}> + <Icon name="logo" color={theme['c-primary-dark-100-alpha-300']} size={28} /> + <Text style={styles.headerText} size={28} color={theme['c-primary-dark-100-alpha-300']}>LX Music</Text> + </View> + </View> + ) +} + +type IdType = InitState['navActiveId'] | 'nav_exit' + +const MenuItem = ({ id, icon, onPress }: { + id: IdType + icon: string + onPress: (id: IdType) => void +}) => { + const t = useI18n() + const activeId = useNavActiveId() + const theme = useTheme() + + return activeId == id + ? <View style={styles.menuItem}> + <View style={styles.iconContent}> + <Icon name={icon} size={20} color={theme['c-primary-font-active']} /> + </View> + <Text style={styles.text} color={theme['c-primary-font']}>{t(id)}</Text> + </View> + : <TouchableOpacity style={styles.menuItem} onPress={() => { onPress(id) }}> + <View style={styles.iconContent}> + <Icon name={icon} size={20} color={theme['c-font-label']} /> + </View> + <Text style={styles.text}>{t(id)}</Text> + </TouchableOpacity> +} + +export default memo(() => { + const theme = useTheme() + // console.log('render drawer nav') + + const handlePress = (id: IdType) => { + if (id == 'nav_exit') { + exitApp() + return + } + // switch (id) { + // case 'nav_search': + // break + // case 'nav_songlist': + // break + // case 'nav_top': + // break + // case 'nav_love': + // break + // case 'nav_setting': + // // void InteractionManager.runAfterInteractions(() => { + // // navigations.pushSettingScreen(commonState.componentIds.home) + // // }) + // return + // } + global.app_event.changeMenuVisible(false) + setNavActiveId(id) + } + + return ( + <View style={{ ...styles.container, backgroundColor: theme['c-content-background'] }}> + <Header /> + <ScrollView style={styles.menus}> + <View style={styles.list}> + {NAV_MENUS.map(menu => <MenuItem key={menu.id} id={menu.id} icon={menu.icon} onPress={handlePress} />)} + </View> + </ScrollView> + <MenuItem id="nav_exit" icon="exit2" onPress={handlePress} /> + </View> + ) +}) + diff --git a/src/screens/Home/Vertical/Header.tsx b/src/screens/Home/Vertical/Header.tsx new file mode 100644 index 000000000..33d09e60b --- /dev/null +++ b/src/screens/Home/Vertical/Header.tsx @@ -0,0 +1,157 @@ +import React from 'react' +import { View, TouchableOpacity } from 'react-native' +// import Button from '@/components/common/Button' +// import { navigations } from '@/navigation' +// import { BorderWidths } from '@/theme' +import { useTheme } from '@/store/theme/hook' +import { useNavActiveId } from '@/store/common/hook' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import { Icon } from '@/components/common/Icon' +import Text from '@/components/common/Text' +import StatusBar from '@/components/common/StatusBar' +import { useSettingValue } from '@/store/setting/hook' +import { scaleSizeH } from '@/utils/pixelRatio' +import { HEADER_HEIGHT } from '@/config/constant' +import { type InitState as CommonState } from '@/store/common/state' +import SearchTypeSelector from '@/screens/Home/Views/Search/SearchTypeSelector' + +const headerComponents: Partial<Record<CommonState['navActiveId'], React.ReactNode>> = { + nav_search: <SearchTypeSelector />, +} + + +// const LeftTitle = () => { +// const id = useNavActiveId() +// const t = useI18n() + +// return <Text style={styles.leftTitle} size={18}>{t(id)}</Text> +// } +const LeftHeader = () => { + const theme = useTheme() + const id = useNavActiveId() + const t = useI18n() + + const openMenu = () => { + global.app_event.changeMenuVisible(true) + } + + return ( + <View style={{ + ...styles.container, + height: scaleSizeH(HEADER_HEIGHT) + StatusBar.currentHeight, + paddingTop: StatusBar.currentHeight, + }}> + <View style={styles.left}> + <TouchableOpacity style={styles.btn} onPress={openMenu}> + <Icon color={theme['c-font']} name="menu" size={18} /> + </TouchableOpacity> + <TouchableOpacity style={styles.titleBtn} onPress={openMenu}> + <Text style={styles.leftTitle} size={18}>{t(id)}</Text> + </TouchableOpacity> + </View> + {headerComponents[id] ?? null} + + {/* <TouchableOpacity style={styles.btn} onPress={openSetting}> + <Icon style={{ ...styles.btnText, color: theme['c-font'] }} name="setting" size={styles.btnText.fontSize} /> + </TouchableOpacity> */} + </View> + ) +} + + +// const RightTitle = () => { +// const id = useNavActiveId() +// const t = useI18n() + +// return <Text style={styles.rightTitle} size={18}>{t(id)}</Text> +// } +const RightHeader = () => { + const theme = useTheme() + const t = useI18n() + const id = useNavActiveId() + + const openMenu = () => { + global.app_event.changeMenuVisible(true) + } + return ( + <View style={{ + ...styles.container, + height: scaleSizeH(HEADER_HEIGHT) + StatusBar.currentHeight, + paddingTop: StatusBar.currentHeight, + }}> + <View style={styles.left}> + <TouchableOpacity style={styles.titleBtn} onPress={openMenu}> + <Text style={styles.rightTitle} size={18}>{t(id)}</Text> + </TouchableOpacity> + </View> + {headerComponents[id] ?? null} + <TouchableOpacity style={styles.btn} onPress={openMenu}> + <Icon color={theme['c-font']} name="menu" size={18} /> + </TouchableOpacity> + {/* <TouchableOpacity style={styles.btn} onPress={openSetting}> + <Icon style={{ ...styles.btnText, color: theme['c-font'] }} name="setting" size={styles.btnText.fontSize} /> + </TouchableOpacity> */} + </View> + ) +} + +const Header = () => { + const drawerLayoutPosition = useSettingValue('common.drawerLayoutPosition') + + return ( + <> + <StatusBar /> + { + drawerLayoutPosition == 'left' + ? <LeftHeader /> + : <RightHeader /> + } + + </> + ) +} + + +const styles = createStyle({ + container: { + // width: '100%', + paddingRight: 5, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + // backgroundColor: 'rgba(0,0,0,0.1)', + zIndex: 10, + }, + left: { + flex: 1, + flexDirection: 'row', + paddingLeft: 5, + alignItems: 'center', + height: '100%', + }, + btn: { + // flex: 1, + width: HEADER_HEIGHT, + // backgroundColor: 'rgba(0,0,0,0.1)', + alignItems: 'center', + justifyContent: 'center', + height: '100%', + }, + titleBtn: { + flex: 1, + // backgroundColor: 'rgba(0,0,0,0.1)', + height: '100%', + justifyContent: 'center', + }, + leftTitle: { + paddingLeft: 14, + paddingRight: 16, + }, + rightTitle: { + paddingLeft: 16, + paddingRight: 16, + }, +}) + +export default Header diff --git a/src/screens/Home/Vertical/index.tsx b/src/screens/Home/Vertical/index.tsx new file mode 100644 index 000000000..9943d7c8e --- /dev/null +++ b/src/screens/Home/Vertical/index.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import Content from './Content' +import PlayerBar from '../components/PlayerBar' + +export default () => { + return ( + <> + <Content /> + <PlayerBar /> + </> + ) +} diff --git a/src/screens/Home/Download/index.js b/src/screens/Home/Views/Download/index.js similarity index 100% rename from src/screens/Home/Download/index.js rename to src/screens/Home/Views/Download/index.js diff --git a/src/screens/Home/Views/Leaderboard/BoardsList/List.tsx b/src/screens/Home/Views/Leaderboard/BoardsList/List.tsx new file mode 100644 index 000000000..957ee0867 --- /dev/null +++ b/src/screens/Home/Views/Leaderboard/BoardsList/List.tsx @@ -0,0 +1,72 @@ +import React, { forwardRef, useImperativeHandle, useState } from 'react' +import { View, ScrollView } from 'react-native' + +import { createStyle } from '@/utils/tools' +import { type Position } from './ListMenu' +import ListItem, { type ListItemProps } from './ListItem' +import { type BoardItem } from '@/store/leaderboard/state' + +export interface ListProps { + onBoundChange: (listId: string) => void + onShowMenu: (info: { listId: string, name: string, index: number }, position: Position) => void +} +export interface ListType { + setList: (list: BoardItem[], activeId: string) => void + hideMenu: () => void +} + +export default forwardRef<ListType, ListProps>(({ onBoundChange, onShowMenu }, ref) => { + const [activeId, setActiveId] = useState('') + const [longPressIndex, setLongPressIndex] = useState(-1) + const [list, setList] = useState<BoardItem[]>([]) + + useImperativeHandle(ref, () => ({ + setList(list, activeId) { + setList(list) + setActiveId(activeId) + }, + hideMenu() { + setLongPressIndex(-1) + }, + }), []) + + const handleBoundChange = (item: BoardItem) => { + setActiveId(item.id) + onBoundChange(item.id) + } + + const handleShowMenu: ListItemProps['onShowMenu'] = (listId, name, index, position: Position) => { + setLongPressIndex(index) + onShowMenu({ listId, name, index }, position) + } + + return ( + <ScrollView style={styles.scrollView} keyboardShouldPersistTaps={'always'}> + <View> + { + list.map((item, index) => { + return ( + <ListItem + key={item.id} + item={item} + index={index} + longPressIndex={longPressIndex} + activeId={activeId} + onShowMenu={handleShowMenu} + onBoundChange={handleBoundChange} + /> + ) + }) + } + </View> + </ScrollView> + ) +}) + + +const styles = createStyle({ + scrollView: { + flexShrink: 1, + }, +}) + diff --git a/src/screens/Home/Views/Leaderboard/BoardsList/ListItem.tsx b/src/screens/Home/Views/Leaderboard/BoardsList/ListItem.tsx new file mode 100644 index 000000000..15d4e6cc5 --- /dev/null +++ b/src/screens/Home/Views/Leaderboard/BoardsList/ListItem.tsx @@ -0,0 +1,54 @@ +import React, { useCallback, useRef } from 'react' +import Text from '@/components/common/Text' +import { useTheme } from '@/store/theme/hook' +import Button, { type BtnType } from '@/components/common/Button' +import { createStyle } from '@/utils/tools' +import { type BoardItem } from '@/store/leaderboard/state' + +// index={index} +// longPressIndex={longPressIndex} +// activeId={activeId} +// showMenu={showMenu} +// onBoundChange={handleBoundChange} +export interface ListItemProps { + item: BoardItem + index: number + longPressIndex: number + activeId: string + onShowMenu: (id: string, name: string, index: number, position: { x: number, y: number, w: number, h: number }) => void + onBoundChange: (item: BoardItem) => void +} + +export default ({ item, activeId, index, longPressIndex, onBoundChange, onShowMenu }: ListItemProps) => { + const theme = useTheme() + const buttonRef = useRef<BtnType>(null) + + const setPosition = useCallback(() => { + if (buttonRef.current?.measure) { + buttonRef.current.measure((fx, fy, width, height, px, py) => { + // console.log(fx, fy, width, height, px, py) + onShowMenu(item.id, item.name, index, { x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }) + }) + } + }, [index, item, onShowMenu]) + + return ( + <Button + ref={buttonRef} + style={{ ...styles.button, backgroundColor: index == longPressIndex ? theme['c-button-background-active'] : undefined }} + key={item.id} onLongPress={setPosition} + onPress={() => { onBoundChange(item) }} + > + <Text size={14} color={activeId == item.id ? theme['c-primary-font-active'] : theme['c-font']} numberOfLines={1}>{item.name}</Text> + </Button> + ) +} + +const styles = createStyle({ + button: { + paddingLeft: 10, + paddingRight: 10, + paddingTop: 10, + paddingBottom: 10, + }, +}) diff --git a/src/screens/Home/Views/Leaderboard/BoardsList/ListMenu.tsx b/src/screens/Home/Views/Leaderboard/BoardsList/ListMenu.tsx new file mode 100644 index 000000000..f4aa97b31 --- /dev/null +++ b/src/screens/Home/Views/Leaderboard/BoardsList/ListMenu.tsx @@ -0,0 +1,71 @@ +import React, { useMemo, useRef, useImperativeHandle, forwardRef, useState } from 'react' +import { useI18n } from '@/lang' +import Menu, { MenuType, Position } from '@/components/common/Menu' + +export interface SelectInfo { + listId: string + name: string + index: number +} +const initSelectInfo = {} + +export interface ListMenuProps { + onPlay: (selectInfo: SelectInfo) => void + onCollect: (selectInfo: SelectInfo) => void + onHideMenu: () => void +} +export interface ListMenuType { + show: (selectInfo: SelectInfo, position: Position) => void +} + +export type { + Position, +} + +export default forwardRef<ListMenuType, ListMenuProps>((props, ref) => { + const t = useI18n() + const [visible, setVisible] = useState(false) + const menuRef = useRef<MenuType>(null) + const selectInfoRef = useRef<SelectInfo>(initSelectInfo as SelectInfo) + + useImperativeHandle(ref, () => ({ + show(selectInfo, position) { + selectInfoRef.current = selectInfo + if (visible) menuRef.current?.show(position) + else { + setVisible(true) + requestAnimationFrame(() => { + menuRef.current?.show(position) + }) + } + }, + })) + + const menus = useMemo(() => { + return [ + { action: 'play', label: t('play') }, + { action: 'collect', label: t('collect') }, + ] as const + }, [t]) + + const handleMenuPress = ({ action }: typeof menus[number]) => { + const selectInfo = selectInfoRef.current + switch (action) { + case 'play': + props.onPlay(selectInfo) + break + case 'collect': + props.onCollect(selectInfo) + break + default: + break + } + } + + return ( + visible + ? <Menu ref={menuRef} menus={menus} onPress={handleMenuPress} onHide={props.onHideMenu} /> + : null + ) +}) + diff --git a/src/screens/Home/Views/Leaderboard/BoardsList/index.tsx b/src/screens/Home/Views/Leaderboard/BoardsList/index.tsx new file mode 100644 index 000000000..2617a8118 --- /dev/null +++ b/src/screens/Home/Views/Leaderboard/BoardsList/index.tsx @@ -0,0 +1,57 @@ +import React, { forwardRef, useImperativeHandle, useRef } from 'react' +import { StyleSheet, View } from 'react-native' +import List, { type ListType, type ListProps } from './List' +import ListMenu, { type ListMenuType, type Position } from './ListMenu' +import { type BoardItem } from '@/store/leaderboard/state' + + +export interface BoardsListProps { + onBoundChange: (listId: string) => void + onPlay: (listId: string) => void + onCollect: (listId: string, name: string) => void +} +export interface BoardsListType { + setList: (list: BoardItem[], activeId: string) => void +} + +export default forwardRef<BoardsListType, BoardsListProps>(({ onBoundChange, onPlay, onCollect }, ref) => { + const listRef = useRef<ListType>(null) + const listMenuRef = useRef<ListMenuType>(null) + + useImperativeHandle(ref, () => ({ + setList(list, listId) { + listRef.current?.setList(list, listId) + }, + }), []) + + const handleShowMenu: ListProps['onShowMenu'] = ({ listId, name, index }, position: Position) => { + listMenuRef.current?.show({ + listId, + index, + name, + }, position) + } + + return ( + <View style={styles.container}> + <List + ref={listRef} + onBoundChange={onBoundChange} + onShowMenu={handleShowMenu} /> + <ListMenu + ref={listMenuRef} + onHideMenu={() => listRef.current?.hideMenu()} + onPlay={({ listId }) => { onPlay(listId) }} + onCollect={({ listId, name }) => { onCollect(listId, name) }} + /> + </View> + ) +}) + + +const styles = StyleSheet.create({ + container: { + flexGrow: 1, + flexShrink: 1, + }, +}) diff --git a/src/screens/Home/Views/Leaderboard/LeftBar.tsx b/src/screens/Home/Views/Leaderboard/LeftBar.tsx new file mode 100644 index 000000000..4fb7b4a89 --- /dev/null +++ b/src/screens/Home/Views/Leaderboard/LeftBar.tsx @@ -0,0 +1,97 @@ +import React, { forwardRef, useImperativeHandle, useRef } from 'react' +import { View } from 'react-native' + +import SourceSelector, { + type SourceSelectorType as _SourceSelectorType, + // type SourceSelectorProps as _SourceSelectorProps, +} from '@/components/SourceSelector' +import BoardsList, { type BoardsListType, type BoardsListProps } from './BoardsList' +import { BorderWidths } from '@/theme' +import { createStyle } from '@/utils/tools' +import { handleCollect, handlePlay } from './listAction' +import boardState, { type InitState } from '@/store/leaderboard/state' +import { useTheme } from '@/store/theme/hook' +import { getBoardsList } from '@/core/leaderboard' + +type Sources = Readonly<InitState['sources']> +// type SourceSelectorProps = _SourceSelectorProps<Sources> +type SourceSelectorType = _SourceSelectorType<Sources> + +export interface LeftBarProps { + onChangeList: (source: LX.OnlineSource, id: string) => void +} + +export interface LeftBarType { + setBound: (source: LX.OnlineSource, id: string) => void +} + +export default forwardRef<LeftBarType, LeftBarProps>(({ onChangeList }, ref) => { + const theme = useTheme() + const sourceSelectorRef = useRef<SourceSelectorType>(null) + const boardsListRef = useRef<BoardsListType>(null) + const boundInfo = useRef<{ source: LX.OnlineSource, id: string | null }>({ source: 'kw', id: null }) + useImperativeHandle(ref, () => ({ + setBound(source, listId) { + boundInfo.current = { source, id: listId } + sourceSelectorRef.current?.setSourceList(boardState.sources, source) + void getBoardsList(source).then(list => { + boardsListRef.current?.setList(list, listId) + }) + }, + }), []) + + + const onSourceChange = (source: LX.OnlineSource) => { + boundInfo.current.source = source + void getBoardsList(source).then(list => { + const id = list[0].id + requestAnimationFrame(() => { + boardsListRef.current?.setList(list, id) + requestAnimationFrame(() => { + onChangeList(source, id) + }) + }) + }) + } + const onBoundChange: BoardsListProps['onBoundChange'] = (id) => { + boundInfo.current.id = id + onChangeList(boundInfo.current.source, id) + } + const onPlay: BoardsListProps['onPlay'] = (id) => { + boundInfo.current.id = id + void handlePlay(id, boardState.listDetailInfo.list) + } + const onCollect: BoardsListProps['onCollect'] = (id, name) => { + boundInfo.current.id = id + void handleCollect(id, name, boundInfo.current.source) + } + + return ( + <View style={{ ...styles.container, borderRightColor: theme['c-list-header-border-bottom'] }}> + <View style={styles.selector}> + <SourceSelector ref={sourceSelectorRef} onSourceChange={onSourceChange} /> + </View> + <BoardsList + ref={boardsListRef} + onBoundChange={onBoundChange} + onPlay={onPlay} + onCollect={onCollect} + /> + </View> + ) +}) + +const styles = createStyle({ + container: { + flexDirection: 'column', + width: '26%', + maxWidth: 180, + flexGrow: 0, + flexShrink: 0, + borderRightWidth: BorderWidths.normal, + }, + selector: { + height: 38, + }, +}) + diff --git a/src/screens/Home/Views/Leaderboard/MusicList.tsx b/src/screens/Home/Views/Leaderboard/MusicList.tsx new file mode 100644 index 000000000..0c1d6b2a2 --- /dev/null +++ b/src/screens/Home/Views/Leaderboard/MusicList.tsx @@ -0,0 +1,91 @@ +import React, { forwardRef, useEffect, useImperativeHandle, useRef } from 'react' +import OnlineList, { type OnlineListType, type OnlineListProps } from '@/components/OnlineList' +import { getListDetail, setListDetail, setListDetailInfo } from '@/core/leaderboard' +import boardState from '@/store/leaderboard/state' +import { handlePlay } from './listAction' + +// export type MusicListProps = Pick<OnlineListProps, +// 'onLoadMore' +// | 'onPlayList' +// | 'onRefresh' +// > + +export interface MusicListType { + loadList: (source: LX.OnlineSource, listId: string) => void +} + +export default forwardRef<MusicListType, {}>((props, ref) => { + const listRef = useRef<OnlineListType>(null) + const isUnmountedRef = useRef(false) + useImperativeHandle(ref, () => ({ + loadList(source, id) { + const listDetailInfo = boardState.listDetailInfo + listRef.current?.setList([]) + if (listDetailInfo.id == id && listDetailInfo.source == source && listDetailInfo.list.length) { + requestAnimationFrame(() => { + listRef.current?.setList(listDetailInfo.list) + }) + } else { + listRef.current?.setStatus('loading') + const page = 1 + setListDetailInfo(id) + return getListDetail(id, page).then((listDetail) => { + const result = setListDetail(listDetail, id, page) + if (isUnmountedRef.current) return + requestAnimationFrame(() => { + listRef.current?.setList(result.list) + listRef.current?.setStatus(boardState.listDetailInfo.maxPage == page ? 'end' : 'idle') + }) + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + }, + }), []) + + useEffect(() => { + isUnmountedRef.current = false + return () => { + isUnmountedRef.current = true + } + }, []) + + + const handlePlayList: OnlineListProps['onPlayList'] = (index) => { + const listDetailInfo = boardState.listDetailInfo + // console.log(boardState.listDetailInfo) + void handlePlay(listDetailInfo.id, listDetailInfo.list, index) + } + const handleRefresh: OnlineListProps['onRefresh'] = () => { + const page = 1 + listRef.current?.setStatus('refreshing') + getListDetail(boardState.listDetailInfo.id, page, true).then((listDetail) => { + const result = setListDetail(listDetail, boardState.listDetailInfo.id, page) + if (isUnmountedRef.current) return + listRef.current?.setList(result.list) + listRef.current?.setStatus(boardState.listDetailInfo.maxPage == page ? 'end' : 'idle') + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + const handleLoadMore: OnlineListProps['onLoadMore'] = () => { + listRef.current?.setStatus('loading') + const page = boardState.listDetailInfo.list.length ? boardState.listDetailInfo.page + 1 : 1 + getListDetail(boardState.listDetailInfo.id, page).then((listDetail) => { + const result = setListDetail(listDetail, boardState.listDetailInfo.id, page) + if (isUnmountedRef.current) return + listRef.current?.setList(result.list) + listRef.current?.setStatus(boardState.listDetailInfo.maxPage == page ? 'end' : 'idle') + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + + return <OnlineList + ref={listRef} + onPlayList={handlePlayList} + onRefresh={handleRefresh} + onLoadMore={handleLoadMore} + /> +}) + diff --git a/src/screens/Home/Views/Leaderboard/index.tsx b/src/screens/Home/Views/Leaderboard/index.tsx new file mode 100644 index 000000000..f444b5295 --- /dev/null +++ b/src/screens/Home/Views/Leaderboard/index.tsx @@ -0,0 +1,62 @@ +import React, { useEffect, useRef } from 'react' +import { View } from 'react-native' +import { createStyle } from '@/utils/tools' + +import LeftBar, { type LeftBarType, type LeftBarProps } from './LeftBar' +import MusicList, { type MusicListType } from './MusicList' +import { getLeaderboardSetting, saveLeaderboardSetting } from '@/utils/data' +// import { BorderWidths } from '@/theme' +// import { useTheme } from '@/store/theme/hook' + + +export default () => { + const leftBarRef = useRef<LeftBarType>(null) + const musicListRef = useRef<MusicListType>(null) + const isUnmountedRef = useRef(false) + // const theme = useTheme() + + const handleChangeBound: LeftBarProps['onChangeList'] = (source, id) => { + musicListRef.current?.loadList(source, id) + void saveLeaderboardSetting({ + source, + boardId: id, + }) + } + + useEffect(() => { + isUnmountedRef.current = false + void getLeaderboardSetting().then(({ source, boardId }) => { + leftBarRef.current?.setBound(source, boardId) + musicListRef.current?.loadList(source, boardId) + }) + + return () => { + isUnmountedRef.current = true + } + }, []) + + + return ( + <View style={styles.container}> + <LeftBar + ref={leftBarRef} + onChangeList={handleChangeBound} + /> + <MusicList + ref={musicListRef} + /> + </View> + ) +} + +const styles = createStyle({ + container: { + width: '100%', + flex: 1, + flexDirection: 'row', + // borderTopWidth: BorderWidths.normal, + }, + content: { + flex: 1, + }, +}) diff --git a/src/screens/Home/Views/Leaderboard/listAction.ts b/src/screens/Home/Views/Leaderboard/listAction.ts new file mode 100644 index 000000000..831a98925 --- /dev/null +++ b/src/screens/Home/Views/Leaderboard/listAction.ts @@ -0,0 +1,57 @@ +import { createList, setTempList } from '@/core/list' +import { playList } from '@/core/player/player' +import { getListDetail, getListDetailAll } from '@/core/leaderboard' +import { LIST_IDS } from '@/config/constant' +import listState from '@/store/list/state' +import syncSourceList from '@/core/syncSourceList' +import { confirmDialog, toast } from '@/utils/tools' + + +const getListId = (id: string) => `board__${id}` + +export const handlePlay = async(id: string, list?: LX.Music.MusicInfoOnline[], index = 0) => { + let isPlayingList = false + // console.log(list) + const listId = getListId(id) + if (!list?.length) list = (await getListDetail(id, 1)).list + if (list?.length) { + await setTempList(listId, [...list]) + void playList(LIST_IDS.TEMP, index) + isPlayingList = true + } + const fullList = await getListDetailAll(id) + if (!fullList.length) return + if (isPlayingList) { + if (listState.tempListMeta.id == listId) { + await setTempList(listId, [...fullList]) + } + } else { + await setTempList(listId, [...fullList]) + void playList(LIST_IDS.TEMP, index) + } +} + +export const handleCollect = async(id: string, name: string, source: LX.OnlineSource) => { + const listId = getListId(id) + const targetList = listState.userList.find(l => l.id == listId) + if (targetList) { + const confirm = await confirmDialog({ + message: global.i18n.t('duplicate_list_tip', { name: targetList.name }), + cancelButtonText: global.i18n.t('list_import_part_button_cancel'), + confirmButtonText: global.i18n.t('confirm_button_text'), + }) + if (!confirm) return + void syncSourceList(targetList) + return + } + + const list = await getListDetailAll(id) + await createList({ + name, + id: listId, + list, + source, + sourceListId: listId, + }) + toast(global.i18n.t('collect_success')) +} diff --git a/src/screens/Home/Views/Mylist/MusicList/ActiveList.tsx b/src/screens/Home/Views/Mylist/MusicList/ActiveList.tsx new file mode 100644 index 000000000..77829b9fc --- /dev/null +++ b/src/screens/Home/Views/Mylist/MusicList/ActiveList.tsx @@ -0,0 +1,86 @@ +import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react' +import { TouchableOpacity } from 'react-native' + +import { Icon } from '@/components/common/Icon' +import { BorderWidths } from '@/theme' +import { useTheme } from '@/store/theme/hook' +import { useActiveListId } from '@/store/list/hook' +import listState from '@/store/list/state' +import { createStyle } from '@/utils/tools' +import { getListPrevSelectId } from '@/utils/data' +import { setActiveList } from '@/core/list' +import Text from '@/components/common/Text' +import { LIST_IDS } from '@/config/constant' + +export interface ActiveListProps { + onShowSearchBar: () => void +} +export interface ActiveListType { + setVisibleBar: (visible: boolean) => void +} + +export default forwardRef<ActiveListType, ActiveListProps>(({ onShowSearchBar }, ref) => { + const theme = useTheme() + const currentListId = useActiveListId() + let currentListName = currentListId == LIST_IDS.TEMP ? global.i18n.t(`list_${LIST_IDS.TEMP}`) : listState.allList.find(l => l.id === currentListId)?.name ?? '' + const [visibleBar, setVisibleBar] = useState(true) + + useImperativeHandle(ref, () => ({ + setVisibleBar(visible) { + setVisibleBar(visible) + }, + })) + + const showList = () => { + global.app_event.changeLoveListVisible(true) + } + + useEffect(() => { + void getListPrevSelectId().then((id) => { + void setActiveList(id) + }) + }, []) + + return ( + <TouchableOpacity onPress={showList} style={{ ...styles.currentList, opacity: visibleBar ? 1 : 0, borderBottomColor: theme['c-border-background'] }}> + <Icon style={styles.currentListIcon} color={theme['c-button-font']} name="chevron-right" size={12} /> + <Text numberOfLines={1} style={styles.currentListText} color={theme['c-button-font']}>{currentListName}</Text> + <TouchableOpacity style={styles.currentListBtns} onPress={onShowSearchBar}> + <Icon color={theme['c-button-font']} name="search-2" /> + </TouchableOpacity> + </TouchableOpacity> + ) +}) + + +const styles = createStyle({ + currentList: { + flexDirection: 'row', + paddingRight: 2, + height: 36, + alignItems: 'center', + borderBottomWidth: BorderWidths.normal, + // backgroundColor: 'rgba(0,0,0,0.2)', + }, + currentListIcon: { + paddingLeft: 15, + paddingRight: 10, + // paddingTop: 10, + // paddingBottom: 0, + }, + currentListText: { + flex: 1, + // minWidth: 70, + // paddingLeft: 10, + paddingRight: 10, + // paddingTop: 10, + // paddingBottom: 10, + }, + currentListBtns: { + width: 46, + justifyContent: 'center', + alignItems: 'center', + height: '100%', + // backgroundColor: 'rgba(0,0,0,0.2)', + }, +}) diff --git a/src/screens/Home/Views/Mylist/MusicList/List.tsx b/src/screens/Home/Views/Mylist/MusicList/List.tsx new file mode 100644 index 000000000..07dcb7411 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MusicList/List.tsx @@ -0,0 +1,283 @@ +import { playList } from '@/core/player/player' +import React, { useMemo, useRef, useState, useEffect, forwardRef, useImperativeHandle } from 'react' +import { FlatList, type NativeScrollEvent, type NativeSyntheticEvent, InteractionManager, type FlatListProps } from 'react-native' + +import listState from '@/store/list/state' +import playerState from '@/store/player/state' +import { getListPosition, getListPrevSelectId, saveListPosition } from '@/utils/data' +// import { useMusicList } from '@/store/list/hook' +import { getListMusics, setActiveList } from '@/core/list' +import ListItem, { ITEM_HEIGHT } from './ListItem' +import { createStyle } from '@/utils/tools' +import { usePlayInfo, usePlayMusicInfo } from '@/store/player/hook' +import type { Position } from './ListMenu' +import type { SelectMode } from './MultipleModeBar' +import { useActiveListId } from '@/store/list/hook' + +type FlatListType = FlatListProps<LX.Music.MusicInfo> + +export interface ListProps { + onShowMenu: (musicInfo: LX.Music.MusicInfo, index: number, position: Position) => void + onMuiltSelectMode: () => void + onSelectAll: (isAll: boolean) => void +} +export interface ListType { + setIsMultiSelectMode: (isMultiSelectMode: boolean) => void + setSelectMode: (mode: SelectMode) => void + selectAll: (isAll: boolean) => void + getSelectedList: () => LX.List.ListMusics + scrollToInfo: (info: LX.Music.MusicInfo) => void +} + +const usePlayIndex = () => { + const activeListId = useActiveListId() + const playMusicInfo = usePlayMusicInfo() + const playInfo = usePlayInfo() + + const playIndex = useMemo(() => { + return playMusicInfo.listId == activeListId ? playInfo.playIndex : -1 + }, [activeListId, playInfo.playIndex, playMusicInfo.listId]) + + return playIndex +} + + +const List = forwardRef<ListType, ListProps>(({ onShowMenu, onMuiltSelectMode, onSelectAll }, ref) => { + // const t = useI18n() + const flatListRef = useRef<FlatList>(null) + const [currentList, setList] = useState<LX.List.ListMusics>([]) + const listFirstScrollRef = useRef(false) + const isMultiSelectModeRef = useRef(false) + const selectModeRef = useRef<SelectMode>('single') + const prevSelectIndexRef = useRef(-1) + const [selectedList, setSelectedList] = useState<LX.List.ListMusics>([]) + const selectedListRef = useRef<LX.List.ListMusics>([]) + const currentListIdRef = useRef('') + const waitJumpListPositionRef = useRef(false) + // console.log('render music list') + + useImperativeHandle(ref, () => ({ + setIsMultiSelectMode(isMultiSelectMode) { + isMultiSelectModeRef.current = isMultiSelectMode + if (!isMultiSelectMode) { + prevSelectIndexRef.current = -1 + handleUpdateSelectedList([]) + } + }, + setSelectMode(mode) { + selectModeRef.current = mode + }, + selectAll(isAll) { + let list: LX.List.ListMusics + if (isAll) { + list = [...currentList] + } else { + list = [] + } + selectedListRef.current = list + setSelectedList(list) + }, + getSelectedList() { + return selectedListRef.current + }, + scrollToInfo(info) { + void getListMusics(listState.activeListId).then((list) => { + const index = list.findIndex(m => m.id == info.id) + if (index < 0) return + flatListRef.current?.scrollToIndex({ index, viewPosition: 0.3, animated: true }) + }) + }, + })) + + useEffect(() => { + let isUpdateingList = true + const updateList = (id: string) => { + if (currentListIdRef.current == id) return + isUpdateingList = true + setList([]) + currentListIdRef.current = id + void Promise.all([getListMusics(id), getListPosition(id)]).then(([list, position]) => { + requestAnimationFrame(() => { + void InteractionManager.runAfterInteractions(() => { + if (currentListIdRef.current != id) return + selectedListRef.current = [] + setSelectedList([]) + setList([...list]) + requestAnimationFrame(() => { + isUpdateingList = false + listFirstScrollRef.current = true + if (waitJumpListPositionRef.current) { + waitJumpListPositionRef.current = false + if (playerState.playMusicInfo.listId == id && playerState.playInfo.playIndex > -1) { + try { + flatListRef.current?.scrollToIndex({ index: playerState.playInfo.playIndex, viewPosition: 0.3, animated: false }) + return + } catch {} + } + } + flatListRef.current?.scrollToOffset({ offset: position, animated: false }) + }) + }) + }) + }) + } + const handleChange = (ids: string[]) => { + if (!ids.includes(listState.activeListId)) return + const id = listState.activeListId + void getListMusics(id).then((list) => { + if (currentListIdRef.current != id) return + selectedListRef.current = [] + setSelectedList([]) + setList([...list]) + }) + } + + const handleJumpPosition = () => { + requestAnimationFrame(() => { + const listId = playerState.playMusicInfo.listId + if (!listId) return + if (listId != listState.activeListId) { + setActiveList(listId) + if (currentListIdRef.current != listId) waitJumpListPositionRef.current = true + } else if (playerState.playInfo.playIndex > -1) { + if (isUpdateingList) waitJumpListPositionRef.current = true + else { + try { + flatListRef.current?.scrollToIndex({ index: playerState.playInfo.playIndex, viewPosition: 0.3, animated: true }) + } catch {} + } + } + }) + } + if (global.lx.jumpMyListPosition) { + global.lx.jumpMyListPosition = false + if (playerState.playMusicInfo.listId) { + waitJumpListPositionRef.current = true + updateList(playerState.playMusicInfo.listId) + } else void getListPrevSelectId().then(updateList) + } else void getListPrevSelectId().then(updateList) + + global.state_event.on('mylistToggled', updateList) + global.app_event.on('myListMusicUpdate', handleChange) + global.app_event.on('jumpListPosition', handleJumpPosition) + + return () => { + global.state_event.off('mylistToggled', updateList) + global.app_event.off('myListMusicUpdate', handleChange) + global.app_event.off('jumpListPosition', handleJumpPosition) + } + }, []) + + const activeIndex = usePlayIndex() + const handlePlay = (index: number) => { + void playList(listState.activeListId, index) + } + + const handleUpdateSelectedList = (newList: LX.List.ListMusics) => { + if (selectedListRef.current.length && newList.length == currentList.length) onSelectAll(true) + else if (selectedListRef.current.length == currentList.length) onSelectAll(false) + selectedListRef.current = newList + setSelectedList(newList) + } + const handleSelect = (item: LX.Music.MusicInfo, pressIndex: number) => { + let newList: LX.List.ListMusics + if (selectModeRef.current == 'single') { + prevSelectIndexRef.current = pressIndex + const index = selectedListRef.current.indexOf(item) + if (index < 0) { + newList = [...selectedListRef.current, item] + } else { + newList = [...selectedListRef.current] + newList.splice(index, 1) + } + } else { + if (selectedListRef.current.length) { + const prevIndex = prevSelectIndexRef.current + const currentIndex = pressIndex + if (prevIndex == currentIndex) { + newList = [] + } else if (currentIndex > prevIndex) { + newList = currentList.slice(prevIndex, currentIndex + 1) + } else { + newList = currentList.slice(currentIndex, prevIndex + 1) + newList.reverse() + } + } else { + newList = [item] + prevSelectIndexRef.current = pressIndex + } + } + + handleUpdateSelectedList(newList) + } + + const handlePress = (item: LX.Music.MusicInfo, index: number) => { + if (isMultiSelectModeRef.current) { + handleSelect(item, index) + } else { + handlePlay(index) + } + } + + const handleLongPress = (item: LX.Music.MusicInfo, index: number) => { + if (isMultiSelectModeRef.current) return + prevSelectIndexRef.current = index + handleUpdateSelectedList([item]) + onMuiltSelectMode() + } + + const handleScroll = ({ nativeEvent }: NativeSyntheticEvent<NativeScrollEvent>) => { + if (listFirstScrollRef.current) { + listFirstScrollRef.current = false + return + } + void saveListPosition(listState.activeListId, nativeEvent.contentOffset.y) + } + + + const renderItem: FlatListType['renderItem'] = ({ item, index }) => ( + <ListItem + item={item} + index={index} + activeIndex={activeIndex} + onPress={handlePress} + onLongPress={handleLongPress} + onShowMenu={onShowMenu} + selectedList={selectedList} + /> + ) + const getkey: FlatListType['keyExtractor'] = item => item.id + const getItemLayout: FlatListType['getItemLayout'] = (data, index) => { + return { length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index } + } + + return ( + <FlatList + ref={flatListRef} + onScroll={handleScroll} + style={styles.list} + data={currentList} + maxToRenderPerBatch={4} + // updateCellsBatchingPeriod={80} + windowSize={8} + removeClippedSubviews={true} + initialNumToRender={12} + renderItem={renderItem} + keyExtractor={getkey} + extraData={activeIndex} + getItemLayout={getItemLayout} + /> + ) +}) + +const styles = createStyle({ + container: { + flex: 1, + }, + list: { + flexGrow: 1, + flexShrink: 1, + }, +}) + +export default List diff --git a/src/screens/Home/Views/Mylist/MusicList/ListItem.tsx b/src/screens/Home/Views/Mylist/MusicList/ListItem.tsx new file mode 100644 index 000000000..5f71f576f --- /dev/null +++ b/src/screens/Home/Views/Mylist/MusicList/ListItem.tsx @@ -0,0 +1,143 @@ +import React, { memo, useRef } from 'react' +import { View, TouchableOpacity } from 'react-native' +import { LIST_ITEM_HEIGHT } from '@/config/constant' +// import { BorderWidths } from '@/theme' +import { Icon } from '@/components/common/Icon' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { useAssertApiSupport } from '@/store/common/hook' +import { scaleSizeH } from '@/utils/pixelRatio' +import Text from '@/components/common/Text' +import Badge from '@/components/common/Badge' + +export const ITEM_HEIGHT = scaleSizeH(LIST_ITEM_HEIGHT) + +export default memo(({ item, index, activeIndex, onPress, onShowMenu, onLongPress, selectedList }: { + item: LX.Music.MusicInfo + index: number + activeIndex: number + onPress: (item: LX.Music.MusicInfo, index: number) => void + onLongPress: (item: LX.Music.MusicInfo, index: number) => void + onShowMenu: (item: LX.Music.MusicInfo, index: number, position: { x: number, y: number, w: number, h: number }) => void + selectedList: LX.Music.MusicInfo[] +}) => { + const theme = useTheme() + + const isSelected = selectedList.includes(item) + // console.log(item.name, selectedList, selectedList.includes(item)) + const isSupported = useAssertApiSupport(item.source) + const moreButtonRef = useRef<TouchableOpacity>(null) + const handleShowMenu = () => { + if (moreButtonRef.current?.measure) { + moreButtonRef.current.measure((fx, fy, width, height, px, py) => { + // console.log(fx, fy, width, height, px, py) + onShowMenu(item, index, { x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }) + }) + } + } + const active = activeIndex == index + + return ( + <View style={{ ...styles.listItem, height: ITEM_HEIGHT, backgroundColor: isSelected ? theme['c-primary-background-hover'] : 'rgba(0,0,0,0)', opacity: isSupported ? 1 : 0.5 }}> + <TouchableOpacity style={styles.listItemLeft} onPress={() => { onPress(item, index) }} onLongPress={() => { onLongPress(item, index) }}> + { + active + ? <Icon style={styles.sn} name="play-outline" size={13} color={theme['c-primary-font']} /> + : <Text style={styles.sn} size={14} color={theme['c-300']}>{index + 1}</Text> + } + <View style={styles.itemInfo}> + {/* <View style={styles.listItemTitle}> */} + <Text color={active ? theme['c-primary-font'] : theme['c-font']} numberOfLines={1}>{item.name}</Text> + {/* </View> */} + <View style={styles.listItemSingle}> + <Text style={styles.listItemSingleText} size={13} color={active ? theme['c-primary-alpha-200'] : theme['c-500']} numberOfLines={1}>{item.singer}</Text> + <Badge>{item.source}</Badge> + </View> + </View> + </TouchableOpacity> + {/* <View style={styles.listItemRight}> */} + <TouchableOpacity onPress={handleShowMenu} ref={moreButtonRef} style={styles.moreButton}> + <Icon name="dots-vertical" style={{ color: theme['c-350'] }} size={12} /> + </TouchableOpacity> + {/* </View> */} + </View> + ) +}, (prevProps, nextProps) => { + return !!(prevProps.item === nextProps.item && + prevProps.index === nextProps.index && + prevProps.activeIndex != nextProps.index && + nextProps.activeIndex != nextProps.index && + nextProps.selectedList.includes(nextProps.item) == prevProps.selectedList.includes(nextProps.item) + ) +}) + + +const styles = createStyle({ + listItem: { + width: '100%', + flexDirection: 'row', + flexWrap: 'nowrap', + // paddingLeft: 10, + paddingRight: 2, + alignItems: 'center', + // borderBottomWidth: BorderWidths.normal, + }, + listItemLeft: { + flex: 1, + flexGrow: 1, + flexShrink: 1, + flexDirection: 'row', + alignItems: 'center', + }, + sn: { + width: 38, + // fontSize: 12, + textAlign: 'center', + // backgroundColor: 'rgba(0,0,0,0.2)', + paddingLeft: 3, + paddingRight: 3, + }, + itemInfo: { + flexGrow: 0, + flexShrink: 1, + // paddingTop: 10, + // paddingBottom: 10, + }, + // listItemTitle: { + // flexGrow: 0, + // flexShrink: 1, + // }, + listItemSingle: { + paddingTop: 2, + flexDirection: 'row', + // alignItems: 'flex-end', + }, + listItemSingleText: { + // backgroundColor: 'rgba(0,0,0,0.2)', + flexGrow: 0, + flexShrink: 1, + // fontSize: 15, + }, + listItemBadge: { + // fontSize: 10, + paddingLeft: 5, + paddingTop: 2, + alignSelf: 'flex-start', + }, + listItemRight: { + flexGrow: 0, + flexShrink: 0, + flexBasis: 'auto', + justifyContent: 'center', + }, + + moreButton: { + height: '80%', + paddingLeft: 16, + paddingRight: 16, + // paddingTop: 10, + // paddingBottom: 10, + // backgroundColor: 'rgba(0,0,0,0.2)', + justifyContent: 'center', + }, +}) diff --git a/src/screens/Home/Views/Mylist/MusicList/ListMenu.tsx b/src/screens/Home/Views/Mylist/MusicList/ListMenu.tsx new file mode 100644 index 000000000..54e961f5f --- /dev/null +++ b/src/screens/Home/Views/Mylist/MusicList/ListMenu.tsx @@ -0,0 +1,107 @@ +import React, { useMemo, useRef, useImperativeHandle, forwardRef, useState } from 'react' +import { useI18n } from '@/lang' +import Menu, { MenuType, Position } from '@/components/common/Menu' + +export interface SelectInfo { + musicInfo: LX.Music.MusicInfo + selectedList: LX.Music.MusicInfo[] + index: number + listId: string + single: boolean +} +const initSelectInfo = {} + +export interface ListMenuProps { + onPlay: (selectInfo: SelectInfo) => void + onPlayLater: (selectInfo: SelectInfo) => void + onAdd: (selectInfo: SelectInfo) => void + onMove: (selectInfo: SelectInfo) => void + onCopyName: (selectInfo: SelectInfo) => void + onChangePosition: (selectInfo: SelectInfo) => void + onRemove: (selectInfo: SelectInfo) => void +} +export interface ListMenuType { + show: (selectInfo: SelectInfo, position: Position) => void +} + +export type { + Position, +} + +export default forwardRef<ListMenuType, ListMenuProps>((props, ref) => { + const t = useI18n() + const [visible, setVisible] = useState(false) + const menuRef = useRef<MenuType>(null) + const selectInfoRef = useRef<SelectInfo>(initSelectInfo as SelectInfo) + + useImperativeHandle(ref, () => ({ + show(selectInfo, position) { + selectInfoRef.current = selectInfo + if (visible) menuRef.current?.show(position) + else { + setVisible(true) + requestAnimationFrame(() => { + menuRef.current?.show(position) + }) + } + }, + })) + + const menus = useMemo(() => { + return [ + { action: 'play', label: t('play') }, + { action: 'playLater', label: t('play_later') }, + // { action: 'download', label: '下载' }, + { action: 'add', label: t('add_to') }, + { action: 'move', label: t('move_to') }, + { action: 'copyName', label: t('copy_name') }, + { action: 'changePosition', label: t('change_position') }, + { action: 'remove', label: t('delete') }, + ] as const + }, [t]) + + const handleMenuPress = ({ action }: typeof menus[number]) => { + const selectInfo = selectInfoRef.current + switch (action) { + case 'play': + props.onPlay(selectInfo) + break + case 'playLater': + props.onPlayLater(selectInfo) + + break + case 'add': + props.onAdd(selectInfo) + // isMoveRef.current = false + // selectedListRef.current.length + // ? setVisibleMusicMultiAddModal(true) + // : setVisibleMusicAddModal(true) + break + case 'move': + props.onMove(selectInfo) + // isMoveRef.current = true + // selectedListRef.current.length + // ? setVisibleMusicMultiAddModal(true) + // : setVisibleMusicAddModal(true) + break + case 'copyName': + props.onCopyName(selectInfo) + break + case 'changePosition': + props.onChangePosition(selectInfo) + // setVIsibleMusicPosition(true) + break + case 'remove': + props.onRemove(selectInfo) + break + default: + break + } + } + + return ( + visible + ? <Menu ref={menuRef} menus={menus} onPress={handleMenuPress} /> + : null + ) +}) diff --git a/src/screens/Home/Views/Mylist/MusicList/ListMusicSearch.tsx b/src/screens/Home/Views/Mylist/MusicList/ListMusicSearch.tsx new file mode 100644 index 000000000..6e95c60c8 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MusicList/ListMusicSearch.tsx @@ -0,0 +1,147 @@ +import React, { useRef, useImperativeHandle, forwardRef, useState, useEffect } from 'react' +import SearchTipList, { type SearchTipListProps as _SearchTipListProps, type SearchTipListType } from '@/components/SearchTipList' +import { debounce } from '@/utils' +import { searchListMusic } from './listAction' +import Button from '@/components/common/Button' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' +import { useTheme } from '@/store/theme/hook' +import { View } from 'react-native' +import { scaleSizeH } from '@/utils/pixelRatio' +import { getListMusics } from '@/core/list' +import listState from '@/store/list/state' + +type SearchTipListProps = _SearchTipListProps<LX.Music.MusicInfo> +interface ListMusicSearchProps { + onScrollToInfo: (info: LX.Music.MusicInfo) => void +} +export const ITEM_HEIGHT = scaleSizeH(46) + +export interface ListMusicSearchType { + search: (keyword: string, height: number) => void + hide: () => void +} + +export const debounceSearchList = debounce((text: string, list: LX.List.ListMusics, callback: (list: LX.List.ListMusics) => void) => { + // console.log(reslutList) + callback(searchListMusic(list, text)) +}, 200) + + +export default forwardRef<ListMusicSearchType, ListMusicSearchProps>(({ onScrollToInfo }, ref) => { + const searchTipListRef = useRef<SearchTipListType<LX.Music.MusicInfo>>(null) + const [visible, setVisible] = useState(false) + const currentListIdRef = useRef('') + const currentKeywordRef = useRef('') + const theme = useTheme() + + const handleShowList = (keyword: string, height: number) => { + searchTipListRef.current?.setHeight(height) + currentKeywordRef.current = keyword + const id = currentListIdRef.current = listState.activeListId + if (keyword) { + void getListMusics(id).then(list => { + debounceSearchList(keyword, list, (list) => { + if (currentListIdRef.current != id) return + searchTipListRef.current?.setList(list) + }) + }) + } else { + searchTipListRef.current?.setList([]) + } + } + + useImperativeHandle(ref, () => ({ + search(keyword, height) { + if (visible) handleShowList(keyword, height) + else { + setVisible(true) + requestAnimationFrame(() => { + handleShowList(keyword, height) + }) + } + }, + hide() { + currentKeywordRef.current = '' + currentListIdRef.current = '' + searchTipListRef.current?.setList([]) + }, + })) + + useEffect(() => { + const updateList = (id: string) => { + currentListIdRef.current = id + if (!currentKeywordRef.current) return + void getListMusics(listState.activeListId).then(list => { + debounceSearchList(currentKeywordRef.current, list, (list) => { + if (currentListIdRef.current != id) return + searchTipListRef.current?.setList(list) + }) + }) + } + const handleChange = (ids: string[]) => { + if (!ids.includes(listState.activeListId)) return + updateList(listState.activeListId) + } + + global.state_event.on('mylistToggled', updateList) + global.app_event.on('myListMusicUpdate', handleChange) + + return () => { + global.state_event.off('mylistToggled', updateList) + global.app_event.off('myListMusicUpdate', handleChange) + } + }, []) + + const renderItem = ({ item, index }: { item: LX.Music.MusicInfo, index: number }) => { + return ( + <Button style={styles.item} onPress={() => { onScrollToInfo(item) }} key={index}> + <View style={styles.itemName}> + <Text numberOfLines={1}>{item.name}</Text> + <Text style={styles.subName} numberOfLines={1} size={12} color={theme['c-font-label']}>{item.singer} ({item.meta.albumName})</Text> + </View> + <Text style={styles.itemSource} size={12} color={theme['c-font-label']}>{item.source}</Text> + </Button> + ) + } + const getkey: SearchTipListProps['keyExtractor'] = item => item.id + const getItemLayout: SearchTipListProps['getItemLayout'] = (data, index) => { + return { length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index } + } + + return ( + visible + ? <SearchTipList + ref={searchTipListRef} + renderItem={renderItem} + onPressBg={() => searchTipListRef.current?.setList([])} + keyExtractor={getkey} + getItemLayout={getItemLayout} + /> + : null + ) +}) + + +const styles = createStyle({ + item: { + height: ITEM_HEIGHT, + flexDirection: 'row', + alignItems: 'center', + paddingLeft: 15, + paddingRight: 15, + // backgroundColor: 'rgba(0, 0, 0, 0.2)', + }, + itemName: { + flexGrow: 1, + flexShrink: 1, + }, + subName: { + marginTop: 2, + }, + itemSource: { + flexGrow: 0, + flexShrink: 0, + }, +}) + diff --git a/src/screens/Home/Views/Mylist/MusicList/ListSearchBar.tsx b/src/screens/Home/Views/Mylist/MusicList/ListSearchBar.tsx new file mode 100644 index 000000000..6fa70ae95 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MusicList/ListSearchBar.tsx @@ -0,0 +1,167 @@ +import React, { useState, useRef, useCallback, useMemo, forwardRef, useImperativeHandle } from 'react' +import { Animated, View, TouchableOpacity } from 'react-native' + +import Text from '@/components/common/Text' +import Input, { type InputType } from '@/components/common/Input' + +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import { BorderWidths } from '@/theme' + +interface SearchInputProps { + onSearch: (keywork: string) => void +} +type SearchInputType = InputType + +const SearchInput = forwardRef<SearchInputType, SearchInputProps>(({ onSearch }, ref) => { + const [text, setText] = useState('') + + const handleChangeText = (text: string) => { + setText(text) + onSearch(text.trim()) + } + + return ( + <Input + onChangeText={handleChangeText} + placeholder="Find for something..." + value={text} + style={styles.input} + // onFocus={showTipList} + clearBtn + ref={ref} + /> + ) +}) + + +export interface ListSearchBarProps { + onSearch: (keywork: string) => void + onExitSearch: () => void +} +export interface ListSearchBarType { + show: () => void + hide: () => void +} + +export default forwardRef<ListSearchBarType, ListSearchBarProps>(({ onSearch, onExitSearch }, ref) => { + const t = useI18n() + // const isGetDetailFailedRef = useRef(false) + const [visible, setVisible] = useState(false) + const [animatePlayed, setAnimatPlayed] = useState(true) + const animFade = useRef(new Animated.Value(0)).current + const animTranslateY = useRef(new Animated.Value(0)).current + const searchInputRef = useRef<SearchInputType>(null) + + const theme = useTheme() + + useImperativeHandle(ref, () => ({ + show() { + handleShow() + requestAnimationFrame(() => { + searchInputRef.current?.focus() + }) + }, + hide() { + handleHide() + }, + })) + + + const handleShow = useCallback(() => { + // console.log('show List') + setVisible(true) + setAnimatPlayed(false) + animTranslateY.setValue(-20) + + Animated.parallel([ + Animated.timing(animFade, { + toValue: 0.92, + duration: 200, + useNativeDriver: true, + }), + Animated.timing(animTranslateY, { + toValue: 0, + duration: 200, + useNativeDriver: true, + }), + ]).start(() => { + setAnimatPlayed(true) + }) + }, [animFade, animTranslateY]) + + const handleHide = useCallback(() => { + setAnimatPlayed(false) + Animated.parallel([ + Animated.timing(animFade, { + toValue: 0, + duration: 200, + useNativeDriver: true, + }), + Animated.timing(animTranslateY, { + toValue: -20, + duration: 200, + useNativeDriver: true, + }), + ]).start(finished => { + if (!finished) return + setVisible(false) + setAnimatPlayed(true) + }) + }, [animFade, animTranslateY]) + + + const animaStyle = useMemo(() => ({ + ...styles.container, + // backgroundColor: theme['c-content-background'], + borderBottomColor: theme['c-border-background'], + opacity: animFade, // Bind opacity to animated value + transform: [ + { translateY: animTranslateY }, + ], + }), [animFade, animTranslateY, theme]) + + const component = useMemo(() => { + return ( + <Animated.View style={animaStyle}> + <View style={styles.content}> + <SearchInput ref={searchInputRef} onSearch={onSearch} /> + </View> + <TouchableOpacity onPress={onExitSearch} style={styles.btn}> + <Text color={theme['c-button-font']}>{t('list_select_cancel')}</Text> + </TouchableOpacity> + </Animated.View> + ) + }, [animaStyle, onSearch, onExitSearch, theme, t]) + + return !visible && animatePlayed ? null : component +}) + +const styles = createStyle({ + container: { + flex: 1, + position: 'absolute', + left: 0, + top: 0, + width: '100%', + height: '100%', + flexDirection: 'row', + paddingLeft: 10, + borderBottomWidth: BorderWidths.normal, + }, + content: { + flexDirection: 'row', + flex: 1, + }, + input: { + height: '100%', + }, + btn: { + // flex: 1, + paddingLeft: 15, + paddingRight: 15, + alignItems: 'center', + justifyContent: 'center', + }, +}) diff --git a/src/screens/Home/Views/Mylist/MusicList/MultipleModeBar.tsx b/src/screens/Home/Views/Mylist/MusicList/MultipleModeBar.tsx new file mode 100644 index 000000000..56fd43343 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MusicList/MultipleModeBar.tsx @@ -0,0 +1,159 @@ +import React, { useState, useRef, useCallback, useMemo, forwardRef, useImperativeHandle } from 'react' +import { Animated, View, TouchableOpacity } from 'react-native' + +import Text from '@/components/common/Text' +import Button from '@/components/common/Button' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import { BorderWidths } from '@/theme' + +export type SelectMode = 'single' | 'range' + +export interface MultipleModeBarProps { + onSwitchMode: (mode: SelectMode) => void + onSelectAll: (isAll: boolean) => void + onExitSelectMode: () => void +} +export interface MultipleModeBarType { + show: () => void + setVisibleBar: (visible: boolean) => void + setIsSelectAll: (isAll: boolean) => void + setSwitchMode: (mode: SelectMode) => void + exitSelectMode: () => void +} + +export default forwardRef<MultipleModeBarType, MultipleModeBarProps>(({ onSelectAll, onSwitchMode, onExitSelectMode }, ref) => { + // const isGetDetailFailedRef = useRef(false) + const [visible, setVisible] = useState(false) + const [animatePlayed, setAnimatPlayed] = useState(true) + const animFade = useRef(new Animated.Value(0)).current + const animTranslateY = useRef(new Animated.Value(0)).current + const [selectMode, setSelectMode] = useState<SelectMode>('single') + const [isSelectAll, setIsSelectAll] = useState(false) + const [visibleBar, setVisibleBar] = useState(true) + const theme = useTheme() + + useImperativeHandle(ref, () => ({ + show() { + handleShow() + }, + setVisibleBar(visible) { + setVisibleBar(visible) + }, + setIsSelectAll(isAll) { + setIsSelectAll(isAll) + }, + setSwitchMode(mode: SelectMode) { + setSelectMode(mode) + }, + exitSelectMode() { + handleHide() + }, + })) + + const handleShow = useCallback(() => { + // console.log('show List') + setVisible(true) + setAnimatPlayed(false) + animTranslateY.setValue(-20) + + Animated.parallel([ + Animated.timing(animFade, { + toValue: 0.92, + duration: 200, + useNativeDriver: true, + }), + Animated.timing(animTranslateY, { + toValue: 0, + duration: 200, + useNativeDriver: true, + }), + ]).start(() => { + setAnimatPlayed(true) + }) + }, [animFade, animTranslateY]) + + const handleHide = useCallback(() => { + setAnimatPlayed(false) + Animated.parallel([ + Animated.timing(animFade, { + toValue: 0, + duration: 200, + useNativeDriver: true, + }), + Animated.timing(animTranslateY, { + toValue: -20, + duration: 200, + useNativeDriver: true, + }), + ]).start(finished => { + if (!finished) return + setVisible(false) + setAnimatPlayed(true) + }) + }, [animFade, animTranslateY]) + + + const animaStyle = useMemo(() => ({ + ...styles.container, + // backgroundColor: theme['c-content-background'], + borderBottomColor: theme['c-border-background'], + opacity: visibleBar ? animFade : 0, // Bind opacity to animated value + transform: [ + { translateY: animTranslateY }, + ], + }), [animFade, animTranslateY, theme, visibleBar]) + + const handleSelectAll = useCallback(() => { + const selectAll = !isSelectAll + setIsSelectAll(selectAll) + onSelectAll(selectAll) + }, [isSelectAll, onSelectAll]) + + const component = useMemo(() => { + return ( + <Animated.View style={animaStyle}> + <View style={styles.switchBtn}> + <Button onPress={() => { onSwitchMode('single') }} style={{ ...styles.btn, backgroundColor: selectMode == 'single' ? theme['c-button-background'] : 'rgba(0,0,0,0)' }}> + <Text color={theme['c-button-font']}>{global.i18n.t('list_select_single')}</Text> + </Button> + <Button onPress={() => { onSwitchMode('range') }} style={{ ...styles.btn, backgroundColor: selectMode == 'range' ? theme['c-button-background'] : 'rgba(0,0,0,0)' }}> + <Text color={theme['c-button-font']}>{global.i18n.t('list_select_range')}</Text> + </Button> + </View> + <TouchableOpacity onPress={handleSelectAll} style={styles.btn}> + <Text color={theme['c-button-font']}>{global.i18n.t(isSelectAll ? 'list_select_unall' : 'list_select_all')}</Text> + </TouchableOpacity> + <TouchableOpacity onPress={onExitSelectMode} style={styles.btn}> + <Text color={theme['c-button-font']}>{global.i18n.t('list_select_cancel')}</Text> + </TouchableOpacity> + </Animated.View> + ) + }, [animaStyle, selectMode, theme, handleSelectAll, isSelectAll, onExitSelectMode, onSwitchMode]) + + return !visible && animatePlayed ? null : component +}) + +const styles = createStyle({ + container: { + flex: 1, + position: 'absolute', + left: 0, + top: 0, + width: '100%', + height: '100%', + flexDirection: 'row', + borderBottomWidth: BorderWidths.normal, + }, + switchBtn: { + flexDirection: 'row', + flex: 1, + }, + btn: { + // flex: 1, + paddingLeft: 18, + paddingRight: 18, + alignItems: 'center', + justifyContent: 'center', + }, +}) diff --git a/src/screens/Home/Views/Mylist/MusicList/MusicPositionModal.tsx b/src/screens/Home/Views/Mylist/MusicList/MusicPositionModal.tsx new file mode 100644 index 000000000..ea53deae7 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MusicList/MusicPositionModal.tsx @@ -0,0 +1,174 @@ +import React, { useState, useRef, useImperativeHandle, forwardRef } from 'react' +import { View } from 'react-native' + +import ConfirmAlert, { type ConfirmAlertType } from '@/components/common/ConfirmAlert' +import Text from '@/components/common/Text' +import Input, { type InputType } from '@/components/common/Input' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' + +interface TitleType { + updateTitle: (musicInfo: SelectInfo['musicInfo'], selectedList: SelectInfo['selectedList']) => void +} +const Title = forwardRef<TitleType, {}>((props, ref) => { + const [title, setTitle] = useState('') + + useImperativeHandle(ref, () => ({ + updateTitle(musicInfo, selectedList) { + setTitle(selectedList.length + ? global.i18n.t('change_position_music_multi_title', { num: selectedList.length }) + : global.i18n.t('change_position_music_title', { name: musicInfo.name })) + }, + })) + + return ( + <Text style={{ marginBottom: 5 }}>{title}</Text> + ) +}) + +interface PositionInputType { + getText: () => string + setText: (text: string) => void + focus: () => void +} +const PositionInput = forwardRef<PositionInputType, {}>((props, ref) => { + const theme = useTheme() + const t = useI18n() + const [text, setText] = useState('') + const inputRef = useRef<InputType>(null) + + useImperativeHandle(ref, () => ({ + getText() { + return text.trim() + }, + setText(text) { + setText(text) + }, + focus() { + inputRef.current?.focus() + }, + })) + + return ( + <Input + placeholder={t('change_position_tip')} + value={text} + onChangeText={setText} + ref={inputRef} + style={{ ...styles.input, backgroundColor: theme['c-primary-input-background'] }} + /> + ) +}) + + +export interface SelectInfo { + musicInfo: LX.Music.MusicInfo + selectedList: LX.Music.MusicInfo[] + index: number + listId: string + single: boolean +} +const initSelectInfo = {} + +interface MusicPositionModalProps { + onUpdatePosition: (info: SelectInfo, position: number) => void +} + +export interface MusicPositionModalType { + show: (listInfo: SelectInfo) => void +} + + +export default forwardRef<MusicPositionModalType, MusicPositionModalProps>(({ onUpdatePosition }, ref) => { + const alertRef = useRef<ConfirmAlertType>(null) + const titleRef = useRef<TitleType>(null) + const inputRef = useRef<PositionInputType>(null) + const selectedInfo = useRef<SelectInfo>(initSelectInfo as SelectInfo) + const [visible, setVisible] = useState(false) + + const handleShow = () => { + alertRef.current?.setVisible(true) + requestAnimationFrame(() => { + titleRef.current?.updateTitle(selectedInfo.current.musicInfo, selectedInfo.current.selectedList) + setTimeout(() => { + inputRef.current?.focus() + }, 300) + }) + } + useImperativeHandle(ref, () => ({ + show(listInfo) { + selectedInfo.current = listInfo + + if (visible) handleShow() + else { + setVisible(true) + requestAnimationFrame(() => { + handleShow() + }) + } + }, + })) + + + const verify = () => { + let result = /^[1-9]\d*/.exec(inputRef.current?.getText() ?? '') + let num = result ? parseInt(result[0]) : '' + inputRef.current?.setText(num.toString()) + return num + } + const handleSetMusicPosition = () => { + let num = verify() + if (num == '') return + alertRef.current?.setVisible(false) + onUpdatePosition(selectedInfo.current, num as number - 1) + } + + return ( + visible + ? <ConfirmAlert + ref={alertRef} + onConfirm={handleSetMusicPosition} + onHide={() => inputRef.current?.setText('')} + > + <View style={styles.content}> + <Title ref={titleRef} /> + <PositionInput ref={inputRef} /> + </View> + </ConfirmAlert> + : null + ) +}) + +const styles = createStyle({ + content: { + flexGrow: 1, + flexShrink: 1, + flexDirection: 'column', + }, + input: { + flexGrow: 1, + flexShrink: 1, + minWidth: 260, + borderRadius: 4, + // paddingTop: 2, + // paddingBottom: 2, + }, + + // tagTypeList: { + // flexDirection: 'row', + // flexWrap: 'wrap', + // }, + // tagButton: { + // // marginRight: 10, + // borderRadius: 4, + // marginRight: 10, + // marginBottom: 10, + // }, + // tagButtonText: { + // paddingLeft: 12, + // paddingRight: 12, + // paddingTop: 8, + // paddingBottom: 8, + // }, +}) diff --git a/src/screens/Home/Views/Mylist/MusicList/index.tsx b/src/screens/Home/Views/Mylist/MusicList/index.tsx new file mode 100644 index 000000000..ba5561505 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MusicList/index.tsx @@ -0,0 +1,157 @@ +import React, { useRef } from 'react' + +import listState from '@/store/list/state' +import ListMenu, { type ListMenuType, type Position, type SelectInfo } from './ListMenu' +import { handlePlay, handlePlayLater, handleRemove, handleShare, handleUpdateMusicPosition } from './listAction' +import List, { type ListType } from './List' +import ListMusicAdd, { type MusicAddModalType as ListMusicAddType } from '@/components/MusicAddModal' +import ListMusicMultiAdd, { type MusicMultiAddModalType as ListAddMultiType } from '@/components/MusicMultiAddModal' +import { createStyle } from '@/utils/tools' +import { type LayoutChangeEvent, View } from 'react-native' +import ActiveList, { type ActiveListType } from './ActiveList' +import MultipleModeBar, { type SelectMode, type MultipleModeBarType } from './MultipleModeBar' +import ListSearchBar, { type ListSearchBarType } from './ListSearchBar' +import ListMusicSearch, { type ListMusicSearchType } from './ListMusicSearch' +import MusicPositionModal, { type MusicPositionModalType } from './MusicPositionModal' + + +export default () => { + // const t = useI18n() + const activeListRef = useRef<ActiveListType>(null) + const listMusicSearchRef = useRef<ListMusicSearchType>(null) + const listRef = useRef<ListType>(null) + const multipleModeBarRef = useRef<MultipleModeBarType>(null) + const listSearchBarRef = useRef<ListSearchBarType>(null) + const listMusicAddRef = useRef<ListMusicAddType>(null) + const listMusicMultiAddRef = useRef<ListAddMultiType>(null) + const musicPositionModalRef = useRef<MusicPositionModalType>(null) + const listMenuRef = useRef<ListMenuType>(null) + const layoutHeightRef = useRef<number>(0) + const isShowMultipleModeBar = useRef(false) + const isShowSearchBarModeBar = useRef(false) + // console.log('render index list') + + const hancelMultiSelect = () => { + if (isShowSearchBarModeBar.current) { + multipleModeBarRef.current?.setVisibleBar(false) + } else activeListRef.current?.setVisibleBar(false) + isShowMultipleModeBar.current = true + multipleModeBarRef.current?.show() + listRef.current?.setIsMultiSelectMode(true) + } + const hancelExitSelect = () => { + if (isShowSearchBarModeBar.current) { + multipleModeBarRef.current?.setVisibleBar(true) + } else activeListRef.current?.setVisibleBar(true) + // console.log('hancelExitSelect', isShowSearchBarModeBar.current) + multipleModeBarRef.current?.exitSelectMode() + listRef.current?.setIsMultiSelectMode(false) + isShowMultipleModeBar.current = false + } + const hancelSwitchSelectMode = (mode: SelectMode) => { + multipleModeBarRef.current?.setSwitchMode(mode) + listRef.current?.setSelectMode(mode) + } + + const showMenu = (musicInfo: LX.Music.MusicInfo, index: number, position: Position) => { + listMenuRef.current?.show({ + musicInfo, + index, + listId: listState.activeListId, + single: false, + selectedList: listRef.current!.getSelectedList(), + }, position) + } + const handleShowSearch = () => { + isShowSearchBarModeBar.current = true + if (isShowMultipleModeBar.current) { + multipleModeBarRef.current?.setVisibleBar(false) + } else activeListRef.current?.setVisibleBar(false) + listSearchBarRef.current?.show() + } + const handleExitSearch = () => { + isShowSearchBarModeBar.current = false + listMusicSearchRef.current?.hide() + listSearchBarRef.current?.hide() + // console.log('handleExitSearch', isShowMultipleModeBar.current) + if (isShowMultipleModeBar.current) { + multipleModeBarRef.current?.setVisibleBar(true) + } else activeListRef.current?.setVisibleBar(true) + } + const handleScrollToInfo = (info: LX.Music.MusicInfo) => { + listRef.current?.scrollToInfo(info) + handleExitSearch() + } + const onLayout = (e: LayoutChangeEvent) => { + layoutHeightRef.current = e.nativeEvent.layout.height + } + + const handleAddMusic = (info: SelectInfo) => { + if (info.selectedList.length) { + listMusicMultiAddRef.current?.show({ selectedList: info.selectedList, listId: info.listId, isMove: false }) + } else { + listMusicAddRef.current?.show({ musicInfo: info.musicInfo, listId: info.listId, isMove: false }) + } + } + const handleMoveMusic = (info: SelectInfo) => { + if (info.selectedList.length) { + listMusicMultiAddRef.current?.show({ selectedList: info.selectedList, listId: info.listId, isMove: true }) + } else { + listMusicAddRef.current?.show({ musicInfo: info.musicInfo, listId: info.listId, isMove: true }) + } + } + + + return ( + <View style={styles.container}> + <View style={{ zIndex: 2 }}> + <ActiveList ref={activeListRef} onShowSearchBar={handleShowSearch} /> + <MultipleModeBar + ref={multipleModeBarRef} + onSwitchMode={hancelSwitchSelectMode} + onSelectAll={isAll => listRef.current?.selectAll(isAll)} + onExitSelectMode={hancelExitSelect} + /> + <ListSearchBar + ref={listSearchBarRef} + onSearch={keyword => listMusicSearchRef.current?.search(keyword, layoutHeightRef.current)} + onExitSearch={handleExitSearch} + /> + </View> + <View style={{ flex: 1 }} onLayout={onLayout}> + <List + ref={listRef} + onShowMenu={showMenu} + onMuiltSelectMode={hancelMultiSelect} + onSelectAll={isAll => multipleModeBarRef.current?.setIsSelectAll(isAll)} + /> + <ListMusicSearch + ref={listMusicSearchRef} + onScrollToInfo={handleScrollToInfo} + /> + </View> + <ListMusicAdd ref={listMusicAddRef} /> + <ListMusicMultiAdd ref={listMusicMultiAddRef} /> + <MusicPositionModal ref={musicPositionModalRef} + onUpdatePosition={(info, postion) => { handleUpdateMusicPosition(postion, info.listId, info.musicInfo, info.selectedList, hancelExitSelect) }} /> + <ListMenu + ref={listMenuRef} + onPlay={info => { handlePlay(info.listId, info.index) }} + onPlayLater={info => { handlePlayLater(info.listId, info.musicInfo, info.selectedList, hancelExitSelect) }} + onRemove={info => { handleRemove(info.listId, info.musicInfo, info.selectedList, hancelExitSelect) }} + onCopyName={info => { handleShare(info.musicInfo) }} + onAdd={handleAddMusic} + onMove={handleMoveMusic} + onChangePosition={info => musicPositionModalRef.current?.show(info)} + /> + </View> + ) +} + + +const styles = createStyle({ + container: { + flex: 1, + flexDirection: 'column', + }, +}) diff --git a/src/screens/Home/Views/Mylist/MusicList/listAction.ts b/src/screens/Home/Views/Mylist/MusicList/listAction.ts new file mode 100644 index 000000000..4357bafa9 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MusicList/listAction.ts @@ -0,0 +1,71 @@ +import { removeListMusics, updateListMusicPosition } from '@/core/list' +import { playList } from '@/core/player/player' +import { addTempPlayList } from '@/core/player/tempPlayList' +import settingState from '@/store/setting/state' +import { similar, sortInsert } from '@/utils' +import { confirmDialog, shareMusic } from '@/utils/tools' + +import type { SelectInfo } from './ListMenu' + +export const handlePlay = (listId: SelectInfo['listId'], index: SelectInfo['index']) => { + void playList(listId, index) +} +export const handlePlayLater = (listId: SelectInfo['listId'], musicInfo: SelectInfo['musicInfo'], selectedList: SelectInfo['selectedList'], onCancelSelect: () => void) => { + if (selectedList.length) { + addTempPlayList(selectedList.map(s => ({ listId, musicInfo: s }))) + onCancelSelect() + } else { + addTempPlayList([{ listId, musicInfo }]) + } +} + +export const handleRemove = (listId: SelectInfo['listId'], musicInfo: SelectInfo['musicInfo'], selectedList: SelectInfo['selectedList'], onCancelSelect: () => void) => { + if (selectedList.length) { + void confirmDialog({ + message: global.i18n.t('list_remove_music_multi_tip', { num: selectedList.length }), + confirmButtonText: global.i18n.t('list_remove_tip_button'), + }).then(isRemove => { + if (!isRemove) return + void removeListMusics(listId, selectedList.map(s => s.id)) + onCancelSelect() + }) + } else { + void removeListMusics(listId, [musicInfo.id]) + } +} + +export const handleUpdateMusicPosition = (position: number, listId: SelectInfo['listId'], musicInfo: SelectInfo['musicInfo'], selectedList: SelectInfo['selectedList'], onCancelSelect: () => void) => { + if (selectedList.length) { + void updateListMusicPosition(listId, position, selectedList.map(s => s.id)) + onCancelSelect() + } else { + // console.log(listId, position, [musicInfo.id]) + void updateListMusicPosition(listId, position, [musicInfo.id]) + } +} + + +export const handleShare = (musicInfo: SelectInfo['musicInfo']) => { + shareMusic(settingState.setting['common.shareType'], settingState.setting['download.fileName'], musicInfo) +} + + +export const searchListMusic = (list: LX.Music.MusicInfo[], text: string) => { + let result: LX.Music.MusicInfo[] = [] + let rxp = new RegExp(text.split('').map(s => s.replace(/[.*+?^${}()|[\]\\]/, '\\$&')).join('.*') + '.*', 'i') + for (const mInfo of list) { + const str = `${mInfo.name}${mInfo.singer}${mInfo.meta.albumName ? mInfo.meta.albumName : ''}` + if (rxp.test(str)) result.push(mInfo) + } + + const sortedList: Array<{ num: number, data: LX.Music.MusicInfo }> = [] + + for (const mInfo of result) { + sortInsert(sortedList, { + num: similar(text, `${mInfo.name}${mInfo.singer}${mInfo.meta.albumName ? mInfo.meta.albumName : ''}`), + data: mInfo, + }) + } + return sortedList.map(item => item.data).reverse() +} + diff --git a/src/screens/Home/Views/Mylist/MyList/List.tsx b/src/screens/Home/Views/Mylist/MyList/List.tsx new file mode 100644 index 000000000..47db8cea9 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MyList/List.tsx @@ -0,0 +1,186 @@ +import React, { memo, useEffect, useRef } from 'react' +import { View, TouchableOpacity, FlatList, InteractionManager, type NativeScrollEvent, type NativeSyntheticEvent, type FlatListProps } from 'react-native' + +import { Icon } from '@/components/common/Icon' + +import { useTheme } from '@/store/theme/hook' +import { useActiveListId, useMyList } from '@/store/list/hook' +import { createStyle } from '@/utils/tools' +import { LIST_SCROLL_POSITION_KEY } from '@/config/constant' +import { getListPosition, saveListPosition } from '@/utils/data' +import { setActiveList } from '@/core/list' +import Text from '@/components/common/Text' +import { type Position } from './ListMenu' +import { scaleSizeH } from '@/utils/pixelRatio' + +type FlatListType = FlatListProps<LX.List.MyListInfo> + +const ITEM_HEIGHT = scaleSizeH(40) + +const ListItem = memo(({ item, index, activeId, onPress, onShowMenu, loading }: { + onPress: (item: LX.List.MyListInfo) => void + index: number + activeId: string + item: LX.List.MyListInfo + onShowMenu: (item: LX.List.MyListInfo, index: number, position: { x: number, y: number, w: number, h: number }) => void + loading: boolean +}) => { + const theme = useTheme() + const moreButtonRef = useRef<TouchableOpacity>(null) + + const active = activeId == item.id + + const handleShowMenu = () => { + if (moreButtonRef.current?.measure) { + moreButtonRef.current.measure((fx, fy, width, height, px, py) => { + // console.log(fx, fy, width, height, px, py) + onShowMenu(item, index, { x: Math.ceil(px), y: Math.ceil(py), w: Math.ceil(width), h: Math.ceil(height) }) + }) + } + } + + const handlePress = () => { + onPress(item) + } + + return ( + <View style={{ ...styles.listItem, height: ITEM_HEIGHT, opacity: loading ? 0.5 : 1 }}> + { + active + ? <Icon style={styles.listActiveIcon} name="chevron-right" size={12} color={theme['c-primary-font']} /> + : null + } + <TouchableOpacity style={styles.listName} onPress={handlePress}> + <Text numberOfLines={1} color={active ? theme['c-primary-font'] : theme['c-font']}>{item.name}</Text> + </TouchableOpacity> + <TouchableOpacity onPress={handleShowMenu} ref={moreButtonRef} style={styles.listMoreBtn}> + <Icon name="dots-vertical" color={theme['c-350']} size={12} /> + </TouchableOpacity> + </View> + ) +}, (prevProps, nextProps) => { + return !!(prevProps.item === nextProps.item && + prevProps.index === nextProps.index && + prevProps.item.name == nextProps.item.name && + prevProps.activeId != nextProps.item.id && + nextProps.activeId != nextProps.item.id + ) +}) + + +export default ({ onShowMenu }: { + onShowMenu: (info: { listInfo: LX.List.MyListInfo, index: number }, position: Position) => void +}) => { + const flatListRef = useRef<FlatList>(null) + const allList = useMyList() + const activeListId = useActiveListId() + + const handleToggleList = (item: LX.List.MyListInfo) => { + // setVisiblePanel(false) + global.app_event.changeLoveListVisible(false) + void InteractionManager.runAfterInteractions(() => { + setActiveList(item.id) + }) + } + + + const handleScroll = ({ nativeEvent }: NativeSyntheticEvent<NativeScrollEvent>) => { + void saveListPosition(LIST_SCROLL_POSITION_KEY, nativeEvent.contentOffset.y) + } + + const showMenu = (listInfo: LX.List.MyListInfo, index: number, position: Position) => { + onShowMenu({ listInfo, index }, position) + } + + useEffect(() => { + void getListPosition(LIST_SCROLL_POSITION_KEY).then((offset) => { + flatListRef.current?.scrollToOffset({ offset, animated: false }) + }) + }, []) + + const renderItem: FlatListType['renderItem'] = ({ item, index }) => ( + <ListItem + key={item.id} + item={item} + index={index} + loading={false} + activeId={activeListId} + onPress={handleToggleList} + onShowMenu={showMenu} + /> + ) + const getkey: FlatListType['keyExtractor'] = item => item.id + const getItemLayout: FlatListType['getItemLayout'] = (data, index) => { + return { length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index } + } + + return ( + <FlatList + ref={flatListRef} + onScroll={handleScroll} + style={styles.container} + data={allList} + maxToRenderPerBatch={9} + // updateCellsBatchingPeriod={80} + windowSize={9} + removeClippedSubviews={true} + initialNumToRender={18} + renderItem={renderItem} + keyExtractor={getkey} + // extraData={activeIndex} + getItemLayout={getItemLayout} + /> + ) +} + + +const styles = createStyle({ + container: { + flexShrink: 1, + flexGrow: 0, + }, + // listContainer: { + // // borderBottomWidth: BorderWidths.normal2, + // }, + + listItem: { + height: 'auto', + flexDirection: 'row', + alignItems: 'center', + paddingRight: 5, + paddingLeft: 5, + // borderBottomWidth: BorderWidths.normal, + }, + listActiveIcon: { + // width: 18, + marginLeft: 3, + // paddingRight: 5, + textAlign: 'center', + }, + listName: { + height: '100%', + // height: 46, + // paddingTop: 12, + // paddingBottom: 12, + justifyContent: 'center', + flexGrow: 1, + flexShrink: 1, + paddingLeft: 5, + // backgroundColor: 'rgba(0,0,0,0.1)', + }, + // listNameText: { + // // height: 46, + // fontSize: 14, + // }, + listMoreBtn: { + height: '100%', + width: 36, + // height: 46, + // paddingTop: 12, + // paddingBottom: 12, + justifyContent: 'center', + alignItems: 'center', + // backgroundColor: 'rgba(0,0,0,0.1)', + }, +}) + diff --git a/src/screens/Home/Views/Mylist/MyList/ListImportExport.tsx b/src/screens/Home/Views/Mylist/MyList/ListImportExport.tsx new file mode 100644 index 000000000..c7b7a15d4 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MyList/ListImportExport.tsx @@ -0,0 +1,103 @@ +import ChoosePath, { type ChoosePathType } from '@/components/common/ChoosePath' +import { LXM_FILE_EXT_RXP } from '@/config/constant' +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' +import { InteractionManager } from 'react-native' +import { handleExport, handleImport } from './listAction' + +export interface SelectInfo { + listInfo: LX.List.MyListInfo + // selectedList: LX.Music.MusicInfo[] + index: number + // listId: string + // single: boolean + action: 'import' | 'export' +} +const initSelectInfo = {} + +// export interface ListImportExportProps { +// // onRename: (listInfo: LX.List.UserListInfo) => void +// // onImport: (index: number) => void +// // onExport: (listInfo: LX.List.MyListInfo) => void +// // onSync: (listInfo: LX.List.UserListInfo) => void +// // onRemove: (listInfo: LX.List.MyListInfo) => void +// } +export interface ListImportExportType { + import: (listInfo: LX.List.MyListInfo, index: number) => void + export: (listInfo: LX.List.MyListInfo, index: number) => void +} + +export default forwardRef<ListImportExportType, {}>((props, ref) => { + const [visible, setVisible] = useState(false) + const choosePathRef = useRef<ChoosePathType>(null) + const selectInfoRef = useRef<SelectInfo>((initSelectInfo as SelectInfo)) + // console.log('render import export') + + useImperativeHandle(ref, () => ({ + import(listInfo, index) { + selectInfoRef.current = { + action: 'import', + listInfo, + index, + } + if (visible) { + choosePathRef.current?.show({ + title: global.i18n.t('list_import_part_desc'), + dirOnly: false, + filter: LXM_FILE_EXT_RXP, + }) + } else { + setVisible(true) + requestAnimationFrame(() => { + choosePathRef.current?.show({ + title: global.i18n.t('list_import_part_desc'), + dirOnly: false, + filter: LXM_FILE_EXT_RXP, + }) + }) + } + }, + export(listInfo, index) { + selectInfoRef.current = { + action: 'export', + listInfo, + index, + } + if (visible) { + choosePathRef.current?.show({ + title: global.i18n.t('list_export_part_desc'), + dirOnly: true, + filter: LXM_FILE_EXT_RXP, + }) + } else { + setVisible(true) + requestAnimationFrame(() => { + choosePathRef.current?.show({ + title: global.i18n.t('list_export_part_desc'), + dirOnly: true, + filter: LXM_FILE_EXT_RXP, + }) + }) + } + }, + })) + + + const onConfirmPath = (path: string) => { + switch (selectInfoRef.current.action) { + case 'import': + handleImport(path, selectInfoRef.current.index) + break + case 'export': + void InteractionManager.runAfterInteractions(() => { + handleExport(selectInfoRef.current.listInfo, path) + }) + break + } + } + + return ( + visible + ? <ChoosePath ref={choosePathRef} onConfirm={onConfirmPath} /> + : null + ) +}) diff --git a/src/screens/Home/Views/Mylist/MyList/ListMenu.tsx b/src/screens/Home/Views/Mylist/MyList/ListMenu.tsx new file mode 100644 index 000000000..c2f4e78d1 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MyList/ListMenu.tsx @@ -0,0 +1,126 @@ +import React, { useRef, useImperativeHandle, forwardRef, useState } from 'react' +import { useI18n } from '@/lang' +import Menu, { Menus, MenuType, Position } from '@/components/common/Menu' +import { LIST_IDS } from '@/config/constant' +import musicSdk from '@/utils/musicSdk' + +export interface SelectInfo { + listInfo: LX.List.MyListInfo + // selectedList: LX.Music.MusicInfo[] + index: number + // listId: string + // single: boolean +} +const initSelectInfo = {} + +export interface ListMenuProps { + onRename: (listInfo: LX.List.UserListInfo) => void + onImport: (listInfo: LX.List.MyListInfo, index: number) => void + onExport: (listInfo: LX.List.MyListInfo, index: number) => void + onSync: (listInfo: LX.List.UserListInfo) => void + onRemove: (listInfo: LX.List.UserListInfo) => void +} +export interface ListMenuType { + show: (selectInfo: SelectInfo, position: Position) => void +} + +export type { + Position, +} + +export default forwardRef<ListMenuType, ListMenuProps>(({ + onRename, + onImport, + onExport, + onSync, + onRemove, +}, ref) => { + const t = useI18n() + const menuRef = useRef<MenuType>(null) + const selectInfoRef = useRef<SelectInfo>(initSelectInfo as SelectInfo) + const [menus, setMenus] = useState<Menus>([]) + const [visible, setVisible] = useState(false) + + useImperativeHandle(ref, () => ({ + show(selectInfo, position) { + selectInfoRef.current = selectInfo + handleSetMenu(selectInfo.listInfo) + if (visible) menuRef.current?.show(position) + else { + setVisible(true) + requestAnimationFrame(() => { + menuRef.current?.show(position) + }) + } + }, + })) + + const handleSetMenu = (listInfo: LX.List.MyListInfo) => { + let rename = false + let sync = false + let remove = false + let userList: LX.List.UserListInfo + switch (listInfo.id) { + case LIST_IDS.DEFAULT: + case LIST_IDS.LOVE: + break + default: + userList = listInfo as LX.List.UserListInfo + rename = true + remove = true + sync = !!(userList.source && musicSdk[userList.source]?.songList) + break + } + + setMenus([ + { action: 'rename', disabled: !rename, label: t('list_rename') }, + { action: 'sync', disabled: !sync, label: t('list_sync') }, + { action: 'import', label: t('list_import') }, + { action: 'export', label: t('list_export') }, + // { action: 'local_file', label: t('list_select_local_file') }, + // { action: 'changePosition', label: t('change_position') }, + { action: 'remove', disabled: !remove, label: t('list_remove') }, + ]) + } + + const handleMenuPress = ({ action }: typeof menus[number]) => { + const selectInfo = selectInfoRef.current + switch (action) { + case 'rename': + onRename(selectInfo.listInfo as LX.List.UserListInfo) + break + case 'import': + onImport(selectInfo.listInfo, selectInfo.index) + break + case 'export': + onExport(selectInfo.listInfo, selectInfo.index) + break + case 'sync': + onSync(selectInfo.listInfo as LX.List.UserListInfo) + break + // case 'changePosition': + + // break + // case 'local_file': + + // break + case 'remove': + onRemove(selectInfo.listInfo as LX.List.UserListInfo) + break + + default: + break + } + } + + return ( + visible + ? <Menu + ref={menuRef} + menus={menus} + onPress={handleMenuPress} + // width={104} + /> + : null + ) +}) diff --git a/src/screens/Home/Views/Mylist/MyList/ListNameEdit.tsx b/src/screens/Home/Views/Mylist/MyList/ListNameEdit.tsx new file mode 100644 index 000000000..391a8ac25 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MyList/ListNameEdit.tsx @@ -0,0 +1,120 @@ +import React, { useRef, useImperativeHandle, forwardRef, useState } from 'react' +import ConfirmAlert, { type ConfirmAlertType } from '@/components/common/ConfirmAlert' +import Text from '@/components/common/Text' +import { View } from 'react-native' +import Input, { type InputType } from '@/components/common/Input' +import { updateUserList } from '@/core/list' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' + +interface NameInputType { + setName: (text: string) => void + getText: () => string + focus: () => void +} +const NameInput = forwardRef<NameInputType, {}>((props, ref) => { + const theme = useTheme() + const [text, setText] = useState('') + const [placeholder, setPlaceholder] = useState('') + const inputRef = useRef<InputType>(null) + + useImperativeHandle(ref, () => ({ + getText() { + return text.trim() + }, + setName(text) { + setText(text) + setPlaceholder(text) + }, + focus() { + inputRef.current?.focus() + }, + })) + + return ( + <Input + ref={inputRef} + placeholder={placeholder} + value={text} + onChangeText={setText} + style={{ ...styles.input, backgroundColor: theme['c-primary-input-background'] }} + /> + ) +}) + + +export interface ListNameEditType { + show: (listInfo: LX.List.UserListInfo) => void +} +const initSelectInfo = {} + + +export default forwardRef<ListNameEditType, {}>((props, ref) => { + const alertRef = useRef<ConfirmAlertType>(null) + const nameInputRef = useRef<NameInputType>(null) + const selectedListInfo = useRef<LX.List.UserListInfo>(initSelectInfo as LX.List.UserListInfo) + const [visible, setVisible] = useState(false) + + const handleShow = () => { + alertRef.current?.setVisible(true) + requestAnimationFrame(() => { + nameInputRef.current?.setName(selectedListInfo.current.name ?? '') + setTimeout(() => { + nameInputRef.current?.focus() + }, 300) + }) + } + useImperativeHandle(ref, () => ({ + show(listInfo) { + selectedListInfo.current = listInfo + if (visible) handleShow() + else { + setVisible(true) + requestAnimationFrame(() => { + handleShow() + }) + } + }, + })) + + const handleRename = () => { + let name = nameInputRef.current?.getText() ?? '' + if (!name.length) return + if (name.length > 100) name = name.substring(0, 100) + void updateUserList([{ ...selectedListInfo.current, name }]) + alertRef.current?.setVisible(false) + } + + return ( + visible + ? <ConfirmAlert + ref={alertRef} + onConfirm={handleRename} + > + <View style={styles.renameContent}> + <Text style={{ marginBottom: 5 }}>{global.i18n.t('list_rename_title')}</Text> + <NameInput ref={nameInputRef} /> + </View> + </ConfirmAlert> + : null + ) +}) + + +const styles = createStyle({ + renameContent: { + flexGrow: 1, + flexShrink: 1, + flexDirection: 'column', + }, + input: { + flexGrow: 1, + flexShrink: 1, + minWidth: 290, + borderRadius: 4, + // paddingTop: 2, + // paddingBottom: 2, + }, +}) + + diff --git a/src/screens/Home/Views/Mylist/MyList/index.tsx b/src/screens/Home/Views/Mylist/MyList/index.tsx new file mode 100644 index 000000000..0a16634ad --- /dev/null +++ b/src/screens/Home/Views/Mylist/MyList/index.tsx @@ -0,0 +1,54 @@ +import React, { useEffect, useRef, useState } from 'react' + +import ListMenu, { type ListMenuType } from './ListMenu' +import ListNameEdit, { type ListNameEditType } from './ListNameEdit' +import List from './List' +import ListImportExport, { type ListImportExportType } from './ListImportExport' +import { handleRemove, handleSync } from './listAction' +import { InteractionManager } from 'react-native' + + +export default () => { + const [visible, setVisible] = useState(false) + const listMenuRef = useRef<ListMenuType>(null) + const listNameEditRef = useRef<ListNameEditType>(null) + const listImportExportRef = useRef<ListImportExportType>(null) + + useEffect(() => { + let isInited = false + const changeVisible = (visibleList: boolean) => { + if (visibleList && !isInited) { + requestAnimationFrame(() => { + void InteractionManager.runAfterInteractions(() => { + setVisible(true) + }) + }) + isInited = true + } + } + global.app_event.on('changeLoveListVisible', changeVisible) + + return () => { + global.app_event.off('changeLoveListVisible', changeVisible) + } + }, []) + + return ( + visible + ? <> + <List onShowMenu={(info, position) => listMenuRef.current?.show(info, position)} /> + <ListNameEdit ref={listNameEditRef} /> + <ListImportExport ref={listImportExportRef} /> + <ListMenu + ref={listMenuRef} + onRename={info => listNameEditRef.current?.show(info)} + onImport={(info, position) => listImportExportRef.current?.import(info, position)} + onExport={(info, position) => listImportExportRef.current?.export(info, position)} + onRemove={info => { handleRemove(info) }} + onSync={info => { handleSync(info) }} + /> + {/* <ImportExport actionType={actionType} visible={isShowChoosePath} hide={() => setShowChoosePath(false)} selectedListRef={selectedListRef} /> */} + </> + : null + ) +} diff --git a/src/screens/Home/Views/Mylist/MyList/listAction.ts b/src/screens/Home/Views/Mylist/MyList/listAction.ts new file mode 100644 index 000000000..05e3d8de2 --- /dev/null +++ b/src/screens/Home/Views/Mylist/MyList/listAction.ts @@ -0,0 +1,88 @@ +import { getListMusics, removeUserList } from '@/core/list' +import { confirmDialog, handleReadFile, handleSaveFile, showImportTip, toast } from '@/utils/tools' +import syncSourceList from '@/core/syncSourceList' +import { log } from '@/utils/log' +import { filterFileName, filterMusicList, toNewMusicInfo } from '@/utils' +import { handleImportListPart } from '@/screens/Home/Views/Setting/Backup/actions' + +export const handleRemove = (listInfo: LX.List.UserListInfo) => { + void confirmDialog({ + message: global.i18n.t('list_remove_tip', { name: listInfo.name }), + confirmButtonText: global.i18n.t('list_remove_tip_button'), + }).then(isRemove => { + if (!isRemove) return + void removeUserList([listInfo.id]) + }) +} + +const readListData = async(path: string) => { + let configData: any + try { + configData = await handleReadFile(path) + } catch (error: any) { + log.error(error.stack) + throw error + } + let listData: LX.ConfigFile.MyListInfoPart['data'] + switch (configData.type) { + case 'playListPart': + listData = configData.data + listData.list = filterMusicList(listData.list.map(m => toNewMusicInfo(m))) + break + case 'playListPart_v2': + listData = configData.data + break + default: + showImportTip(configData.type) + return null + } + return listData +} + +export const handleImport = (path: string, position: number) => { + toast(global.i18n.t('setting_backup_part_import_list_tip_unzip')) + void readListData(path).then(async listData => { + if (listData == null) return + void handleImportListPart(listData, position) + }).catch(() => { + toast(global.i18n.t('setting_backup_part_import_list_tip_error')) + }) +} + +const exportList = async(listInfo: LX.List.MyListInfo, path: string) => { + const data = JSON.parse(JSON.stringify({ + type: 'playListPart_v2', + data: { + ...listInfo, + list: await getListMusics(listInfo.id), + }, + })) + try { + await handleSaveFile(`${path}/lx_list_part_${filterFileName(listInfo.name)}.lxmc`, data) + } catch (error: any) { + log.error(error.stack) + } +} +export const handleExport = (listInfo: LX.List.MyListInfo, path: string) => { + toast(global.i18n.t('setting_backup_part_export_list_tip_zip')) + exportList(listInfo, path).then(() => { + toast(global.i18n.t('setting_backup_part_export_list_tip_success')) + }).catch((err: any) => { + log.error(err.message) + toast(global.i18n.t('setting_backup_part_export_list_tip_failed') + ': ' + (err.message as string)) + }) +} + +export const handleSync = (listInfo: LX.List.UserListInfo) => { + void confirmDialog({ + message: global.i18n.t('list_sync_confirm_tip', { name: listInfo.name }), + confirmButtonText: global.i18n.t('list_remove_tip_button'), + }).then(isSync => { + if (!isSync) return + void syncSourceList(listInfo).then(() => { + toast(global.i18n.t('list_update_success', { name: listInfo.name })) + }).catch(() => { + toast(global.i18n.t('list_update_error', { name: listInfo.name })) + }) + }) +} diff --git a/src/screens/Home/Views/Mylist/index.tsx b/src/screens/Home/Views/Mylist/index.tsx new file mode 100644 index 000000000..4d45d64f5 --- /dev/null +++ b/src/screens/Home/Views/Mylist/index.tsx @@ -0,0 +1,64 @@ +import React, { useEffect, useRef } from 'react' +import { type DrawerLayoutAndroid } from 'react-native' +import settingState from '@/store/setting/state' +import MusicList from './MusicList' +import MyList from './MyList' +import { useTheme } from '@/store/theme/hook' +import DrawerLayoutFixed from '@/components/common/DrawerLayoutFixed' +import { COMPONENT_IDS } from '@/config/constant' +import { scaleSizeW } from '@/utils/pixelRatio' + +const MAX_WIDTH = scaleSizeW(400) + +export default () => { + const drawer = useRef<DrawerLayoutAndroid>(null) + const theme = useTheme() + // const [width, setWidth] = useState(0) + + useEffect(() => { + const changeVisible = (visible: boolean) => { + if (visible) { + requestAnimationFrame(() => { + drawer.current?.openDrawer() + }) + } else { + drawer.current?.closeDrawer() + } + } + // setWidth(getWindowSise().width * 0.82) + + global.app_event.on('changeLoveListVisible', changeVisible) + + // 就放旋转屏幕后的宽度没有更新的问题 + // const changeEvent = onDimensionChange(({ window }) => { + // setWidth(window.width * 0.82) + // drawer.current?.setNativeProps({ + // width: window.width, + // }) + // }) + + return () => { + global.app_event.off('changeLoveListVisible', changeVisible) + // changeEvent.remove() + } + }, []) + + const navigationView = () => <MyList /> + // console.log('render drawer content') + + return ( + <DrawerLayoutFixed + ref={drawer} + visibleNavNames={[COMPONENT_IDS.home]} + // drawerWidth={width} + widthPercentage={0.82} + widthPercentageMax={MAX_WIDTH} + drawerPosition={settingState.setting['common.drawerLayoutPosition']} + renderNavigationView={navigationView} + drawerBackgroundColor={theme['c-content-background']} + style={{ elevation: 1 }} + > + <MusicList /> + </DrawerLayoutFixed> + ) +} diff --git a/src/screens/Home/Views/Search/BlankView/HistorySearch.tsx b/src/screens/Home/Views/Search/BlankView/HistorySearch.tsx new file mode 100644 index 000000000..45ec0921d --- /dev/null +++ b/src/screens/Home/Views/Search/BlankView/HistorySearch.tsx @@ -0,0 +1,96 @@ +import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react' +import { View } from 'react-native' +import { type InitState } from '@/store/hotSearch/state' +import Button from '@/components/common/Button' +import Text from '@/components/common/Text' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' +import { getSearchHistory } from '@/core/search/search' + + +interface ListProps { + onSearch: (keyword: string) => void +} +export interface HistorySearchType { + show: () => void +} + + +export type List = NonNullable<InitState['sourceList'][keyof InitState['sourceList']]> + +const ListItem = ({ keyword, onSearch }: { + keyword: string + onSearch: (keyword: string) => void +}) => { + const theme = useTheme() + return ( + <Button style={{ ...styles.button, backgroundColor: theme['c-button-background'] }} onPress={() => { onSearch(keyword) }}> + <Text color={theme['c-button-font']} size={13}>{keyword}</Text> + </Button> + ) +} + +export default forwardRef<HistorySearchType, ListProps>((props, ref) => { + const [list, setList] = useState<List>([]) + const isUnmountedRef = useRef(false) + const t = useI18n() + // const theme = useTheme() + + useEffect(() => { + isUnmountedRef.current = false + return () => { + isUnmountedRef.current = true + } + }, []) + + useImperativeHandle(ref, () => ({ + show() { + void getSearchHistory().then((list) => { + if (isUnmountedRef.current) return + setList(list) + }) + }, + }), []) + + return ( + list.length + ? ( + <View> + <Text style={styles.title} size={16}>{t('search_history_search')}</Text> + <View style={styles.list}> + { + list.map(keyword => <ListItem keyword={keyword} key={keyword} onSearch={props.onSearch} />) + } + </View> + </View> + ) + : null + ) +}) + + +const styles = createStyle({ + title: { + // paddingLeft: 15, + paddingTop: 15, + // paddingBottom: 5, + }, + list: { + // paddingLeft: 15, + // paddingRight: 15, + flexDirection: 'row', + flexWrap: 'wrap', + // paddingBottom: 15, + }, + button: { + textAlign: 'center', + paddingLeft: 10, + paddingRight: 10, + paddingTop: 5, + paddingBottom: 5, + borderRadius: 4, + marginRight: 10, + marginTop: 8, + }, +}) diff --git a/src/screens/Home/Views/Search/BlankView/HotSearch.tsx b/src/screens/Home/Views/Search/BlankView/HotSearch.tsx new file mode 100644 index 000000000..69ece0844 --- /dev/null +++ b/src/screens/Home/Views/Search/BlankView/HotSearch.tsx @@ -0,0 +1,98 @@ +import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react' +import { ScrollView, View } from 'react-native' +import { type Source, type InitState } from '@/store/hotSearch/state' +import Button from '@/components/common/Button' +import { getList } from '@/core/hotSearch' +import Text from '@/components/common/Text' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' + + +interface ListProps { + onSearch: (keyword: string) => void +} +export interface HotSearchType { + show: (source: Source) => void +} + + +export type List = NonNullable<InitState['sourceList'][keyof InitState['sourceList']]> + +const ListItem = ({ keyword, onSearch }: { + keyword: string + onSearch: (keyword: string) => void +}) => { + const theme = useTheme() + return ( + <Button style={{ ...styles.button, backgroundColor: theme['c-button-background'] }} onPress={() => { onSearch(keyword) }}> + <Text color={theme['c-button-font']} size={13}>{keyword}</Text> + </Button> + ) +} + +export default forwardRef<HotSearchType, ListProps>((props, ref) => { + // const [listType, setListType] = useState<SearchState['searchType']>('music') + // const listRef = useRef<MusicListType>(null) + const [list, setList] = useState<List>([]) + const t = useI18n() + // const theme = useTheme() + + const isUnmountedRef = useRef(false) + useEffect(() => { + isUnmountedRef.current = false + return () => { + isUnmountedRef.current = true + } + }, []) + + useImperativeHandle(ref, () => ({ + show(source) { + void getList(source).then((list) => { + if (isUnmountedRef.current) return + setList(list) + }) + }, + }), []) + + return ( + list.length + ? ( + <ScrollView> + <Text style={styles.title} size={16}>{t('search_hot_search')}</Text> + <View style={styles.list}> + { + list.map(keyword => <ListItem keyword={keyword} key={keyword} onSearch={props.onSearch} />) + } + </View> + </ScrollView> + ) + : null + ) +}) + + +const styles = createStyle({ + title: { + // paddingLeft: 15, + paddingTop: 15, + // paddingBottom: 10, + }, + list: { + // paddingLeft: 15, + // paddingRight: 15, + flexDirection: 'row', + flexWrap: 'wrap', + // paddingBottom: 15, + }, + button: { + textAlign: 'center', + paddingLeft: 10, + paddingRight: 10, + paddingTop: 5, + paddingBottom: 5, + borderRadius: 4, + marginRight: 10, + marginTop: 8, + }, +}) diff --git a/src/screens/Home/Views/Search/BlankView/index.tsx b/src/screens/Home/Views/Search/BlankView/index.tsx new file mode 100644 index 000000000..906af309e --- /dev/null +++ b/src/screens/Home/Views/Search/BlankView/index.tsx @@ -0,0 +1,81 @@ +import Text from '@/components/common/Text' +import { useI18n } from '@/lang' +import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' +import { ScrollView, View } from 'react-native' +import HistorySearch, { type HistorySearchType } from './HistorySearch' +import HotSearch, { type HotSearchType } from './HotSearch' + +interface BlankViewProps { + onSearch: (keyword: string) => void +} +type Source = LX.OnlineSource | 'all' + +export interface BlankViewType { + show: (source: Source) => void +} + +export default forwardRef<BlankViewType, BlankViewProps>(({ onSearch }, ref) => { + // const [listType, setListType] = useState<SearchState['searchType']>('music') + const [visible, setVisible] = useState(false) + const hotSearchRef = useRef<HotSearchType>(null) + const historySearchRef = useRef<HistorySearchType>(null) + const isShowHotSearch = useSettingValue('search.isShowHotSearch') + const isShowHistorySearch = useSettingValue('search.isShowHistorySearch') + const t = useI18n() + const theme = useTheme() + + const handleShow = (source: Source) => { + hotSearchRef.current?.show(source) + historySearchRef.current?.show() + } + + useImperativeHandle(ref, () => ({ + show(source) { + if (visible) handleShow(source) + else { + setVisible(true) + requestAnimationFrame(() => { + handleShow(source) + }) + } + }, + }), [visible]) + + return ( + visible + ? isShowHotSearch || isShowHistorySearch + ? ( + <ScrollView> + <View style={styles.content}> + { isShowHotSearch ? <HotSearch ref={hotSearchRef} onSearch={onSearch} /> : null } + { isShowHistorySearch ? <HistorySearch ref={historySearchRef} onSearch={onSearch} /> : null } + </View> + </ScrollView> + ) + : ( + <View style={styles.welcome}> + <Text size={22} color={theme['c-font-label']}>{t('search__welcome')}</Text> + </View> + ) + : null + + ) +}) + + +const styles = createStyle({ + content: { + // paddingTop: 15, + paddingBottom: 15, + paddingLeft: 15, + paddingRight: 15, + }, + welcome: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + }, +}) diff --git a/src/screens/Home/Views/Search/HeaderBar/SearchInput.tsx b/src/screens/Home/Views/Search/HeaderBar/SearchInput.tsx new file mode 100644 index 000000000..10d219a87 --- /dev/null +++ b/src/screens/Home/Views/Search/HeaderBar/SearchInput.tsx @@ -0,0 +1,68 @@ +import React, { useCallback, useRef, forwardRef, useImperativeHandle, useState } from 'react' +// import { StyleSheet } from 'react-native' +import Input, { type InputType, type InputProps } from '@/components/common/Input' + +export interface SearchInputProps { + onChangeText: (text: string) => void + onSubmit: (text: string) => void + onBlur: () => void + onTouchStart: () => void +} + +export interface SearchInputType { + setText: (text: string) => void + // getText: () => string + focus: () => void + blur: () => void +} + +export default forwardRef<SearchInputType, SearchInputProps>(({ onChangeText, onSubmit, onBlur, onTouchStart }, ref) => { + // const theme = useTheme() + const [text, setText] = useState('') + const inputRef = useRef<InputType>(null) + + useImperativeHandle(ref, () => ({ + // getText() { + // return text.trim() + // }, + setText(text) { + setText(text) + }, + focus() { + inputRef.current?.focus() + }, + blur() { + inputRef.current?.blur() + }, + })) + + const handleChangeText = (text: string) => { + setText(text) + onChangeText(text.trim()) + } + + const handleClearText = useCallback(() => { + setText('') + onChangeText('') + onSubmit('') + }, [onChangeText, onSubmit]) + + const handleSubmit = useCallback<NonNullable<InputProps['onSubmitEditing']>>(({ nativeEvent: { text } }) => { + onSubmit(text) + }, [onSubmit]) + + return ( + <Input + ref={inputRef} + placeholder="Search for something..." + value={text} + onChangeText={handleChangeText} + // style={{ ...styles.input, backgroundColor: theme['c-primary-input-background'] }} + onBlur={onBlur} + onSubmitEditing={handleSubmit} + onClearText={handleClearText} + onTouchStart={onTouchStart} + clearBtn + /> + ) +}) diff --git a/src/screens/Home/Views/Search/HeaderBar/index.tsx b/src/screens/Home/Views/Search/HeaderBar/index.tsx new file mode 100644 index 000000000..cae923c0a --- /dev/null +++ b/src/screens/Home/Views/Search/HeaderBar/index.tsx @@ -0,0 +1,81 @@ +import React, { useRef, forwardRef, useImperativeHandle } from 'react' +import { View } from 'react-native' + +// import music from '@/utils/musicSdk' +import { BorderWidths } from '@/theme' +// import InsetShadow from 'react-native-inset-shadow' +import SourceSelector, { + type SourceSelectorType as _SourceSelectorType, + type SourceSelectorProps as _SourceSelectorProps, +} from '@/components/SourceSelector' +import SearchInput, { type SearchInputType, type SearchInputProps } from './SearchInput' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { type Source as MusicSource } from '@/store/search/music/state' +import { type Source as SonglistSource } from '@/store/search/songlist/state' + +type Sources = Readonly<Array<MusicSource | SonglistSource>> +type SourceSelectorProps = _SourceSelectorProps<Sources> +type SourceSelectorType = _SourceSelectorType<Sources> + +export interface HeaderBarProps { + onSourceChange: SourceSelectorProps['onSourceChange'] + onTempSearch: SearchInputProps['onChangeText'] + onSearch: SearchInputProps['onSubmit'] + onHideTipList: SearchInputProps['onBlur'] + onShowTipList: SearchInputProps['onTouchStart'] +} + +export interface HeaderBarType { + setSourceList: SourceSelectorType['setSourceList'] + setText: SearchInputType['setText'] + blur: SearchInputType['blur'] +} + + +export default forwardRef<HeaderBarType, HeaderBarProps>(({ onSourceChange, onTempSearch, onSearch, onHideTipList, onShowTipList }, ref) => { + const sourceSelectorRef = useRef<SourceSelectorType>(null) + const searchInputRef = useRef<SearchInputType>(null) + const theme = useTheme() + + useImperativeHandle(ref, () => ({ + setSourceList(list, source) { + sourceSelectorRef.current?.setSourceList(list, source) + }, + setText(text) { + searchInputRef.current?.setText(text) + }, + blur() { + searchInputRef.current?.blur() + }, + }), []) + + + return ( + <View style={{ ...styles.searchBar, borderBottomColor: theme['c-border-background'] }}> + <View style={styles.selector}> + <SourceSelector ref={sourceSelectorRef} onSourceChange={onSourceChange} center /> + </View> + <SearchInput + ref={searchInputRef} + onChangeText={onTempSearch} + onSubmit={onSearch} + onBlur={onHideTipList} + onTouchStart={onShowTipList} + /> + </View> + ) +}) + +const styles = createStyle({ + searchBar: { + flexDirection: 'row', + height: 38, + zIndex: 2, + paddingRight: 10, + borderBottomWidth: BorderWidths.normal, + }, + selector: { + // width: 86, + }, +}) diff --git a/src/screens/Home/Views/Search/List.tsx b/src/screens/Home/Views/Search/List.tsx new file mode 100644 index 000000000..55937e73d --- /dev/null +++ b/src/screens/Home/Views/Search/List.tsx @@ -0,0 +1,47 @@ +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' +import type { InitState as SearchState } from '@/store/search/state' +import type { Source as MusicSource } from '@/store/search/music/state' +import type { Source as SongListSource } from '@/store/search/songlist/state' +import MusicList, { type MusicListType } from './MusicList' +import BlankView, { type BlankViewType } from './BlankView' +import SonglistList from './SonglistList' + +interface ListProps { + onSearch: (keyword: string) => void +} +export interface ListType { + loadList: (text: string, source: MusicSource | SongListSource, type: SearchState['searchType']) => void +} + +export default forwardRef<ListType, ListProps>(({ onSearch }, ref) => { + const [listType, setListType] = useState<SearchState['searchType']>('music') + const [showBlankView, setShowListView] = useState(true) + const listRef = useRef<MusicListType>(null) + const blankViewRef = useRef<BlankViewType>(null) + + useImperativeHandle(ref, () => ({ + loadList(text, source, type) { + if (text) { + setShowListView(false) + setListType(type) + // const listDetailInfo = searchMusicState.listDetailInfo + requestAnimationFrame(() => { + listRef.current?.loadList(text, source) + }) + } else { + setShowListView(true) + requestAnimationFrame(() => { + blankViewRef.current?.show(source) + }) + } + }, + }), []) + + return ( + showBlankView + ? <BlankView ref={blankViewRef} onSearch={onSearch} /> + : listType == 'songlist' + ? <SonglistList ref={listRef} /> + : <MusicList ref={listRef} /> + ) +}) diff --git a/src/screens/Home/Views/Search/MusicList.tsx b/src/screens/Home/Views/Search/MusicList.tsx new file mode 100644 index 000000000..496e9bf35 --- /dev/null +++ b/src/screens/Home/Views/Search/MusicList.tsx @@ -0,0 +1,87 @@ +import React, { forwardRef, useEffect, useImperativeHandle, useRef } from 'react' +import OnlineList, { type OnlineListType, type OnlineListProps } from '@/components/OnlineList' +import { search } from '@/core/search/music' +import searchMusicState, { type ListInfo, type Source } from '@/store/search/music/state' + +// export type MusicListProps = Pick<OnlineListProps, +// 'onLoadMore' +// | 'onPlayList' +// | 'onRefresh' +// > + +export interface MusicListType { + loadList: (text: string, source: Source) => void +} + +export default forwardRef<MusicListType, {}>((props, ref) => { + const listRef = useRef<OnlineListType>(null) + const searchInfoRef = useRef<{ text: string, source: Source }>({ text: '', source: 'kw' }) + const isUnmountedRef = useRef(false) + useImperativeHandle(ref, () => ({ + loadList(text, source) { + // const listDetailInfo = searchMusicState.listDetailInfo + listRef.current?.setList([], source == 'all') + if (searchMusicState.searchText == text && searchMusicState.source == source && searchMusicState.listInfos[searchMusicState.source]!.list.length) { + requestAnimationFrame(() => { + listRef.current?.setList(searchMusicState.listInfos[searchMusicState.source]!.list, source == 'all') + }) + } else { + listRef.current?.setStatus('loading') + const page = 1 + searchInfoRef.current.text = text + searchInfoRef.current.source = source + return search(text, page, source).then((list) => { + // const result = setListInfo(listDetail, id, page) + if (isUnmountedRef.current) return + requestAnimationFrame(() => { + listRef.current?.setList(list, source == 'all') + listRef.current?.setStatus(searchMusicState.listInfos[searchMusicState.source]!.maxPage == page ? 'end' : 'idle') + }) + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + }, + }), []) + + useEffect(() => { + isUnmountedRef.current = false + return () => { + isUnmountedRef.current = true + } + }, []) + + + const handleRefresh: OnlineListProps['onRefresh'] = () => { + const page = 1 + listRef.current?.setStatus('refreshing') + search(searchInfoRef.current.text, page, searchInfoRef.current.source).then((list) => { + // const result = setListInfo(listDetail, searchMusicState.listDetailInfo.id, page) + if (isUnmountedRef.current) return + listRef.current?.setList(list, searchInfoRef.current.source == 'all') + listRef.current?.setStatus(searchMusicState.listInfos[searchInfoRef.current.source]!.maxPage == page ? 'end' : 'idle') + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + const handleLoadMore: OnlineListProps['onLoadMore'] = () => { + listRef.current?.setStatus('loading') + const info = searchMusicState.listInfos[searchInfoRef.current.source] as ListInfo + const page = info?.list.length ? info.page + 1 : 1 + search(searchInfoRef.current.text, page, searchInfoRef.current.source).then((list) => { + // const result = setListInfo(listDetail, searchMusicState.listDetailInfo.id, page) + if (isUnmountedRef.current) return + listRef.current?.setList(list, searchInfoRef.current.source == 'all') + listRef.current?.setStatus(info.maxPage == page ? 'end' : 'idle') + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + + return <OnlineList + ref={listRef} + onRefresh={handleRefresh} + onLoadMore={handleLoadMore} + /> +}) + diff --git a/src/screens/Home/Views/Search/SearchTypeSelector.tsx b/src/screens/Home/Views/Search/SearchTypeSelector.tsx new file mode 100644 index 000000000..66b96010f --- /dev/null +++ b/src/screens/Home/Views/Search/SearchTypeSelector.tsx @@ -0,0 +1,75 @@ +import React, { useEffect, useMemo, useState } from 'react' +import { ScrollView, TouchableOpacity } from 'react-native' + +import { createStyle } from '@/utils/tools' +import { type SearchType } from '@/store/search/state' +import { useI18n } from '@/lang' +import Text from '@/components/common/Text' +import { useTheme } from '@/store/theme/hook' +import { getSearchSetting } from '@/utils/data' + +const SEARCH_TYPE_LIST = [ + 'music', + 'songlist', +] as const + +export default () => { + const t = useI18n() + const theme = useTheme() + const [type, setType] = useState<SearchType>('music') + + useEffect(() => { + void getSearchSetting().then(info => { + setType(info.type) + }) + }, []) + + const list = useMemo(() => { + return SEARCH_TYPE_LIST.map(type => ({ label: t(`search_type_${type}`), id: type })) + }, [t]) + + const handleTypeChange = (type: SearchType) => { + setType(type) + global.app_event.searchTypeChanged(type) + } + + return ( + <ScrollView style={styles.container} keyboardShouldPersistTaps={'always'} horizontal={true}> + { + list.map(t => ( + <TouchableOpacity style={styles.button} onPress={() => { handleTypeChange(t.id) }} key={t.id}> + <Text style={styles.buttonText} color={type == t.id ? theme['c-primary-font-active'] : theme['c-font']}>{t.label}</Text> + </TouchableOpacity> + )) + } + </ScrollView> + ) +} + +const styles = createStyle({ + container: { + height: '100%', + flexGrow: 0, + flexShrink: 1, + // paddingLeft: 5, + // paddingRight: 5, + // backgroundColor: 'rgba(0,0,0,0.1)', + }, + button: { + // height: 38, + // lineHeight: 38, + justifyContent: 'center', + // width: 80, + // backgroundColor: 'rgba(0,0,0,0.1)', + }, + buttonText: { + // height: 38, + // lineHeight: 38, + textAlign: 'center', + paddingLeft: 10, + paddingRight: 10, + // paddingTop: 10, + // paddingBottom: 10, + // width: 80, + }, +}) diff --git a/src/screens/Home/Views/Search/SonglistList.tsx b/src/screens/Home/Views/Search/SonglistList.tsx new file mode 100644 index 000000000..e6a0604ff --- /dev/null +++ b/src/screens/Home/Views/Search/SonglistList.tsx @@ -0,0 +1,88 @@ +import React, { forwardRef, useEffect, useImperativeHandle, useRef } from 'react' + +import { search } from '@/core/search/songlist' +import Songlist, { type SonglistProps, type SonglistType } from '@/screens/Home/Views/SongList/components/Songlist' +import searchSonglistState, { type SearchListInfo, type Source } from '@/store/search/songlist/state' + +// export type MusicListProps = Pick<OnlineListProps, +// 'onLoadMore' +// | 'onPlayList' +// | 'onRefresh' +// > + +export interface MusicListType { + loadList: (text: string, source: Source) => void +} + +export default forwardRef<MusicListType, {}>((props, ref) => { + const listRef = useRef<SonglistType>(null) + const searchInfoRef = useRef<{ text: string, source: Source }>({ text: '', source: 'kw' }) + const isUnmountedRef = useRef(false) + useImperativeHandle(ref, () => ({ + loadList(text, source) { + // const listDetailInfo = searchSonglistState.listDetailInfo + listRef.current?.setList([], source == 'all') + if (searchSonglistState.searchText == text && searchSonglistState.source == source && searchSonglistState.listInfos[searchSonglistState.source]!.list.length) { + requestAnimationFrame(() => { + listRef.current?.setList(searchSonglistState.listInfos[searchSonglistState.source]!.list, source == 'all') + }) + } else { + listRef.current?.setStatus('loading') + const page = 1 + searchInfoRef.current.text = text + searchInfoRef.current.source = source + return search(text, page, source).then((list) => { + // const result = setListInfo(listDetail, id, page) + if (isUnmountedRef.current) return + requestAnimationFrame(() => { + listRef.current?.setList(list, source == 'all') + listRef.current?.setStatus(searchSonglistState.maxPages[searchSonglistState.source] == page ? 'end' : 'idle') + }) + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + }, + }), []) + + useEffect(() => { + isUnmountedRef.current = false + return () => { + isUnmountedRef.current = true + } + }, []) + + + const handleRefresh: SonglistProps['onRefresh'] = () => { + const page = 1 + listRef.current?.setStatus('refreshing') + search(searchInfoRef.current.text, page, searchInfoRef.current.source).then((list) => { + // const result = setListInfo(listDetail, searchSonglistState.listDetailInfo.id, page) + if (isUnmountedRef.current) return + listRef.current?.setList(list, searchInfoRef.current.source == 'all') + listRef.current?.setStatus(searchSonglistState.maxPages[searchSonglistState.source] == page ? 'end' : 'idle') + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + const handleLoadMore: SonglistProps['onLoadMore'] = () => { + listRef.current?.setStatus('loading') + const info = searchSonglistState.listInfos[searchInfoRef.current.source] as SearchListInfo + const page = info.list.length ? info.page + 1 : 1 + search(searchInfoRef.current.text, page, searchInfoRef.current.source).then((list) => { + // const result = setListInfo(listDetail, searchSonglistState.listDetailInfo.id, page) + if (isUnmountedRef.current) return + listRef.current?.setList(list, searchInfoRef.current.source == 'all') + listRef.current?.setStatus(searchSonglistState.maxPages[searchSonglistState.source] == page ? 'end' : 'idle') + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + + return <Songlist + ref={listRef} + onRefresh={handleRefresh} + onLoadMore={handleLoadMore} + /> +}) + diff --git a/src/screens/Home/Views/Search/TipList.tsx b/src/screens/Home/Views/Search/TipList.tsx new file mode 100644 index 000000000..238485733 --- /dev/null +++ b/src/screens/Home/Views/Search/TipList.tsx @@ -0,0 +1,136 @@ +import React, { useRef, useImperativeHandle, forwardRef, useState, useEffect } from 'react' +import SearchTipList, { type SearchTipListProps as _SearchTipListProps, type SearchTipListType as _SearchTipListType } from '@/components/SearchTipList' +import Button from '@/components/common/Button' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' +import { scaleSizeH } from '@/utils/pixelRatio' +import musicSdk from '@/utils/musicSdk' +import searchState, { type InitState as SearchState } from '@/store/search/state' +import { setSearchText, setTipList, setTipListInfo } from '@/core/search/search' +import { debounce } from '@/utils' + +export const ITEM_HEIGHT = scaleSizeH(36) + +export const debounceTipSearch = debounce((keyword: string, source: SearchState['temp_source'], callback: (list: string[]) => void) => { + // console.log(reslutList) + void musicSdk[source].tempSearch.search(keyword).then(callback) +}, 200) + + +export type SearchTipListProps = _SearchTipListProps<string> +export type SearchTipListType = _SearchTipListType<string> + +interface TipListProps { + onSearch: (keyword: string) => void +} +export interface TipListType { + search: (keyword: string, height: number) => void + show: (height: number) => void + hide: () => void +} + +export default forwardRef<TipListType, TipListProps>(({ onSearch }, ref) => { + const searchTipListRef = useRef<SearchTipListType>(null) + const [visible, setVisible] = useState(false) + const visibleListRef = useRef(false) + const isUnmountedRef = useRef(false) + + useEffect(() => { + isUnmountedRef.current = false + return () => { + isUnmountedRef.current = true + } + }, []) + + const handleSearch = (keyword: string, height: number) => { + searchTipListRef.current?.setHeight(height) + setSearchText(keyword) + if (keyword) { + visibleListRef.current = true + setTipListInfo(keyword, searchState.temp_source) + debounceTipSearch(keyword, searchState.temp_source, (list) => { + if (keyword != searchState.tipListInfo.text) return + setTipList(list) + if (!visibleListRef.current || isUnmountedRef.current) return + searchTipListRef.current?.setList(list) + }) + } else { + setTipListInfo(keyword, searchState.temp_source) + setTipList([]) + searchTipListRef.current?.setList([]) + } + } + + const handleShowList = (height: number) => { + searchTipListRef.current?.setHeight(height) + if (searchState.tipListInfo.list.length) { + visibleListRef.current = true + searchTipListRef.current?.setList([...searchState.tipListInfo.list]) + } + } + + useImperativeHandle(ref, () => ({ + search(keyword, height) { + if (visible) handleSearch(keyword, height) + else { + setVisible(true) + requestAnimationFrame(() => { + handleSearch(keyword, height) + }) + } + }, + show(height) { + visibleListRef.current = true + if (visible) handleShowList(height) + else { + setVisible(true) + requestAnimationFrame(() => { + handleShowList(height) + }) + } + }, + hide() { + requestAnimationFrame(() => { + visibleListRef.current = false + searchTipListRef.current?.setList([]) + }) + }, + }), [visible]) + + const renderItem: SearchTipListProps['renderItem'] = ({ item, index }) => { + return ( + <Button style={styles.item} onPress={() => { onSearch(item) }} key={index}> + <Text numberOfLines={1}>{item}</Text> + </Button> + ) + } + const getkey: SearchTipListProps['keyExtractor'] = (item, index) => String(index) + const getItemLayout: SearchTipListProps['getItemLayout'] = (data, index) => { + return { length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index } + } + + return ( + visible + ? <SearchTipList + ref={searchTipListRef} + renderItem={renderItem} + onPressBg={() => searchTipListRef.current?.setList([])} + keyExtractor={getkey} + getItemLayout={getItemLayout} + /> + : null + ) +}) + + +const styles = createStyle({ + item: { + height: ITEM_HEIGHT, + flexDirection: 'row', + alignItems: 'center', + paddingLeft: 15, + paddingRight: 15, + // backgroundColor: 'rgba(0, 0, 0, 0.2)', + }, +}) + diff --git a/src/screens/Home/Views/Search/index.tsx b/src/screens/Home/Views/Search/index.tsx new file mode 100644 index 000000000..19e8e48fc --- /dev/null +++ b/src/screens/Home/Views/Search/index.tsx @@ -0,0 +1,117 @@ +import React, { useRef, useEffect } from 'react' +import { type LayoutChangeEvent, View } from 'react-native' + +// import music from '@/utils/musicSdk' +// import InsetShadow from 'react-native-inset-shadow' +// import TipList from './components/TipList' +// import MusicList from './components/MusicList' +import HeaderBar, { type HeaderBarProps, type HeaderBarType } from './HeaderBar' +import searchState, { type SearchType } from '@/store/search/state' +import searchMusicState from '@/store/search/music/state' +import searchSonglistState from '@/store/search/songlist/state' +import { getSearchSetting, saveSearchSetting } from '@/utils/data' +import { createStyle } from '@/utils/tools' +import TipList, { type TipListType } from './TipList' +import List, { type ListType } from './List' +import { addHistoryWord } from '@/core/search/search' + + +interface SearchInfo { + temp_source: LX.OnlineSource + source: LX.OnlineSource | 'all' + searchType: 'music' | 'songlist' +} + +export default () => { + const headerBarRef = useRef<HeaderBarType>(null) + const searchTipListRef = useRef<TipListType>(null) + const listRef = useRef<ListType>(null) + const layoutHeightRef = useRef<number>(0) + const searchInfo = useRef<SearchInfo>({ temp_source: 'kw', source: 'kw', searchType: 'music' }) + + useEffect(() => { + void getSearchSetting().then(info => { + // info.type = 'music' + searchInfo.current.temp_source = info.temp_source + searchInfo.current.source = info.source + searchInfo.current.searchType = info.type + switch (info.type) { + case 'music': + headerBarRef.current?.setSourceList(searchMusicState.sources, info.source) + break + case 'songlist': + headerBarRef.current?.setSourceList(searchSonglistState.sources, info.source) + break + } + headerBarRef.current?.setText(searchState.searchText) + listRef.current?.loadList(searchState.searchText, searchInfo.current.source, searchInfo.current.searchType) + }) + + const handleTypeChange = (type: SearchType) => { + searchInfo.current.searchType = type + void saveSearchSetting({ type }) + listRef.current?.loadList(searchState.searchText, searchInfo.current.source, type) + } + global.app_event.on('searchTypeChanged', handleTypeChange) + + return () => { + global.app_event.off('searchTypeChanged', handleTypeChange) + } + }, []) + + + const handleLayout = (e: LayoutChangeEvent) => { + layoutHeightRef.current = e.nativeEvent.layout.height + } + + const handleSourceChange: HeaderBarProps['onSourceChange'] = (source) => { + searchInfo.current.source = source + void saveSearchSetting({ source }) + listRef.current?.loadList(searchState.searchText, source, searchInfo.current.searchType) + } + const handleTempSearch: HeaderBarProps['onTempSearch'] = (text) => { + setTimeout(() => { + searchTipListRef.current?.search(text, layoutHeightRef.current) + }, 500) + } + const handleSearch: HeaderBarProps['onSearch'] = (text) => { + searchTipListRef.current?.search(text, layoutHeightRef.current) + searchTipListRef.current?.hide() + headerBarRef.current?.setText(text) + headerBarRef.current?.blur() + void addHistoryWord(text) + listRef.current?.loadList(text, searchInfo.current.source, searchInfo.current.searchType) + } + const handleShowTipList: HeaderBarProps['onShowTipList'] = () => { + setTimeout(() => { + searchTipListRef.current?.show(layoutHeightRef.current) + }, 500) + } + + return ( + <View style={styles.container}> + <HeaderBar + ref={headerBarRef} + onSourceChange={handleSourceChange} + onTempSearch={handleTempSearch} + onSearch={handleSearch} + onHideTipList={() => searchTipListRef.current?.hide()} + onShowTipList={handleShowTipList} + /> + <View style={styles.content} onLayout={handleLayout}> + <TipList ref={searchTipListRef} onSearch={handleSearch} /> + <List ref={listRef} onSearch={handleSearch} /> + </View> + </View> + ) +} + +const styles = createStyle({ + container: { + width: '100%', + flex: 1, + }, + content: { + flex: 1, + }, +}) diff --git a/src/screens/Home/Setting/About.js b/src/screens/Home/Views/Setting/About.tsx similarity index 50% rename from src/screens/Home/Setting/About.js rename to src/screens/Home/Views/Setting/About.tsx index 0f8c8677e..494fd64e9 100644 --- a/src/screens/Home/Setting/About.js +++ b/src/screens/Home/Views/Setting/About.tsx @@ -1,13 +1,15 @@ -import React, { useMemo, memo, useState, useEffect } from 'react' -import { StyleSheet, View, Text, TouchableOpacity } from 'react-native' +import React, { memo } from 'react' +import { StyleSheet, View, TouchableOpacity } from 'react-native' import Section from './components/Section' // import Button from './components/Button' -import { useTranslation } from '@/plugins/i18n' -import { useGetter, useDispatch } from '@/store' import { openUrl } from '@/utils/tools' -import { showPactModal } from '@/navigation' +// import { showPactModal } from '@/navigation' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' +import Text from '@/components/common/Text' +import { showPactModal } from '@/core/common' const qqGroupUrl = 'mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26jump_from%3Dwebapi%26k%3Du1zyxek8roQAwic44nOkBXtG9CfbAxFw' const qqGroupUrl2 = 'mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26jump_from%3Dwebapi%26k%3D-l4kNZ2bPQAuvfCQFFhl1UoibvF5wcrQ' @@ -15,16 +17,16 @@ const qqGroupWebUrl = 'https://qm.qq.com/cgi-bin/qm/qr?k=jRZkyFSZ4FmUuTHA3P_RAXb const qqGroupWebUrl2 = 'https://qm.qq.com/cgi-bin/qm/qr?k=HPNJEfrZpBZ9T8szYWbe2d5JrAAeOt_l&jump_from=webapi' export default memo(() => { - const theme = useGetter('common', 'theme') - const { t } = useTranslation() + const theme = useTheme() + const t = useI18n() const openHomePage = () => { - openUrl('https://github.com/lyswhut/lx-music-mobile#readme') + void openUrl('https://github.com/lyswhut/lx-music-mobile#readme') } const openNetdiskPage = () => { - openUrl('https://www.lanzoui.com/b0bf2cfa/') + void openUrl('https://www.lanzoui.com/b0bf2cfa/') } const openFAQPage = () => { - openUrl('https://lyswhut.github.io/lx-music-doc/mobile/faq') + void openUrl('https://lyswhut.github.io/lx-music-doc/mobile/faq') } // const openIssuesPage = () => { // openUrl('https://github.com/lyswhut/lx-music-mobile/issues') @@ -33,75 +35,73 @@ export default memo(() => { showPactModal() } const openPartPage = () => { - openUrl('https://github.com/lyswhut/lx-music-mobile#%E9%A1%B9%E7%9B%AE%E5%8D%8F%E8%AE%AE') + void openUrl('https://github.com/lyswhut/lx-music-mobile#%E9%A1%B9%E7%9B%AE%E5%8D%8F%E8%AE%AE') } const goToQQGroup = () => { openUrl(qqGroupUrl).catch(() => { - openUrl(qqGroupWebUrl) + void openUrl(qqGroupWebUrl) }) } const goToQQGroup2 = () => { openUrl(qqGroupUrl2).catch(() => { - openUrl(qqGroupWebUrl2) + void openUrl(qqGroupWebUrl2) }) } - const textStyle = StyleSheet.compose(styles.text, { - color: theme.normal, - }) - const textLinkStyle = StyleSheet.compose(styles.text, { + const textLinkStyle = { + ...styles.text, textDecorationLine: 'underline', - color: theme.secondary, - fontSize: 14, - }) + color: theme['c-primary-font'], + // fontSize: 14, + } as const return ( <Section title={t('setting_about')}> <View style={styles.part}> - <Text style={textStyle} >本软件完全免费,代码已开源,开源地址:</Text> + <Text style={styles.text} >本软件完全免费,代码已开源,开源地址:</Text> <TouchableOpacity onPress={openHomePage}> <Text style={textLinkStyle}>https://github.com/lyswhut/lx-music-mobile</Text> </TouchableOpacity> </View> <View style={styles.part}> - <Text style={textStyle} >最新版网盘下载地址:</Text> + <Text style={styles.text} >最新版网盘下载地址:</Text> <TouchableOpacity onPress={openNetdiskPage}> <Text style={textLinkStyle}>网盘地址(密码:glqw)</Text> </TouchableOpacity> </View> <View style={styles.part}> - <Text style={textStyle} >软件的常见问题可转至:</Text> + <Text style={styles.text} >软件的常见问题可转至:</Text> <TouchableOpacity onPress={openFAQPage}> <Text style={textLinkStyle}>常见问题</Text> </TouchableOpacity> </View> <View style={styles.part}> - <Text style={textStyle}><Text style={{ fontWeight: 'bold' }} >本软件没有客服</Text>,但我们整理了一些常见的使用问题,<Text style={{ fontWeight: 'bold' }} >仔细 仔细 仔细 </Text>地阅读常见问题后,</Text> - <Text style={textStyle}>仍有问题可加企鹅群 </Text> + <Text style={styles.text}><Text style={styles.boldText}>本软件没有客服</Text>,但我们整理了一些常见的使用问题,<Text style={styles.boldText} >仔细 仔细 仔细 </Text>地阅读常见问题后,</Text> + <Text style={styles.text}>仍有问题可加企鹅群 </Text> <TouchableOpacity onPress={goToQQGroup}><Text style={textLinkStyle}>830125506</Text></TouchableOpacity> - <Text style={textStyle}> 反馈。</Text> - <Text style={textStyle}>注意:<Text style={{ fontWeight: 'bold' }}>为免满人,无事勿加,入群先看群公告</Text></Text> + <Text style={styles.text}> 反馈。</Text> + <Text style={styles.text}>注意:<Text style={styles.boldText}>为免满人,无事勿加,入群先看群公告</Text></Text> </View> <View style={styles.part}> - <Text style={textStyle}>如果你喜欢并经常使用洛雪音乐,并想要第一时间尝鲜洛雪的新功能<Text style={{ textDecorationLine: 'line-through' }}>(当小白鼠)</Text>,</Text> - <Text style={textStyle}>可以加入测试企鹅群 </Text> + <Text style={styles.text}>如果你喜欢并经常使用洛雪音乐,并想要第一时间尝鲜洛雪的新功能<Text style={styles.throughText}>(当小白鼠)</Text>,</Text> + <Text style={styles.text}>可以加入测试企鹅群 </Text> <TouchableOpacity onPress={goToQQGroup2}><Text style={textLinkStyle}>768786588</Text></TouchableOpacity> - <Text style={textStyle}>注意:测试版的功能可能会不稳定,<Text style={{ fontWeight: 'bold' }}>打算潜水的勿加</Text></Text> + <Text style={styles.text}> 注意:测试版的功能可能会不稳定,<Text style={styles.boldText}>打算潜水的勿加</Text></Text> </View> <View style={styles.part}> - <Text style={textStyle}>由于软件开发的初衷仅是为了对新技术的学习与研究,因此软件直至停止维护都将会一直保持纯净。</Text> + <Text style={styles.text}>由于软件开发的初衷仅是为了对新技术的学习与研究,因此软件直至停止维护都将会一直保持纯净。</Text> </View> <View style={styles.part}> - <Text style={textStyle}>你已签署本软件的</Text> - <TouchableOpacity onPress={openPactModal}><Text style={{ ...styles.text, color: theme.secondary }}>许可协议</Text></TouchableOpacity> - <Text style={textStyle}>,协议的在线版本在</Text> + <Text style={styles.text}>你已签署本软件的</Text> + <TouchableOpacity onPress={openPactModal}><Text style={styles.text} color={theme['c-primary-font']}>许可协议</Text></TouchableOpacity> + <Text style={styles.text}>,协议的在线版本在</Text> <TouchableOpacity onPress={openPartPage}><Text style={textLinkStyle}>这里</Text></TouchableOpacity> </View> <View style={styles.part}> - <Text style={{ ...styles.text, color: theme.normal, fontSize: 12 }}>By:</Text> - <Text style={textStyle}>落雪无痕</Text> + <Text style={styles.text}>By:</Text> + <Text style={styles.text}>落雪无痕</Text> </View> </Section> ) @@ -116,7 +116,17 @@ const styles = StyleSheet.create({ flexWrap: 'wrap', }, text: { - fontSize: 13, + fontSize: 14, + textAlignVertical: 'bottom', + }, + boldText: { + fontSize: 14, + fontWeight: 'bold', + textAlignVertical: 'bottom', + }, + throughText: { + fontSize: 14, + textDecorationLine: 'line-through', textAlignVertical: 'bottom', }, btn: { diff --git a/src/screens/Home/Setting/Backup/All.js b/src/screens/Home/Views/Setting/Backup/All.js similarity index 100% rename from src/screens/Home/Setting/Backup/All.js rename to src/screens/Home/Views/Setting/Backup/All.js diff --git a/src/screens/Home/Views/Setting/Backup/ListImportExport.tsx b/src/screens/Home/Views/Setting/Backup/ListImportExport.tsx new file mode 100644 index 000000000..2d84a7955 --- /dev/null +++ b/src/screens/Home/Views/Setting/Backup/ListImportExport.tsx @@ -0,0 +1,97 @@ +import ChoosePath, { ChoosePathType } from '@/components/common/ChoosePath' +import { LXM_FILE_EXT_RXP } from '@/config/constant' +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' +import { InteractionManager } from 'react-native' +import { handleExportList, handleImportList } from './actions' + +export interface SelectInfo { + // listInfo: LX.List.MyListInfo + // selectedList: LX.Music.MusicInfo[] + // index: number + // listId: string + // single: boolean + action: 'import' | 'export' +} +const initSelectInfo = {} + +// export interface ListImportExportProps { +// // onRename: (listInfo: LX.List.UserListInfo) => void +// // onImport: (index: number) => void +// // onExport: (listInfo: LX.List.MyListInfo) => void +// // onSync: (listInfo: LX.List.UserListInfo) => void +// // onRemove: (listInfo: LX.List.MyListInfo) => void +// } +export interface ListImportExportType { + import: () => void + export: () => void +} + +export default forwardRef<ListImportExportType, {}>((props, ref) => { + const [visible, setVisible] = useState(false) + const choosePathRef = useRef<ChoosePathType>(null) + const selectInfoRef = useRef<SelectInfo>((initSelectInfo as SelectInfo)) + console.log('render import export') + + useImperativeHandle(ref, () => ({ + import() { + selectInfoRef.current.action = 'import' + if (visible) { + choosePathRef.current?.show({ + title: global.i18n.t('list_import_part_desc'), + dirOnly: false, + filter: LXM_FILE_EXT_RXP, + }) + } else { + setVisible(true) + requestAnimationFrame(() => { + choosePathRef.current?.show({ + title: global.i18n.t('list_import_part_desc'), + dirOnly: false, + filter: LXM_FILE_EXT_RXP, + }) + }) + } + }, + export() { + selectInfoRef.current.action = 'export' + if (visible) { + choosePathRef.current?.show({ + title: global.i18n.t('list_export_part_desc'), + dirOnly: true, + filter: LXM_FILE_EXT_RXP, + }) + } else { + setVisible(true) + requestAnimationFrame(() => { + choosePathRef.current?.show({ + title: global.i18n.t('list_export_part_desc'), + dirOnly: true, + filter: LXM_FILE_EXT_RXP, + }) + }) + } + }, + })) + + + const onConfirmPath = (path: string) => { + switch (selectInfoRef.current.action) { + case 'import': + void InteractionManager.runAfterInteractions(() => { + handleImportList(path) + }) + break + case 'export': + void InteractionManager.runAfterInteractions(() => { + handleExportList(path) + }) + break + } + } + + return ( + visible + ? <ChoosePath ref={choosePathRef} onConfirm={onConfirmPath} /> + : null + ) +}) diff --git a/src/screens/Home/Views/Setting/Backup/Part.tsx b/src/screens/Home/Views/Setting/Backup/Part.tsx new file mode 100644 index 000000000..59869fb59 --- /dev/null +++ b/src/screens/Home/Views/Setting/Backup/Part.tsx @@ -0,0 +1,41 @@ +import React, { memo, useRef } from 'react' +import { StyleSheet, View } from 'react-native' + +// import { gzip, ungzip } from 'pako' + +import SubTitle from '../components/SubTitle' +import Button from '../components/Button' +import { useI18n } from '@/lang' +import ListImportExport, { type ListImportExportType } from './ListImportExport' + + +export default memo(() => { + const t = useI18n() + const listImportExportRef = useRef<ListImportExportType>(null) + + return ( + <> + <SubTitle title={t('setting_backup_part')}> + <View style={styles.list}> + <Button onPress={() => listImportExportRef.current?.import()}>{t('setting_backup_part_import_list')}</Button> + <Button onPress={() => listImportExportRef.current?.export()}>{t('setting_backup_part_export_list')}</Button> + {/* <Button onPress={() => importAndExportData('import', 'setting')}>{t('setting_backup_part_import_setting')}</Button> + <Button onPress={() => importAndExportData('export', 'setting')}>{t('setting_backup_part_export_setting')}</Button> */} + </View> + </SubTitle> + {/* <SubTitle title={t('setting_backup_all')}> + <View style={styles.list}> + <Button onPress={() => importAndExportData('import', 'all')}>{t('setting_backup_all_import')}</Button> + <Button onPress={() => importAndExportData('export', 'all')}>{t('setting_backup_all_export')}</Button> + </View> + </SubTitle> */} + <ListImportExport ref={listImportExportRef} /> + </> + ) +}) + +const styles = StyleSheet.create({ + list: { + flexDirection: 'row', + }, +}) diff --git a/src/screens/Home/Views/Setting/Backup/actions.ts b/src/screens/Home/Views/Setting/Backup/actions.ts new file mode 100644 index 000000000..5f420e006 --- /dev/null +++ b/src/screens/Home/Views/Setting/Backup/actions.ts @@ -0,0 +1,182 @@ +import { LIST_IDS } from '@/config/constant' +import { createList, getListMusics, overwriteList, overwriteListFull, overwriteListMusics } from '@/core/list' +import { filterMusicList, fixNewMusicInfoQuality, toNewMusicInfo } from '@/utils' +import { log } from '@/utils/log' +import { confirmDialog, handleReadFile, handleSaveFile, showImportTip, toast } from '@/utils/tools' +import listState from '@/store/list/state' + + +const getAllLists = async() => { + const lists = [] + lists.push(await getListMusics(listState.defaultList.id).then(musics => ({ ...listState.defaultList, list: musics }))) + lists.push(await getListMusics(listState.loveList.id).then(musics => ({ ...listState.loveList, list: musics }))) + + for await (const list of listState.userList) { + lists.push(await getListMusics(list.id).then(musics => ({ ...list, list: musics }))) + } + + return lists +} +const importOldListData = async(lists: any[]) => { + const allLists = await getAllLists() + for (const list of lists) { + try { + const targetList = allLists.find(l => l.id == list.id) + if (targetList) { + targetList.list = filterMusicList((list.list as any[]).map(m => toNewMusicInfo(m))) + } else { + const listInfo = { + name: list.name, + id: list.id, + list: filterMusicList((list.list as any[]).map(m => toNewMusicInfo(m))), + source: list.source, + sourceListId: list.sourceListId, + locationUpdateTime: list.locationUpdateTime ?? null, + } + allLists.push(listInfo as LX.List.UserListInfoFull) + } + } catch (err) { + console.log(err) + } + } + const defaultList = allLists.shift()!.list + const loveList = allLists.shift()!.list + await overwriteListFull({ defaultList, loveList, userList: allLists as LX.List.UserListInfoFull[] }) +} +const importNewListData = async(lists: Array<LX.List.MyDefaultListInfoFull | LX.List.MyLoveListInfoFull | LX.List.UserListInfoFull>) => { + const allLists = await getAllLists() + for (const list of lists) { + try { + const targetList = allLists.find(l => l.id == list.id) + if (targetList) { + targetList.list = filterMusicList(list.list).map(m => fixNewMusicInfoQuality(m)) + } else { + const data = { + name: list.name, + id: list.id, + list: filterMusicList(list.list).map(m => fixNewMusicInfoQuality(m)), + source: (list as LX.List.UserListInfoFull).source, + sourceListId: (list as LX.List.UserListInfoFull).sourceListId, + locationUpdateTime: (list as LX.List.UserListInfoFull).locationUpdateTime ?? null, + } + allLists.push(data as LX.List.UserListInfoFull) + } + } catch (err) { + console.log(err) + } + } + const defaultList = allLists.shift()!.list + const loveList = allLists.shift()!.list + await overwriteListFull({ defaultList, loveList, userList: allLists as LX.List.UserListInfoFull[] }) +} + +/** + * 导入单个列表 + * @param listData + * @param position + * @returns + */ +export const handleImportListPart = async(listData: LX.ConfigFile.MyListInfoPart['data'], position: number = listState.userList.length) => { + const targetList = listState.allList.find(l => l.id === listData.id) + if (targetList) { + const confirm = await confirmDialog({ + message: global.i18n.t('list_import_part_confirm', { importName: listData.name, localName: targetList.name }), + cancelButtonText: global.i18n.t('list_import_part_button_cancel'), + confirmButtonText: global.i18n.t('list_import_part_button_confirm'), + bgClose: false, + }) + if (confirm) { + listData.name = targetList.name + void overwriteList(listData) + toast(global.i18n.t('setting_backup_part_import_list_tip_success')) + return + } + listData.id += `__${Date.now()}` + } + const userList = listData as LX.List.UserListInfoFull + void createList({ + name: userList.name, + id: userList.id, + list: userList.list, + source: userList.source, + sourceListId: userList.sourceListId, + position: Math.max(position, -1), + }).then(() => { + toast(global.i18n.t('setting_backup_part_import_list_tip_success')) + }).catch(() => { + toast(global.i18n.t('setting_backup_part_import_list_tip_error')) + }) +} + +const importPlayList = async(path: string) => { + let configData: any + try { + configData = await handleReadFile(path) + } catch (error: any) { + log.error(error.stack) + throw error + } + + switch (configData.type) { + case 'defautlList': // 兼容0.6.2及以前版本的列表数据 + await overwriteListMusics(LIST_IDS.DEFAULT, filterMusicList((configData.data as LX.List.MyDefaultListInfoFull).list.map(m => toNewMusicInfo(m)))) + break + case 'playList': + await importOldListData(configData.data) + break + case 'playList_v2': + await importNewListData(configData.data) + break + case 'allData': + // 兼容0.6.2及以前版本的列表数据 + if (configData.defaultList) await overwriteListMusics(LIST_IDS.DEFAULT, filterMusicList((configData.defaultList as LX.List.MyDefaultListInfoFull).list.map(m => toNewMusicInfo(m)))) + else await importOldListData(configData.playList) + break + case 'allData_v2': + await importNewListData(configData.playList) + break + case 'playListPart': + configData.data.list = filterMusicList((configData.data as LX.ConfigFile.MyListInfoPart['data']).list.map(m => toNewMusicInfo(m))) + void handleImportListPart(configData.data) + return true + case 'playListPart_v2': + configData.data.list = filterMusicList((configData.data as LX.ConfigFile.MyListInfoPart['data']).list).map(m => fixNewMusicInfoQuality(m)) + void handleImportListPart(configData.data) + return true + default: showImportTip(configData.type) + } +} + +export const handleImportList = (path: string) => { + console.log(path) + toast(global.i18n.t('setting_backup_part_import_list_tip_unzip')) + void importPlayList(path).then((skipTip) => { + if (skipTip) return + toast(global.i18n.t('setting_backup_part_import_list_tip_success')) + }).catch(() => { + toast(global.i18n.t('setting_backup_part_import_list_tip_error')) + }) +} + + +const exportAllList = async(path: string) => { + const data = JSON.parse(JSON.stringify({ + type: 'playList_v2', + data: await getAllLists(), + })) + + try { + await handleSaveFile(path + '/lx_list.lxmc', data) + } catch (error: any) { + log.error(error.stack) + } +} +export const handleExportList = (path: string) => { + toast(global.i18n.t('setting_backup_part_export_list_tip_zip')) + void exportAllList(path).then(() => { + toast(global.i18n.t('setting_backup_part_export_list_tip_success')) + }).catch((err: any) => { + log.error(err.message) + toast(global.i18n.t('setting_backup_part_export_list_tip_failed') + ': ' + (err.message as string)) + }) +} diff --git a/src/screens/Home/Setting/Backup/index.js b/src/screens/Home/Views/Setting/Backup/index.tsx similarity index 78% rename from src/screens/Home/Setting/Backup/index.js rename to src/screens/Home/Views/Setting/Backup/index.tsx index 47ad5e902..e448acd9d 100644 --- a/src/screens/Home/Setting/Backup/index.js +++ b/src/screens/Home/Views/Setting/Backup/index.tsx @@ -1,12 +1,12 @@ +import { useI18n } from '@/lang' import React, { memo } from 'react' import Section from '../components/Section' import Part from './Part' // import MaxCache from './MaxCache' -import { useTranslation } from '@/plugins/i18n' export default memo(() => { - const { t } = useTranslation() + const t = useI18n() return ( <Section title={t('setting_backup')}> diff --git a/src/screens/Home/Views/Setting/Basic/DrawerLayoutPosition.tsx b/src/screens/Home/Views/Setting/Basic/DrawerLayoutPosition.tsx new file mode 100644 index 000000000..8a2b501d2 --- /dev/null +++ b/src/screens/Home/Views/Setting/Basic/DrawerLayoutPosition.tsx @@ -0,0 +1,60 @@ +import React, { memo, useMemo } from 'react' + +import { StyleSheet, View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import CheckBox from '@/components/common/CheckBox' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { updateSetting } from '@/core/common' + +const LIST = [ + { + position: 'left', + name: 'setting_basic_drawer_layout_position_left', + }, + { + position: 'right', + name: 'setting_basic_drawer_layout_position_right', + }, +] as const + +const useActive = (id: LX.AppSetting['common.drawerLayoutPosition']) => { + const drawerLayoutPosition = useSettingValue('common.drawerLayoutPosition') + const isActive = useMemo(() => drawerLayoutPosition == id, [drawerLayoutPosition, id]) + return isActive +} + +const Item = ({ position, label }: { + position: LX.AppSetting['common.drawerLayoutPosition'] + label: string +}) => { + const isActive = useActive(position) + // const [toggleCheckBox, setToggleCheckBox] = useState(false) + return <CheckBox marginRight={8} check={isActive} label={label} onChange={() => updateSetting({ 'common.drawerLayoutPosition': position })} need /> +} + +export default memo(() => { + const t = useI18n() + + const list = useMemo(() => { + return LIST.map((item) => ({ position: item.position, name: t(item.name) })) + }, [t]) + + return ( + <SubTitle title={t('setting_basic_drawer_layout_position')}> + <View style={styles.list}> + { + list.map(({ position, name }) => <Item key={position} position={position} label={name} />) + } + </View> + </SubTitle> + ) +}) + +const styles = StyleSheet.create({ + list: { + flexDirection: 'row', + flexWrap: 'wrap', + }, +}) diff --git a/src/screens/Home/Views/Setting/Basic/FontSize.tsx b/src/screens/Home/Views/Setting/Basic/FontSize.tsx new file mode 100644 index 000000000..a1c4810e5 --- /dev/null +++ b/src/screens/Home/Views/Setting/Basic/FontSize.tsx @@ -0,0 +1,98 @@ +import React, { memo, useMemo } from 'react' + +import { StyleSheet, View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import CheckBox from '@/components/common/CheckBox' +import { useI18n } from '@/lang' +import { setFontSize } from '@/core/common' +import { useFontSize } from '@/store/common/hook' +import Text from '@/components/common/Text' +import { getTextSize } from '@/utils/pixelRatio' +import { useTheme } from '@/store/theme/hook' + +const LIST = [ + { + size: 0.8, + name: 'setting_basic_font_size_80', + }, + { + size: 0.9, + name: 'setting_basic_font_size_90', + }, + { + size: 1, + name: 'setting_basic_font_size_100', + }, + { + size: 1.1, + name: 'setting_basic_font_size_110', + }, + { + size: 1.2, + name: 'setting_basic_font_size_120', + }, + { + size: 1.3, + name: 'setting_basic_font_size_130', + }, +] as const + +type SIZE_TYPE = typeof LIST[number]['size'] + +const useActive = (size: SIZE_TYPE) => { + const _size = useFontSize() + const isActive = useMemo(() => _size == size, [_size, size]) + return isActive +} + +const SizeText = () => { + const size = getTextSize(14) * useFontSize() + const t = useI18n() + const theme = useTheme() + + return <Text style={{ fontSize: size }} color={theme['c-primary']}>{t('setting_basic_font_size_preview')}</Text> +} + +const Item = ({ size, label }: { + size: SIZE_TYPE + label: string +}) => { + const isActive = useActive(size) + // const [toggleCheckBox, setToggleCheckBox] = useState(false) + return <CheckBox marginRight={8} check={isActive} label={label} onChange={() => { setFontSize(size) }} need /> +} + +export default memo(() => { + const t = useI18n() + + const list = useMemo(() => { + return LIST.map((item) => ({ size: item.size, name: t(item.name) })) + }, [t]) + + return ( + <SubTitle title={t('setting_basic_font_size')}> + <View style={styles.preview}> + <SizeText /> + </View> + <View style={styles.list}> + { + list.map(({ size, name }) => <Item key={size} size={size} label={name} />) + } + </View> + </SubTitle> + ) +}) + +const styles = StyleSheet.create({ + preview: { + justifyContent: 'center', + // paddingTop: 3, + paddingBottom: 10, + height: 45, + }, + list: { + flexDirection: 'row', + flexWrap: 'wrap', + }, +}) diff --git a/src/screens/Home/Setting/Basic/IsAutoHidePlayBar.js b/src/screens/Home/Views/Setting/Basic/IsAutoHidePlayBar.js similarity index 100% rename from src/screens/Home/Setting/Basic/IsAutoHidePlayBar.js rename to src/screens/Home/Views/Setting/Basic/IsAutoHidePlayBar.js diff --git a/src/screens/Home/Views/Setting/Basic/IsAutoTheme.tsx b/src/screens/Home/Views/Setting/Basic/IsAutoTheme.tsx new file mode 100644 index 000000000..1f6e54254 --- /dev/null +++ b/src/screens/Home/Views/Setting/Basic/IsAutoTheme.tsx @@ -0,0 +1,43 @@ +import React, { memo } from 'react' +import { View } from 'react-native' + +import CheckBoxItem from '../components/CheckBoxItem' +import { createStyle, getIsSupportedAutoTheme } from '@/utils/tools' +import { useI18n } from '@/lang' +import { updateSetting } from '@/core/common' +import { useSettingValue } from '@/store/setting/hook' +import { getTheme } from '@/theme/themes' +import { applyTheme } from '@/core/theme' +import themeState from '@/store/theme/state' + +const isSupportedAutoTheme = getIsSupportedAutoTheme() + +export default memo(() => { + const t = useI18n() + const isAutoTheme = useSettingValue('common.isAutoTheme') + const setIsAutoTheme = (isAutoTheme: boolean) => { + updateSetting({ 'common.isAutoTheme': isAutoTheme }) + void getTheme().then(theme => { + if (theme.id == themeState.theme.id) return + applyTheme(theme) + }) + } + + + return ( + isSupportedAutoTheme + ? ( + <View style={styles.content}> + <CheckBoxItem check={isAutoTheme} label={t('setting_basic_theme_auto_theme')} onChange={setIsAutoTheme} /> + </View> + ) + : null + ) +}) + +const styles = createStyle({ + content: { + marginTop: 5, + // marginBottom: 5, + }, +}) diff --git a/src/screens/Home/Views/Setting/Basic/IsStartupAutoPlay.tsx b/src/screens/Home/Views/Setting/Basic/IsStartupAutoPlay.tsx new file mode 100644 index 000000000..35277ef38 --- /dev/null +++ b/src/screens/Home/Views/Setting/Basic/IsStartupAutoPlay.tsx @@ -0,0 +1,31 @@ +import { updateSetting } from '@/core/common' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' + + +import CheckBoxItem from '../components/CheckBoxItem' + +export default memo(() => { + const t = useI18n() + const startupAutoPlay = useSettingValue('player.startupAutoPlay') + const setStartupAutoPlay = (startupAutoPlay: boolean) => { + updateSetting({ 'player.startupAutoPlay': startupAutoPlay }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={startupAutoPlay} label={t('setting_basic_startup_auto_play')} onChange={setStartupAutoPlay} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + marginBottom: 15, + }, +}) diff --git a/src/screens/Home/Views/Setting/Basic/Language.tsx b/src/screens/Home/Views/Setting/Basic/Language.tsx new file mode 100644 index 000000000..72fc8844d --- /dev/null +++ b/src/screens/Home/Views/Setting/Basic/Language.tsx @@ -0,0 +1,46 @@ +import React, { memo, useMemo } from 'react' + +import { StyleSheet, View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import CheckBox from '@/components/common/CheckBox' +import type { I18n } from '@/lang' +import { useI18n, langList } from '@/lang' +import { setLanguage } from '@/core/common' +import { useSettingValue } from '@/store/setting/hook' + +const useActive = (id: I18n['locale']) => { + const activeLangId = useSettingValue('common.langId') + const isActive = useMemo(() => activeLangId == id, [activeLangId, id]) + return isActive +} + +const Item = ({ id, name }: { + id: I18n['locale'] + name: string +}) => { + const isActive = useActive(id) + // const [toggleCheckBox, setToggleCheckBox] = useState(false) + return <CheckBox marginRight={8} check={isActive} label={name} onChange={() => setLanguage(id)} need /> +} + +export default memo(() => { + const t = useI18n() + + return ( + <SubTitle title={t('setting_basic_lang')}> + <View style={styles.list}> + { + langList.map(({ locale, name }) => <Item name={name} id={locale} key={locale} />) + } + </View> + </SubTitle> + ) +}) + +const styles = StyleSheet.create({ + list: { + flexDirection: 'row', + flexWrap: 'wrap', + }, +}) diff --git a/src/screens/Home/Views/Setting/Basic/ShareType.tsx b/src/screens/Home/Views/Setting/Basic/ShareType.tsx new file mode 100644 index 000000000..4b75e207c --- /dev/null +++ b/src/screens/Home/Views/Setting/Basic/ShareType.tsx @@ -0,0 +1,64 @@ +import React, { memo, useMemo } from 'react' + +import { StyleSheet, View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import CheckBox from '@/components/common/CheckBox' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { updateSetting } from '@/core/common' + +type ShareType = LX.AppSetting['common.shareType'] + +const setShareType = (type: ShareType) => { + updateSetting({ 'common.shareType': type }) +} + + +const useActive = (type: ShareType) => { + const shareType = useSettingValue('common.shareType') + const isActive = useMemo(() => shareType == type, [shareType, type]) + return isActive +} + +const Item = ({ id, name }: { + id: ShareType + name: string +}) => { + const isActive = useActive(id) + // const [toggleCheckBox, setToggleCheckBox] = useState(false) + return <CheckBox marginBottom={3} check={isActive} label={name} onChange={() => setShareType(id)} need /> +} + +export default memo(() => { + const t = useI18n() + const list = useMemo(() => { + return [ + { + id: 'system', + name: t('setting_basic_share_type_system'), + }, + { + id: 'clipboard', + name: t('setting_basic_share_type_clipboard'), + }, + ] as const + }, [t]) + + return ( + <SubTitle title={t('setting_basic_share_type')}> + <View style={styles.list}> + { + list.map(({ id, name }) => <Item name={name} id={id} key={id} />) + } + </View> + </SubTitle> + ) +}) + +const styles = StyleSheet.create({ + list: { + flexDirection: 'row', + flexWrap: 'wrap', + }, +}) diff --git a/src/screens/Home/Setting/Basic/Source.js b/src/screens/Home/Views/Setting/Basic/Source.tsx similarity index 52% rename from src/screens/Home/Setting/Basic/Source.js rename to src/screens/Home/Views/Setting/Basic/Source.tsx index 2f02605a8..675cf7e0a 100644 --- a/src/screens/Home/Setting/Basic/Source.js +++ b/src/screens/Home/Views/Setting/Basic/Source.tsx @@ -1,37 +1,47 @@ import React, { memo, useCallback, useMemo } from 'react' -import { StyleSheet, View, InteractionManager } from 'react-native' -import { useGetter, useDispatch } from '@/store' +import { View } from 'react-native' import SubTitle from '../components/SubTitle' -import { useTranslation } from '@/plugins/i18n' import CheckBox from '@/components/common/CheckBox' +import { createStyle } from '@/utils/tools' +import { setUserApi } from '@/core/apiSource' +import { useI18n } from '@/lang' +import apiSourceInfo from '@/utils/musicSdk/api-source-info' +import { useSettingValue } from '@/store/setting/hook' -const useActive = id => { - const activeLangId = useGetter('common', 'activeApiSourceId') +const apiSourceList = apiSourceInfo.map(api => ({ + id: api.id, + name: api.name, + disabled: api.disabled, +})) + +const useActive = (id: string) => { + const activeLangId = useSettingValue('common.apiSource') const isActive = useMemo(() => activeLangId == id, [activeLangId, id]) return isActive } -const Item = ({ id, name, change }) => { +const Item = ({ id, name, change }: { + id: string + name: string + change: (id: string) => void +}) => { const isActive = useActive(id) // const [toggleCheckBox, setToggleCheckBox] = useState(false) - return <CheckBox marginBottom={3} check={isActive} label={name} onChange={() => change(id)} need /> + return <CheckBox marginBottom={5} check={isActive} label={name} onChange={() => change(id)} need /> } export default memo(() => { - const { t } = useTranslation() - const setApiSource = useDispatch('common', 'setApiSource') - const apiSourceList = useGetter('common', 'apiSourceList') + const t = useI18n() const list = useMemo(() => apiSourceList.map(s => ({ + // @ts-expect-error name: t(`setting_basic_source_${s.id}`) || s.name, id: s.id, - })), [apiSourceList, t]) - const setApiSourceId = useCallback((id) => { - InteractionManager.runAfterInteractions(() => { - setApiSource(id) - }) - }, [setApiSource]) + })), [t]) + const setApiSourceId = useCallback((id: string) => { + setUserApi(id) + }, []) return ( <SubTitle title={t('setting_basic_source')}> @@ -44,7 +54,7 @@ export default memo(() => { ) }) -const styles = StyleSheet.create({ +const styles = createStyle({ list: { flexGrow: 0, flexShrink: 1, diff --git a/src/screens/Home/Views/Setting/Basic/SourceName.tsx b/src/screens/Home/Views/Setting/Basic/SourceName.tsx new file mode 100644 index 000000000..0a9c982bb --- /dev/null +++ b/src/screens/Home/Views/Setting/Basic/SourceName.tsx @@ -0,0 +1,64 @@ +import React, { memo, useMemo } from 'react' + +import { StyleSheet, View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import CheckBox from '@/components/common/CheckBox' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { updateSetting } from '@/core/common' + +type SourceNameType = LX.AppSetting['common.sourceNameType'] + +const setSourceNameType = (type: SourceNameType) => { + updateSetting({ 'common.sourceNameType': type }) +} + + +const useActive = (type: SourceNameType) => { + const sourceNameType = useSettingValue('common.sourceNameType') + const isActive = useMemo(() => sourceNameType == type, [sourceNameType, type]) + return isActive +} + +const Item = ({ id, name }: { + id: SourceNameType + name: string +}) => { + const isActive = useActive(id) + // const [toggleCheckBox, setToggleCheckBox] = useState(false) + return <CheckBox marginBottom={3} check={isActive} label={name} onChange={() => setSourceNameType(id)} need /> +} + +export default memo(() => { + const t = useI18n() + const list = useMemo(() => { + return [ + { + id: 'real', + name: t('setting_basic_sourcename_real'), + }, + { + id: 'alias', + name: t('setting_basic_sourcename_alias'), + }, + ] as const + }, [t]) + + return ( + <SubTitle title={t('setting_basic_sourcename')}> + <View style={styles.list}> + { + list.map(({ id, name }) => <Item name={name} id={id} key={id} />) + } + </View> + </SubTitle> + ) +}) + +const styles = StyleSheet.create({ + list: { + flexDirection: 'row', + flexWrap: 'wrap', + }, +}) diff --git a/src/screens/Home/Views/Setting/Basic/Theme.tsx b/src/screens/Home/Views/Setting/Basic/Theme.tsx new file mode 100644 index 000000000..3ce196340 --- /dev/null +++ b/src/screens/Home/Views/Setting/Basic/Theme.tsx @@ -0,0 +1,123 @@ +import React, { memo, useCallback, useEffect, useMemo, useState } from 'react' +import { View, ImageBackground, TouchableOpacity, InteractionManager, ImageSourcePropType } from 'react-native' +import { setTheme } from '@/core/theme' +import { useI18n } from '@/lang' +import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' + +import SubTitle from '../components/SubTitle' +import { BG_IMAGES, getAllThemes, LocalTheme } from '@/theme/themes' +import Text from '@/components/common/Text' +import { createStyle } from '@/utils/tools' +import { scaleSizeH } from '@/utils/pixelRatio' + +const useActive = (id: string) => { + const activeThemeId = useSettingValue('theme.id') + const isActive = useMemo(() => activeThemeId == id, [activeThemeId, id]) + return isActive +} + +const ThemeItem = ({ id, name, color, image, setTheme }: { + id: string + name: string + color: string + image?: ImageSourcePropType + setTheme: (id: string) => void +}) => { + const theme = useTheme() + const isActive = useActive(id) + + return ( + <TouchableOpacity style={{ ...styles.item, width: scaleSizeH(ITEM_HEIGHT) }} activeOpacity={0.5} onPress={() => setTheme(id)}> + <View style={{ ...styles.colorContent, width: scaleSizeH(COLOR_ITEM_HEIGHT), borderColor: isActive ? color : 'transparent' }}> + { + image + ? <ImageBackground style={{ ...styles.imageContent, width: scaleSizeH(IMAGE_HEIGHT), backgroundColor: color }} + source={image} borderRadius={4} /> + : <View style={{ ...styles.imageContent, width: scaleSizeH(IMAGE_HEIGHT), backgroundColor: color }}></View> + } + </View> + <Text style={styles.name} size={12} color={isActive ? color : theme['c-font']} numberOfLines={1}>{name}</Text> + </TouchableOpacity> + ) +} + +interface ThemeInfo { + themes: Readonly<LocalTheme[]> + userThemes: LX.Theme[] + dataPath: string +} +const initInfo: ThemeInfo = { themes: [], userThemes: [], dataPath: '' } +export default memo(() => { + const t = useI18n() + const [themeInfo, setThemeInfo] = useState(initInfo) + const setThemeId = useCallback((id: string) => { + void InteractionManager.runAfterInteractions(() => { + setTheme(id) + }) + }, []) + + useEffect(() => { + void getAllThemes().then(setThemeInfo) + }, []) + + return ( + <SubTitle title={t('setting_basic_theme')}> + <View style={styles.list}> + { + themeInfo.themes.map(({ id, config }) => { + return <ThemeItem + key={id} + color={config.themeColors['c-theme']} + image={config.extInfo['bg-image'] ? BG_IMAGES[config.extInfo['bg-image']] : undefined} + id={id} + name={t(`theme_${id}`)} + setTheme={setThemeId} /> + }) + } + { + themeInfo.userThemes.map(({ id, name, config }) => { + return <ThemeItem + key={id} + color={config.themeColors['c-theme']} + // image={undefined} + id={id} + name={name} + setTheme={setThemeId} /> + }) + } + </View> + </SubTitle> + ) +}) + +const ITEM_HEIGHT = 56 +const COLOR_ITEM_HEIGHT = 34 +const IMAGE_HEIGHT = 27 +const styles = createStyle({ + list: { + flexDirection: 'row', + flexWrap: 'wrap', + }, + item: { + marginRight: 15, + alignItems: 'center', + marginTop: 5, + // backgroundColor: 'rgba(0,0,0,0.2)', + }, + colorContent: { + height: COLOR_ITEM_HEIGHT, + borderRadius: 4, + borderWidth: 1.6, + alignItems: 'center', + justifyContent: 'center', + }, + imageContent: { + height: IMAGE_HEIGHT, + borderRadius: 4, + // elevation: 1, + }, + name: { + marginTop: 2, + }, +}) diff --git a/src/screens/Home/Setting/Basic/index.js b/src/screens/Home/Views/Setting/Basic/index.tsx similarity index 68% rename from src/screens/Home/Setting/Basic/index.js rename to src/screens/Home/Views/Setting/Basic/index.tsx index 8b0a3ef60..8fa5a77e4 100644 --- a/src/screens/Home/Setting/Basic/index.js +++ b/src/screens/Home/Views/Setting/Basic/index.tsx @@ -5,14 +5,16 @@ import Theme from './Theme' import Source from './Source' import SourceName from './SourceName' import Language from './Language' +import FontSize from './FontSize' import ShareType from './ShareType' import IsAutoTheme from './IsAutoTheme' import IsStartupAutoPlay from './IsStartupAutoPlay' -import IsAutoHidePlayBar from './IsAutoHidePlayBar' -import { useTranslation } from '@/plugins/i18n' +import DrawerLayoutPosition from './DrawerLayoutPosition' +// import IsAutoHidePlayBar from './IsAutoHidePlayBar' +import { useI18n } from '@/lang/i18n' export default memo(() => { - const { t } = useTranslation() + const t = useI18n() return ( @@ -20,11 +22,15 @@ export default memo(() => { <Theme /> <IsAutoTheme /> <IsStartupAutoPlay /> - <IsAutoHidePlayBar /> <Source /> - <Language /> <SourceName /> + <DrawerLayoutPosition /> + <Language /> + <FontSize /> <ShareType /> + {/* + <IsAutoHidePlayBar /> + */} </Section> ) }) diff --git a/src/screens/Home/Views/Setting/List/AddMusicLocationType.tsx b/src/screens/Home/Views/Setting/List/AddMusicLocationType.tsx new file mode 100644 index 000000000..db1a22537 --- /dev/null +++ b/src/screens/Home/Views/Setting/List/AddMusicLocationType.tsx @@ -0,0 +1,49 @@ +import React, { memo, useMemo } from 'react' + +import { StyleSheet, View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import CheckBox from '@/components/common/CheckBox' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { updateSetting } from '@/core/common' + +const setAddMusicLocationType = (type: LX.AddMusicLocationType) => { + updateSetting({ 'list.addMusicLocationType': type }) +} + +const useActive = (id: LX.AddMusicLocationType) => { + const addMusicLocationType = useSettingValue('list.addMusicLocationType') + const isActive = useMemo(() => addMusicLocationType == id, [addMusicLocationType, id]) + return isActive +} + +const Item = ({ id, name }: { + id: LX.AddMusicLocationType + name: string +}) => { + const isActive = useActive(id) + // const [toggleCheckBox, setToggleCheckBox] = useState(false) + return <CheckBox marginRight={8} check={isActive} label={name} onChange={() => setAddMusicLocationType(id)} need /> +} + + +export default memo(() => { + const t = useI18n() + + return ( + <SubTitle title={t('setting_list_add_music_location_type')}> + <View style={styles.list}> + <Item id="top" name={t('setting_list_add_music_location_type_top')} /> + <Item id="bottom" name={t('setting_list_add_music_location_type_bottom')} /> + </View> + </SubTitle> + ) +}) + +const styles = StyleSheet.create({ + list: { + flexDirection: 'row', + flexWrap: 'wrap', + }, +}) diff --git a/src/screens/Home/Views/Setting/List/IsClickPlayList.tsx b/src/screens/Home/Views/Setting/List/IsClickPlayList.tsx new file mode 100644 index 000000000..9f4d6f67a --- /dev/null +++ b/src/screens/Home/Views/Setting/List/IsClickPlayList.tsx @@ -0,0 +1,32 @@ +import { updateSetting } from '@/core/common' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' + + +import CheckBoxItem from '../components/CheckBoxItem' + +export default memo(() => { + const t = useI18n() + const isClickPlayList = useSettingValue('list.isClickPlayList') + const setClickPlayList = (isClickPlayList: boolean) => { + updateSetting({ 'list.isClickPlayList': isClickPlayList }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isClickPlayList} onChange={setClickPlayList} label={t('setting_list_click_action')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + marginBottom: 15, + }, +}) + diff --git a/src/screens/Home/Setting/List/index.js b/src/screens/Home/Views/Setting/List/index.tsx similarity index 81% rename from src/screens/Home/Setting/List/index.js rename to src/screens/Home/Views/Setting/List/index.tsx index 4d87569a8..60142a999 100644 --- a/src/screens/Home/Setting/List/index.js +++ b/src/screens/Home/Views/Setting/List/index.tsx @@ -3,10 +3,11 @@ import React, { memo } from 'react' import Section from '../components/Section' import AddMusicLocationType from './AddMusicLocationType' import IsClickPlayList from './IsClickPlayList' -import { useTranslation } from '@/plugins/i18n' + +import { useI18n } from '@/lang' export default memo(() => { - const { t } = useTranslation() + const t = useI18n() return ( <Section title={t('setting_list')}> diff --git a/src/screens/Home/Views/Setting/LyricDesktop/IsLockLyric.tsx b/src/screens/Home/Views/Setting/LyricDesktop/IsLockLyric.tsx new file mode 100644 index 000000000..0ef026274 --- /dev/null +++ b/src/screens/Home/Views/Setting/LyricDesktop/IsLockLyric.tsx @@ -0,0 +1,33 @@ +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' + + +import CheckBoxItem from '../components/CheckBoxItem' +import { toggleDesktopLyricLock } from '@/core/desktopLyric' +import { updateSetting } from '@/core/common' + +export default memo(() => { + const t = useI18n() + const isLock = useSettingValue('desktopLyric.isLock') + const setLock = (isLock: boolean) => { + void toggleDesktopLyricLock(isLock).then(() => { + updateSetting({ 'desktopLyric.isLock': isLock }) + }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isLock} onChange={setLock} label={t('setting_lyric_desktop_lock')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + }, +}) diff --git a/src/screens/Home/Views/Setting/LyricDesktop/IsShowLyric.tsx b/src/screens/Home/Views/Setting/LyricDesktop/IsShowLyric.tsx new file mode 100644 index 000000000..706784a41 --- /dev/null +++ b/src/screens/Home/Views/Setting/LyricDesktop/IsShowLyric.tsx @@ -0,0 +1,63 @@ +import React, { memo, useRef } from 'react' +import { View } from 'react-native' + +import ConfirmAlert, { type ConfirmAlertType } from '@/components/common/ConfirmAlert' +import CheckBoxItem from '../components/CheckBoxItem' + +import { createStyle, toast } from '@/utils/tools' + +import { useI18n } from '@/lang' +import { useSettingValue } from '@/store/setting/hook' +import { checkDesktopLyricOverlayPermission, hideDesktopLyric, openDesktopLyricOverlayPermissionActivity, showDesktopLyric } from '@/core/desktopLyric' +import { updateSetting } from '@/core/common' + +export default memo(() => { + const t = useI18n() + const isEnable = useSettingValue('desktopLyric.enable') + // const setIsShowDesktopLyric = useDispatch('common', 'setIsShowDesktopLyric') + const confirmAlertRef = useRef<ConfirmAlertType>(null) + + const handleChangeEnableDesktopLyric = async(isEnable: boolean) => { + if (isEnable) { + try { + await checkDesktopLyricOverlayPermission() + await showDesktopLyric() + } catch (err) { + console.log(err) + confirmAlertRef.current?.setVisible(true) + // return false + } + } else await hideDesktopLyric() + // return true + updateSetting({ 'desktopLyric.enable': isEnable }) + } + + const handleTipsCancel = () => { + toast(t('disagree_tip'), 'long') + } + const handleTipsConfirm = () => { + confirmAlertRef.current?.setVisible(false) + void openDesktopLyricOverlayPermissionActivity() + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isEnable} onChange={(enable) => { void handleChangeEnableDesktopLyric(enable) }} label={t('setting_lyric_desktop_enable')} /> + <ConfirmAlert + ref={confirmAlertRef} + onCancel={handleTipsCancel} + onConfirm={handleTipsConfirm} + bgHide={false} + closeBtn={false} + cancelText={t('disagree')} + confirmText={t('agree_go')} + text={t('setting_lyric_dektop_permission_tip')} /> + </View> + ) +}) + +const styles = createStyle({ + content: { + marginTop: 5, + }, +}) diff --git a/src/screens/Home/Views/Setting/LyricDesktop/IsShowToggleAnima.tsx b/src/screens/Home/Views/Setting/LyricDesktop/IsShowToggleAnima.tsx new file mode 100644 index 000000000..065e63291 --- /dev/null +++ b/src/screens/Home/Views/Setting/LyricDesktop/IsShowToggleAnima.tsx @@ -0,0 +1,33 @@ +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' + + +import CheckBoxItem from '../components/CheckBoxItem' +import { setShowDesktopLyricToggleAnima } from '@/core/desktopLyric' +import { updateSetting } from '@/core/common' + +export default memo(() => { + const t = useI18n() + const showToggleAnima = useSettingValue('desktopLyric.showToggleAnima') + const update = (showToggleAnima: boolean) => { + void setShowDesktopLyricToggleAnima(showToggleAnima).then(() => { + updateSetting({ 'desktopLyric.showToggleAnima': showToggleAnima }) + }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={showToggleAnima} onChange={update} label={t('setting_lyric_desktop_toggle_anima')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + }, +}) diff --git a/src/screens/Home/Views/Setting/LyricDesktop/IsSingleLine.tsx b/src/screens/Home/Views/Setting/LyricDesktop/IsSingleLine.tsx new file mode 100644 index 000000000..ce53e63a9 --- /dev/null +++ b/src/screens/Home/Views/Setting/LyricDesktop/IsSingleLine.tsx @@ -0,0 +1,34 @@ +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' + + +import CheckBoxItem from '../components/CheckBoxItem' +import { setDesktopLyricSingleLine } from '@/core/desktopLyric' +import { updateSetting } from '@/core/common' + +export default memo(() => { + const t = useI18n() + const isSingleLine = useSettingValue('desktopLyric.isSingleLine') + const update = (isSingleLine: boolean) => { + void setDesktopLyricSingleLine(isSingleLine).then(() => { + updateSetting({ 'desktopLyric.isSingleLine': isSingleLine }) + }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isSingleLine} onChange={update} label={t('setting_lyric_desktop_single_line')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + marginBottom: 15, + }, +}) diff --git a/src/screens/Home/Views/Setting/LyricDesktop/MaxLineNum.tsx b/src/screens/Home/Views/Setting/LyricDesktop/MaxLineNum.tsx new file mode 100644 index 000000000..a336f714f --- /dev/null +++ b/src/screens/Home/Views/Setting/LyricDesktop/MaxLineNum.tsx @@ -0,0 +1,62 @@ +import React, { memo, useCallback, useState } from 'react' +import { View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import Slider, { type SliderProps } from '../components/Slider' +import { useI18n } from '@/lang' +import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' +import { setDesktopLyricMaxLineNum } from '@/core/desktopLyric' +import { updateSetting } from '@/core/common' + + +export default memo(() => { + const t = useI18n() + const maxLineNum = useSettingValue('desktopLyric.maxLineNum') + const theme = useTheme() + const [sliderSize, setSliderSize] = useState(maxLineNum) + const [isSliding, setSliding] = useState(false) + const handleSlidingStart = useCallback<NonNullable<SliderProps['onSlidingStart']>>(() => { + setSliding(true) + }, []) + const handleValueChange = useCallback<NonNullable<SliderProps['onValueChange']>>(value => { + setSliderSize(value) + }, []) + const handleSlidingComplete = useCallback<NonNullable<SliderProps['onSlidingComplete']>>(value => { + if (maxLineNum == value) return + void setDesktopLyricMaxLineNum(value).then(() => { + updateSetting({ 'desktopLyric.maxLineNum': value }) + }).finally(() => { + setSliding(false) + }) + }, [maxLineNum]) + + return ( + <SubTitle title={t('setting_lyric_desktop_maxlineNum')}> + <View style={styles.content}> + <Text style={{ color: theme['c-primary-font'] }}>{isSliding ? sliderSize : maxLineNum}</Text> + <Slider + minimumValue={1} + maximumValue={8} + onSlidingComplete={handleSlidingComplete} + onValueChange={handleValueChange} + onSlidingStart={handleSlidingStart} + step={1} + value={maxLineNum} + /> + </View> + </SubTitle> + ) +}) + +const styles = createStyle({ + content: { + flexGrow: 0, + flexShrink: 1, + flexDirection: 'row', + flexWrap: 'wrap', + alignItems: 'center', + }, +}) diff --git a/src/screens/Home/Views/Setting/LyricDesktop/TextOpacity.tsx b/src/screens/Home/Views/Setting/LyricDesktop/TextOpacity.tsx new file mode 100644 index 000000000..f795f4d31 --- /dev/null +++ b/src/screens/Home/Views/Setting/LyricDesktop/TextOpacity.tsx @@ -0,0 +1,63 @@ +import React, { memo, useCallback, useState } from 'react' +import { View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import Slider, { type SliderProps } from '../components/Slider' +import { useI18n } from '@/lang' +import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' +import { setDesktopLyricAlpha } from '@/core/desktopLyric' +import { updateSetting } from '@/core/common' + + +export default memo(() => { + const t = useI18n() + const opacity = useSettingValue('desktopLyric.style.opacity') + const theme = useTheme() + const [sliderSize, setSliderSize] = useState(opacity) + const [isSliding, setSliding] = useState(false) + const handleSlidingStart = useCallback<NonNullable<SliderProps['onSlidingStart']>>(() => { + setSliding(true) + }, []) + const handleValueChange = useCallback<NonNullable<SliderProps['onValueChange']>>(value => { + setSliderSize(value) + }, []) + const handleSlidingComplete = useCallback<NonNullable<SliderProps['onSlidingComplete']>>(value => { + if (opacity == value) return + void setDesktopLyricAlpha(value).then(() => { + updateSetting({ 'desktopLyric.style.opacity': value }) + }).finally(() => { + setSliding(false) + }) + }, [opacity]) + + return ( + <SubTitle title={t('setting_lyric_desktop_text_opacity')}> + <View style={styles.content}> + <Text style={{ color: theme['c-primary-font'] }}>{isSliding ? sliderSize : opacity}</Text> + <Slider + minimumValue={10} + maximumValue={100} + onSlidingComplete={handleSlidingComplete} + onValueChange={handleValueChange} + onSlidingStart={handleSlidingStart} + step={2} + value={opacity} + /> + </View> + </SubTitle> + ) +}) + +const styles = createStyle({ + content: { + flexGrow: 0, + flexShrink: 1, + flexDirection: 'row', + flexWrap: 'wrap', + alignItems: 'center', + }, +}) + diff --git a/src/screens/Home/Views/Setting/LyricDesktop/TextPositionX.tsx b/src/screens/Home/Views/Setting/LyricDesktop/TextPositionX.tsx new file mode 100644 index 000000000..68b2046c5 --- /dev/null +++ b/src/screens/Home/Views/Setting/LyricDesktop/TextPositionX.tsx @@ -0,0 +1,67 @@ +import React, { memo, useMemo } from 'react' + +import { View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import CheckBox from '@/components/common/CheckBox' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { setDesktopLyricTextPosition } from '@/core/desktopLyric' +import { createStyle } from '@/utils/tools' +import { updateSetting } from '@/core/common' + +type X_TYPE = LX.AppSetting['desktopLyric.textPosition.x'] + +const X_LIST = [ + 'left', + 'center', + 'right', +] as const + +const useActive = (id: X_TYPE) => { + const x = useSettingValue('desktopLyric.textPosition.x') + const isActive = useMemo(() => x == id, [x, id]) + return isActive +} + +const Item = ({ id, name, change }: { + id: X_TYPE + name: string + change: (id: X_TYPE) => void +}) => { + const isActive = useActive(id) + // const [toggleCheckBox, setToggleCheckBox] = useState(false) + return <CheckBox marginBottom={3} check={isActive} label={name} onChange={() => { change(id) }} need /> +} + +export default memo(() => { + const t = useI18n() + const list = useMemo(() => { + return X_LIST.map(id => ({ id, name: t(`setting_lyric_desktop_text_x_${id}`) })) + }, [t]) + + const setPosition = (id: X_TYPE) => { + void setDesktopLyricTextPosition(id, null).then(() => { + updateSetting({ 'desktopLyric.textPosition.x': id }) + }) + } + + return ( + <SubTitle title={t('setting_lyric_desktop_text_x')}> + <View style={styles.list}> + { + list.map(({ id, name }) => <Item name={name} id={id} key={id} change={setPosition} />) + } + </View> + </SubTitle> + ) +}) + +const styles = createStyle({ + list: { + flexGrow: 0, + flexShrink: 1, + flexDirection: 'row', + flexWrap: 'wrap', + }, +}) diff --git a/src/screens/Home/Views/Setting/LyricDesktop/TextPositionY.tsx b/src/screens/Home/Views/Setting/LyricDesktop/TextPositionY.tsx new file mode 100644 index 000000000..d9cee28d6 --- /dev/null +++ b/src/screens/Home/Views/Setting/LyricDesktop/TextPositionY.tsx @@ -0,0 +1,65 @@ +import React, { memo, useMemo } from 'react' +import { View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import CheckBox from '@/components/common/CheckBox' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { setDesktopLyricTextPosition } from '@/core/desktopLyric' +import { createStyle } from '@/utils/tools' +import { updateSetting } from '@/core/common' + +type Y_TYPE = LX.AppSetting['desktopLyric.textPosition.y'] + +const Y_LIST = [ + 'top', + 'center', + 'bottom', +] as const + +const useActive = (id: Y_TYPE) => { + const y = useSettingValue('desktopLyric.textPosition.y') + const isActive = useMemo(() => y == id, [y, id]) + return isActive +} + +const Item = ({ id, name, change }: { + id: Y_TYPE + name: string + change: (id: Y_TYPE) => void +}) => { + const isActive = useActive(id) + return <CheckBox marginBottom={3} check={isActive} label={name} onChange={() => { change(id) }} need /> +} + +export default memo(() => { + const t = useI18n() + const list = useMemo(() => { + return Y_LIST.map(id => ({ id, name: t(`setting_lyric_desktop_text_y_${id}`) })) + }, [t]) + + const setPosition = (id: Y_TYPE) => { + void setDesktopLyricTextPosition(null, id).then(() => { + updateSetting({ 'desktopLyric.textPosition.y': id }) + }) + } + + return ( + <SubTitle title={t('setting_lyric_desktop_text_y')}> + <View style={styles.list}> + { + list.map(({ id, name }) => <Item name={name} id={id} key={id} change={setPosition} />) + } + </View> + </SubTitle> + ) +}) + +const styles = createStyle({ + list: { + flexGrow: 0, + flexShrink: 1, + flexDirection: 'row', + flexWrap: 'wrap', + }, +}) diff --git a/src/screens/Home/Views/Setting/LyricDesktop/TextSize.tsx b/src/screens/Home/Views/Setting/LyricDesktop/TextSize.tsx new file mode 100644 index 000000000..ce2e269ea --- /dev/null +++ b/src/screens/Home/Views/Setting/LyricDesktop/TextSize.tsx @@ -0,0 +1,62 @@ +import React, { memo, useCallback, useState } from 'react' +import { View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import Slider, { type SliderProps } from '../components/Slider' +import { useI18n } from '@/lang' +import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' +import { setDesktopLyricTextSize } from '@/core/desktopLyric' +import { updateSetting } from '@/core/common' + + +export default memo(() => { + const t = useI18n() + const fontSize = useSettingValue('desktopLyric.style.fontSize') + const theme = useTheme() + const [sliderSize, setSliderSize] = useState(fontSize) + const [isSliding, setSliding] = useState(false) + const handleSlidingStart = useCallback<NonNullable<SliderProps['onSlidingStart']>>(() => { + setSliding(true) + }, []) + const handleValueChange = useCallback<NonNullable<SliderProps['onValueChange']>>(value => { + setSliderSize(value) + }, []) + const handleSlidingComplete = useCallback<NonNullable<SliderProps['onSlidingComplete']>>(value => { + if (fontSize == value) return + void setDesktopLyricTextSize(value).then(() => { + updateSetting({ 'desktopLyric.style.fontSize': value }) + }).finally(() => { + setSliding(false) + }) + }, [fontSize]) + + return ( + <SubTitle title={t('setting_lyric_desktop_text_size')}> + <View style={styles.content}> + <Text style={{ color: theme['c-primary-font'] }}>{isSliding ? sliderSize : fontSize}</Text> + <Slider + minimumValue={100} + maximumValue={500} + onSlidingComplete={handleSlidingComplete} + onValueChange={handleValueChange} + onSlidingStart={handleSlidingStart} + step={2} + value={fontSize} + /> + </View> + </SubTitle> + ) +}) + +const styles = createStyle({ + content: { + flexGrow: 0, + flexShrink: 1, + flexDirection: 'row', + flexWrap: 'wrap', + alignItems: 'center', + }, +}) diff --git a/src/screens/Home/Setting/LyricDesktop/Theme.js b/src/screens/Home/Views/Setting/LyricDesktop/Theme.tsx similarity index 50% rename from src/screens/Home/Setting/LyricDesktop/Theme.js rename to src/screens/Home/Views/Setting/LyricDesktop/Theme.tsx index a04d25d20..2900a5ccd 100644 --- a/src/screens/Home/Setting/LyricDesktop/Theme.js +++ b/src/screens/Home/Views/Setting/LyricDesktop/Theme.tsx @@ -1,24 +1,31 @@ -import React, { memo, useMemo } from 'react' - +import { updateSetting } from '@/core/common' +import { setDesktopLyricColor } from '@/core/desktopLyric' +import { useI18n } from '@/lang' +import React, { memo } from 'react' import { StyleSheet, View, TouchableOpacity } from 'react-native' -import { useGetter, useDispatch } from '@/store' import SubTitle from '../components/SubTitle' -import { useTranslation } from '@/plugins/i18n' -import { themes } from '@/utils/lyricDesktop' -const useActive = id => { - const themeDesktopLyric = useGetter('common', 'themeDesktopLyric') - const isActive = useMemo(() => themeDesktopLyric == id, [themeDesktopLyric, id]) - return isActive -} +const themes = [ + '#07c556', + '#fffa12', + '#19b5fe', + '#ff1222', + '#f1828d', + '#c851d4', + '#ffad12', + '#bdc3c7', + '#333333', + '#ffffff', +] as const -const ThemeItem = ({ id, color, setTheme }) => { - const theme = useGetter('common', 'theme') - const isActive = useActive(id) +const ThemeItem = ({ color, change }: { + color: string + change: (color: string) => void +}) => { return ( - <TouchableOpacity style={styles.item} activeOpacity={0.5} onPress={() => setTheme(id)}> - <View style={{ ...styles.colorContent, backgroundColor: theme.primary, borderColor: isActive ? color : 'transparent' }}> + <TouchableOpacity style={styles.item} activeOpacity={0.5} onPress={() => { change(color) }}> + <View style={styles.colorContent}> <View style={{ ...styles.image, backgroundColor: color }}></View> </View> </TouchableOpacity> @@ -26,14 +33,20 @@ const ThemeItem = ({ id, color, setTheme }) => { } export default memo(() => { - const { t } = useTranslation() - const setThemeDesktopLyric = useDispatch('common', 'setThemeDesktopLyric') + const t = useI18n() + + const setThemeDesktopLyric = (color: string) => { + const shadowColor = 'rgba(0,0,0,0.6)' + void setDesktopLyricColor(null, color, shadowColor).then(() => { + updateSetting({ 'desktopLyric.style.lyricPlayedColor': color, 'desktopLyric.style.lyricShadowColor': shadowColor }) + }) + } return ( <SubTitle title={t('setting_lyric_desktop_theme')}> <View style={styles.list}> { - themes.map(({ id, value }) => <ThemeItem key={id} color={value} id={id} setTheme={setThemeDesktopLyric} />) + themes.map(c => <ThemeItem key={c} color={c} change={setThemeDesktopLyric} />) } </View> </SubTitle> @@ -56,7 +69,7 @@ const styles = StyleSheet.create({ width: 26, height: 26, borderRadius: 4, - borderWidth: 1.6, + // borderWidth: 1.6, alignItems: 'center', justifyContent: 'center', }, diff --git a/src/screens/Home/Views/Setting/LyricDesktop/ViewWidth.tsx b/src/screens/Home/Views/Setting/LyricDesktop/ViewWidth.tsx new file mode 100644 index 000000000..3d57b2794 --- /dev/null +++ b/src/screens/Home/Views/Setting/LyricDesktop/ViewWidth.tsx @@ -0,0 +1,63 @@ +import React, { memo, useCallback, useState } from 'react' +import { View } from 'react-native' + +import SubTitle from '../components/SubTitle' +import Slider, { type SliderProps } from '../components/Slider' +import { useI18n } from '@/lang' +import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' +import { setDesktopLyricWidth } from '@/core/desktopLyric' +import { updateSetting } from '@/core/common' + + +export default memo(() => { + const t = useI18n() + const width = useSettingValue('desktopLyric.width') + const theme = useTheme() + const [sliderSize, setSliderSize] = useState(width) + const [isSliding, setSliding] = useState(false) + const handleSlidingStart = useCallback<NonNullable<SliderProps['onSlidingStart']>>(() => { + setSliding(true) + }, []) + const handleValueChange = useCallback<NonNullable<SliderProps['onValueChange']>>(value => { + setSliderSize(value) + }, []) + const handleSlidingComplete = useCallback<NonNullable<SliderProps['onSlidingComplete']>>(value => { + if (width == value) return + void setDesktopLyricWidth(value).then(() => { + updateSetting({ 'desktopLyric.width': value }) + }).finally(() => { + setSliding(false) + }) + }, [width]) + + return ( + <SubTitle title={t('setting_lyric_desktop_view_width')}> + <View style={styles.content}> + <Text style={{ color: theme['c-primary-font'] }}>{isSliding ? sliderSize : width}</Text> + <Slider + minimumValue={10} + maximumValue={100} + onSlidingComplete={handleSlidingComplete} + onValueChange={handleValueChange} + onSlidingStart={handleSlidingStart} + step={1} + value={width} + /> + </View> + </SubTitle> + ) +}) + +const styles = createStyle({ + content: { + flexGrow: 0, + flexShrink: 1, + flexDirection: 'row', + flexWrap: 'wrap', + alignItems: 'center', + }, +}) + diff --git a/src/screens/Home/Setting/LyricDesktop/index.js b/src/screens/Home/Views/Setting/LyricDesktop/index.tsx similarity index 89% rename from src/screens/Home/Setting/LyricDesktop/index.js rename to src/screens/Home/Views/Setting/LyricDesktop/index.tsx index b045b4ec5..38af20980 100644 --- a/src/screens/Home/Setting/LyricDesktop/index.js +++ b/src/screens/Home/Views/Setting/LyricDesktop/index.tsx @@ -11,11 +11,12 @@ import MaxLineNum from './MaxLineNum' import TextOpacity from './TextOpacity' import TextPositionX from './TextPositionX' import TextPositionY from './TextPositionY' +import { useI18n } from '@/lang' import Theme from './Theme' -import { useTranslation } from '@/plugins/i18n' +// import { useTranslation } from '@/plugins/i18n' export default memo(() => { - const { t } = useTranslation() + const t = useI18n() return ( <Section title={t('setting_lyric_desktop')}> diff --git a/src/screens/Home/Setting/Other/Cache.js b/src/screens/Home/Views/Setting/Other/Cache.tsx similarity index 67% rename from src/screens/Home/Setting/Other/Cache.js rename to src/screens/Home/Views/Setting/Other/Cache.tsx index 205803f0d..afa2c8b93 100644 --- a/src/screens/Home/Setting/Other/Cache.js +++ b/src/screens/Home/Views/Setting/Other/Cache.tsx @@ -1,42 +1,42 @@ import React, { memo, useCallback, useState, useEffect } from 'react' -import { StyleSheet, View, Text, InteractionManager } from 'react-native' +import { StyleSheet, View, InteractionManager } from 'react-native' -import { useGetter, useDispatch } from '@/store' // import { gzip, ungzip } from 'pako' import SubTitle from '../components/SubTitle' import Button from '../components/Button' -import { useTranslation } from '@/plugins/i18n' import { toast, resetNotificationPermissionCheck, confirmDialog } from '@/utils/tools' -import { getAppCacheSize, clearAppCache } from '@/utils/cache' +import { getAppCacheSize, clearAppCache } from '@/utils/nativeModules/cache' import { sizeFormate } from '@/utils' +import { useI18n } from '@/lang' +import Text from '@/components/common/Text' export default memo(() => { - const { t } = useTranslation() + const t = useI18n() const [cleaning, setCleaning] = useState(false) - const [cacheSize, setCacheSize] = useState(null) + const [cacheSize, setCacheSize] = useState<string | null>(null) // const setting = useGetter('common', 'setting') - const theme = useGetter('common', 'theme') - const clearCache = useDispatch('list', 'clearCache') + // TODO clear list cache + // const clearCache = useDispatch('list', 'clearCache') const handleGetAppCacheSize = useCallback(() => { - getAppCacheSize().then(size => { + void getAppCacheSize().then(size => { setCacheSize(sizeFormate(size)) }) }, []) const handleCleanCache = useCallback(() => { if (cacheSize == null) return - confirmDialog({ + void confirmDialog({ message: t('confirm_tip'), confirmButtonText: t('list_remove_tip_button'), }).then(confirm => { if (!confirm) return setCleaning(true) - InteractionManager.runAfterInteractions(() => { + void InteractionManager.runAfterInteractions(() => { Promise.all([ clearAppCache(), - clearCache(), + // clearCache(), resetNotificationPermissionCheck(), ]).then(() => { toast(t('setting_other_cache_clear_success_tip')) @@ -46,7 +46,7 @@ export default memo(() => { }) }) }) - }, [cacheSize, clearCache, handleGetAppCacheSize, t]) + }, [cacheSize, handleGetAppCacheSize, t]) useEffect(() => { @@ -57,7 +57,7 @@ export default memo(() => { <> <SubTitle title={t('setting_other_cache')}> <View style={styles.cacheSize}> - <Text style={{ color: theme.normal }}>{cacheSize == null ? t('setting_other_cache_getting') : t('setting_other_cache_size') + cacheSize}</Text> + <Text>{cacheSize == null ? t('setting_other_cache_getting') : t('setting_other_cache_size') + cacheSize}</Text> </View> <View style={styles.clearBtn}> <Button disabled={cleaning} onPress={handleCleanCache}>{t('setting_other_cache_clear_btn')}</Button> diff --git a/src/screens/Home/Setting/Other/Log.js b/src/screens/Home/Views/Setting/Other/Log.js similarity index 100% rename from src/screens/Home/Setting/Other/Log.js rename to src/screens/Home/Views/Setting/Other/Log.js diff --git a/src/screens/Home/Setting/Other/index.js b/src/screens/Home/Views/Setting/Other/index.tsx similarity index 71% rename from src/screens/Home/Setting/Other/index.js rename to src/screens/Home/Views/Setting/Other/index.tsx index b14e4fca4..10a657745 100644 --- a/src/screens/Home/Setting/Other/index.js +++ b/src/screens/Home/Views/Setting/Other/index.tsx @@ -2,17 +2,17 @@ import React, { memo } from 'react' import Section from '../components/Section' import Cache from './Cache' -import Log from './Log' +// import Log from './Log' // import MaxCache from './MaxCache' -import { useTranslation } from '@/plugins/i18n' +import { useI18n } from '@/lang' export default memo(() => { - const { t } = useTranslation() + const t = useI18n() return ( <Section title={t('setting_other')}> <Cache /> - <Log /> + {/* <Log /> */} {/* <MaxCache /> */} </Section> ) diff --git a/src/screens/Home/Views/Setting/Player/IsHandleAudioFocus.tsx b/src/screens/Home/Views/Setting/Player/IsHandleAudioFocus.tsx new file mode 100644 index 000000000..959328207 --- /dev/null +++ b/src/screens/Home/Views/Setting/Player/IsHandleAudioFocus.tsx @@ -0,0 +1,32 @@ +import { updateSetting } from '@/core/common' +import { useI18n } from '@/lang' +import { createStyle, toast } from '@/utils/tools' +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' + + +import CheckBoxItem from '../components/CheckBoxItem' + +export default memo(() => { + const t = useI18n() + const isHandleAudioFocus = useSettingValue('player.isHandleAudioFocus') + const setHandleAudioFocus = (isHandleAudioFocus: boolean) => { + updateSetting({ 'player.isHandleAudioFocus': isHandleAudioFocus }) + toast(t('setting_play_handle_audio_focus_tip')) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isHandleAudioFocus} onChange={setHandleAudioFocus} label={t('setting_play_handle_audio_focus')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + }, +}) + diff --git a/src/screens/Home/Views/Setting/Player/IsPlayHighQuality.tsx b/src/screens/Home/Views/Setting/Player/IsPlayHighQuality.tsx new file mode 100644 index 000000000..f85ce1941 --- /dev/null +++ b/src/screens/Home/Views/Setting/Player/IsPlayHighQuality.tsx @@ -0,0 +1,31 @@ +import { updateSetting } from '@/core/common' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' + + +import CheckBoxItem from '../components/CheckBoxItem' + +export default memo(() => { + const t = useI18n() + const isPlayHighQuality = useSettingValue('player.isPlayHighQuality') + const setPlayHighQuality = (isPlayHighQuality: boolean) => { + updateSetting({ 'player.isPlayHighQuality': isPlayHighQuality }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isPlayHighQuality} onChange={setPlayHighQuality} label={t('setting_play_quality')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + }, +}) + diff --git a/src/screens/Home/Views/Setting/Player/IsS2T.tsx b/src/screens/Home/Views/Setting/Player/IsS2T.tsx new file mode 100644 index 000000000..3a9358126 --- /dev/null +++ b/src/screens/Home/Views/Setting/Player/IsS2T.tsx @@ -0,0 +1,31 @@ +import { updateSetting } from '@/core/common' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' + + +import CheckBoxItem from '../components/CheckBoxItem' + +export default memo(() => { + const t = useI18n() + const isS2t = useSettingValue('player.isS2t') + const setS2T = (isS2t: boolean) => { + updateSetting({ 'player.isS2t': isS2t }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isS2t} onChange={setS2T} label={t('setting_play_s2t')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + }, +}) + diff --git a/src/screens/Home/Views/Setting/Player/IsSavePlayTime.tsx b/src/screens/Home/Views/Setting/Player/IsSavePlayTime.tsx new file mode 100644 index 000000000..a37325e43 --- /dev/null +++ b/src/screens/Home/Views/Setting/Player/IsSavePlayTime.tsx @@ -0,0 +1,30 @@ +import { updateSetting } from '@/core/common' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' + + +import CheckBoxItem from '../components/CheckBoxItem' + +export default memo(() => { + const t = useI18n() + const isSavePlayTime = useSettingValue('player.isSavePlayTime') + const setSavePlayTime = (isSavePlayTime: boolean) => { + updateSetting({ 'player.isSavePlayTime': isSavePlayTime }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isSavePlayTime} label={t('setting_player_save_play_time')} onChange={setSavePlayTime} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + }, +}) diff --git a/src/screens/Home/Views/Setting/Player/IsShowLyricRoma.tsx b/src/screens/Home/Views/Setting/Player/IsShowLyricRoma.tsx new file mode 100644 index 000000000..0bbb67ff6 --- /dev/null +++ b/src/screens/Home/Views/Setting/Player/IsShowLyricRoma.tsx @@ -0,0 +1,30 @@ +import { updateSetting } from '@/core/common' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' + + +import CheckBoxItem from '../components/CheckBoxItem' + +export default memo(() => { + const t = useI18n() + const isShowLyricRoma = useSettingValue('player.isShowLyricRoma') + const setShowLyricRoma = (isShowLyricRoma: boolean) => { + updateSetting({ 'player.isShowLyricRoma': isShowLyricRoma }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isShowLyricRoma} onChange={setShowLyricRoma} label={t('setting_play_show_roma')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + }, +}) diff --git a/src/screens/Home/Views/Setting/Player/IsShowLyricTranslation.tsx b/src/screens/Home/Views/Setting/Player/IsShowLyricTranslation.tsx new file mode 100644 index 000000000..709e66349 --- /dev/null +++ b/src/screens/Home/Views/Setting/Player/IsShowLyricTranslation.tsx @@ -0,0 +1,30 @@ +import { updateSetting } from '@/core/common' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' + + +import CheckBoxItem from '../components/CheckBoxItem' + +export default memo(() => { + const t = useI18n() + const isShowLyricTranslation = useSettingValue('player.isShowLyricTranslation') + const setShowLyricTranslation = (isShowLyricTranslation: boolean) => { + updateSetting({ 'player.isShowLyricTranslation': isShowLyricTranslation }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isShowLyricTranslation} onChange={setShowLyricTranslation} label={t('setting_play_show_translation')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + }, +}) diff --git a/src/screens/Home/Views/Setting/Player/IsShowNotificationImage.tsx b/src/screens/Home/Views/Setting/Player/IsShowNotificationImage.tsx new file mode 100644 index 000000000..6efda6f53 --- /dev/null +++ b/src/screens/Home/Views/Setting/Player/IsShowNotificationImage.tsx @@ -0,0 +1,31 @@ +import { updateSetting } from '@/core/common' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' + + +import CheckBoxItem from '../components/CheckBoxItem' + +export default memo(() => { + const t = useI18n() + const isShowNotificationImage = useSettingValue('player.isShowNotificationImage') + const setShowNotificationImage = (isShowNotificationImage: boolean) => { + updateSetting({ 'player.isShowNotificationImage': isShowNotificationImage }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isShowNotificationImage} onChange={setShowNotificationImage} label={t('setting_play_show_notification_image')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + }, +}) + diff --git a/src/screens/Home/Views/Setting/Player/MaxCache.tsx b/src/screens/Home/Views/Setting/Player/MaxCache.tsx new file mode 100644 index 000000000..1e76656bb --- /dev/null +++ b/src/screens/Home/Views/Setting/Player/MaxCache.tsx @@ -0,0 +1,53 @@ +import React, { memo, useMemo } from 'react' +import { View } from 'react-native' + +import InputItem, { InputItemProps } from '../components/InputItem' +import { createStyle, toast } from '@/utils/tools' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { updateSetting } from '@/core/common' + +const MAX_SIZE = 1024 * 1024 * 1024 +export default memo(() => { + const t = useI18n() + const cacheSize = useSettingValue('player.cacheSize') + const setCacheSize = (size: string) => { + updateSetting({ 'player.cacheSize': size }) + } + + const size = useMemo(() => { + let size: number | string = parseInt(cacheSize) + if (size == 0 || Number.isNaN(size)) size = '' + return size.toString() + }, [cacheSize]) + + const setSize: InputItemProps['onChanged'] = (value, callback) => { + let size: number | string = parseInt(value) + if (Number.isNaN(size) || size < 0) size = '' + else if (size > MAX_SIZE) size = MAX_SIZE + size = size.toString() + callback(size) + if (cacheSize == size) return + setCacheSize(size) + toast(t('setting_play_cache_size_save_tip')) + } + + return ( + <View style={styles.content} > + <InputItem + value={size} + label={t('setting_play_cache_size')} + onChanged={setSize} + keyboardType="number-pad" + placeholder={t('setting_play_cache_size_no_cache')} /> + </View> + ) +}) + +const styles = createStyle({ + content: { + marginTop: 10, + marginBottom: 15, + }, +}) + diff --git a/src/screens/Home/Views/Setting/Player/index.tsx b/src/screens/Home/Views/Setting/Player/index.tsx new file mode 100644 index 000000000..ed2f512d8 --- /dev/null +++ b/src/screens/Home/Views/Setting/Player/index.tsx @@ -0,0 +1,30 @@ +import React, { memo } from 'react' + +import Section from '../components/Section' +import IsSavePlayTime from './IsSavePlayTime' +import IsPlayHighQuality from './IsPlayHighQuality' +import IsHandleAudioFocus from './IsHandleAudioFocus' +import IsShowNotificationImage from './IsShowNotificationImage' +import IsShowLyricTranslation from './IsShowLyricTranslation' +import IsShowLyricRoma from './IsShowLyricRoma' +import IsS2T from './IsS2T' +import MaxCache from './MaxCache' +import { useI18n } from '@/lang' + + +export default memo(() => { + const t = useI18n() + + return ( + <Section title={t('setting_play')}> + <IsSavePlayTime /> + <IsPlayHighQuality /> + <IsHandleAudioFocus /> + <IsShowNotificationImage /> + <IsShowLyricTranslation /> + <IsShowLyricRoma /> + <IsS2T /> + <MaxCache /> + </Section> + ) +}) diff --git a/src/screens/Home/Views/Setting/Search/IsShowHistorySearch.tsx b/src/screens/Home/Views/Setting/Search/IsShowHistorySearch.tsx new file mode 100644 index 000000000..c33caa492 --- /dev/null +++ b/src/screens/Home/Views/Setting/Search/IsShowHistorySearch.tsx @@ -0,0 +1,32 @@ +import { updateSetting } from '@/core/common' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' + + +import CheckBoxItem from '../components/CheckBoxItem' + +export default memo(() => { + const t = useI18n() + const isShowHistorySearch = useSettingValue('search.isShowHistorySearch') + const handleUpdate = (isShowHistorySearch: boolean) => { + updateSetting({ 'search.isShowHistorySearch': isShowHistorySearch }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isShowHistorySearch} onChange={handleUpdate} label={t('setting_search_show_history_search')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + marginBottom: 15, + }, +}) + diff --git a/src/screens/Home/Views/Setting/Search/IsShowHotSearch.tsx b/src/screens/Home/Views/Setting/Search/IsShowHotSearch.tsx new file mode 100644 index 000000000..817588ffa --- /dev/null +++ b/src/screens/Home/Views/Setting/Search/IsShowHotSearch.tsx @@ -0,0 +1,31 @@ +import { updateSetting } from '@/core/common' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import React, { memo } from 'react' +import { View } from 'react-native' +import { useSettingValue } from '@/store/setting/hook' + + +import CheckBoxItem from '../components/CheckBoxItem' + +export default memo(() => { + const t = useI18n() + const isShowHotSearch = useSettingValue('search.isShowHotSearch') + const handleUpdate = (isShowHotSearch: boolean) => { + updateSetting({ 'search.isShowHotSearch': isShowHotSearch }) + } + + return ( + <View style={styles.content}> + <CheckBoxItem check={isShowHotSearch} onChange={handleUpdate} label={t('setting_search_show_hot_search')} /> + </View> + ) +}) + + +const styles = createStyle({ + content: { + marginTop: 5, + }, +}) + diff --git a/src/screens/Home/Views/Setting/Search/index.tsx b/src/screens/Home/Views/Setting/Search/index.tsx new file mode 100644 index 000000000..302619e48 --- /dev/null +++ b/src/screens/Home/Views/Setting/Search/index.tsx @@ -0,0 +1,18 @@ +import React, { memo } from 'react' + +import Section from '../components/Section' +import IsShowHotSearch from './IsShowHotSearch' +import IsShowHistorySearch from './IsShowHistorySearch' + +import { useI18n } from '@/lang' + +export default memo(() => { + const t = useI18n() + + return ( + <Section title={t('setting_search')}> + <IsShowHotSearch /> + <IsShowHistorySearch /> + </Section> + ) +}) diff --git a/src/screens/Home/Setting/Sync/History.js b/src/screens/Home/Views/Setting/Sync/History.tsx similarity index 85% rename from src/screens/Home/Setting/Sync/History.js rename to src/screens/Home/Views/Setting/Sync/History.tsx index beb970393..a1002b45c 100644 --- a/src/screens/Home/Setting/Sync/History.js +++ b/src/screens/Home/Views/Setting/Sync/History.tsx @@ -1,14 +1,14 @@ import React, { memo, useRef, useState, useEffect, useCallback } from 'react' -import { StyleSheet, View, Text, TouchableOpacity, ScrollView } from 'react-native' -import { useGetter } from '@/store' +import { View, TouchableOpacity, ScrollView } from 'react-native' // import { gzip, ungzip } from 'pako' import { Icon } from '@/components/common/Icon' import Button from '../components/Button' import { useTranslation } from '@/plugins/i18n' -import { getSyncHostHistory, removeSyncHostHistory, setSyncHost } from '@/utils/tools' +import { createStyle, getSyncHostHistory, removeSyncHostHistory, setSyncHost } from '@/utils/tools' import Popup from '@/components/common/Popup' import { BorderWidths } from '@/theme' +import Text from '@/components/common/Text' const HistoryListItem = ({ item, index, remove, setHostInfo }) => { const theme = useGetter('common', 'theme') @@ -29,8 +29,8 @@ const HistoryListItem = ({ item, index, remove, setHostInfo }) => { return ( <View style={{ ...styles.listItem, borderBottomColor: theme.borderColor }}> <TouchableOpacity style={styles.listName} onPress={handleSetHost}> - <Text numberOfLines={1} style={{ fontSize: 12, color: theme.normal }}>{item.host}</Text> - <Text numberOfLines={1} style={{ fontSize: 12, color: theme.normal20 }}>{item.port}</Text> + <Text numberOfLines={1}>{item.host}</Text> + <Text color={theme['c-font-label']} numberOfLines={1}>{item.port}</Text> </TouchableOpacity> <TouchableOpacity onPress={handleRemove} style={styles.listMoreBtn}> <Icon name="remove" style={{ color: theme.normal35 }} size={16} /> @@ -75,7 +75,7 @@ const HistoryList = ({ visible, setHostInfo }) => { { list.length ? list.map((item, index) => <HistoryListItem item={item} index={index} remove={handleRemove} key={`${item.host}:${item.port}`} setHostInfo={setHostInfo} />) - : <Text style={{ ...styles.tipText, color: theme.normal10 }}>{t('setting_sync_history_empty')}</Text> + : <Text style={styles.tipText} color={theme['c-font-label']}>{t('setting_sync_history_empty')}</Text> } </ScrollView> ) @@ -110,7 +110,7 @@ export default memo(({ setHostInfo, isWaiting }) => { ) }) -const styles = StyleSheet.create({ +const styles = createStyle({ cacheSize: { marginBottom: 5, }, @@ -120,7 +120,6 @@ const styles = StyleSheet.create({ marginBottom: 15, }, tipText: { - fontSize: 14, textAlign: 'center', marginTop: 15, }, diff --git a/src/screens/Home/Setting/Sync/IsEnable.js b/src/screens/Home/Views/Setting/Sync/IsEnable.tsx similarity index 51% rename from src/screens/Home/Setting/Sync/IsEnable.js rename to src/screens/Home/Views/Setting/Sync/IsEnable.tsx index 6b4ddcf0a..bc040d369 100644 --- a/src/screens/Home/Setting/Sync/IsEnable.js +++ b/src/screens/Home/Views/Setting/Sync/IsEnable.tsx @@ -1,28 +1,37 @@ import React, { memo, useCallback, useState, useEffect, useRef, useMemo } from 'react' -import { View, Text, StyleSheet } from 'react-native' - -import { useGetter, useDispatch } from '@/store' +import { View } from 'react-native' import CheckBoxItem from '../components/CheckBoxItem' -import ConfirmAlert from '@/components/common/ConfirmAlert' +import ConfirmAlert, { type ConfirmAlertType } from '@/components/common/ConfirmAlert' import Input from '@/components/common/Input' -import { useTranslation } from '@/plugins/i18n' import { connect, disconnect, SYNC_CODE } from '@/plugins/sync' -import { getSyncHost, setSyncHost, toast, addSyncHostHistory } from '@/utils/tools' import InputItem from '../components/InputItem' -import { getWIFIIPV4Address } from '@/utils/utils' +import { getWIFIIPV4Address } from '@/utils/nativeModules/utils' +import { createStyle, toast } from '@/utils/tools' +import { useI18n } from '@/lang' +import { updateSetting } from '@/core/common' +import { addSyncHostHistory, getSyncHost, setSyncHost } from '@/utils/data' +import { setSyncMessage } from '@/core/sync' +import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' +import { useStatus } from '@/store/sync/hook' +import Text from '@/components/common/Text' const addressRxp = /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/ const portRxp = /(\d+)/ -const HostInput = memo(({ setHost, host, disabled }) => { - const { t } = useTranslation() +const HostInput = memo(({ setHost, host, disabled }: { + setHost: (host: string) => void + host: string + disabled?: boolean +}) => { + const t = useI18n() const hostAddress = useMemo(() => { return addressRxp.test(host) ? RegExp.$1 : '' }, [host]) - const setHostAddress = useCallback((value, callback) => { + const setHostAddress = useCallback((value: string, callback: (host: string) => void) => { let hostAddress = addressRxp.test(value) ? RegExp.$1 : '' callback(hostAddress) if (host == hostAddress) return @@ -34,20 +43,24 @@ const HostInput = memo(({ setHost, host, disabled }) => { editable={!disabled} value={hostAddress} label={t('setting_sync_host_label')} - onChange={setHostAddress} + onChanged={setHostAddress} keyboardType="number-pad" placeholder={t('setting_sync_host_tip')} /> ) }) -const PortInput = memo(({ setPort, port, disabled }) => { - const { t } = useTranslation() +const PortInput = memo(({ setPort, port, disabled }: { + setPort: (port: string) => void + port: string + disabled?: boolean +}) => { + const t = useI18n() const portNum = useMemo(() => { return portRxp.test(port) ? RegExp.$1 : '' }, [port]) - const setPortAddress = useCallback((value, callback) => { + const setPortAddress = useCallback((value: string, callback: (port: string) => void) => { let portNum = portRxp.test(value) ? RegExp.$1 : '' callback(portNum) if (port == portNum) return @@ -59,31 +72,38 @@ const PortInput = memo(({ setPort, port, disabled }) => { editable={!disabled} value={portNum} label={t('setting_sync_port_label')} - onChange={setPortAddress} + onChanged={setPortAddress} keyboardType="number-pad" placeholder={t('setting_sync_port_tip')} /> ) }) -export default memo(({ hostInfo, setHostInfo, isWaiting, setIsWaiting }) => { - const { t } = useTranslation() - const setIsEnableSync = useDispatch('common', 'setIsEnableSync') - const syncStatus = useGetter('common', 'syncStatus') - const isEnableSync = useGetter('common', 'isEnableSync') +export default memo(({ hostInfo, setHostInfo, isWaiting, setIsWaiting }: { + hostInfo: { host: string, port: string } + isWaiting: boolean + setHostInfo: (hostInfo: { host: string, port: string }) => void + setIsWaiting: (isWaiting: boolean) => void +}) => { + const t = useI18n() + const setIsEnableSync = useCallback((enable: boolean) => { + updateSetting({ 'sync.enable': enable }) + }, []) + const syncStatus = useStatus() + const isEnableSync = useSettingValue('sync.enable') const isUnmountedRef = useRef(true) - const theme = useGetter('common', 'theme') + const theme = useTheme() const [address, setAddress] = useState('') - const [visibleCodeModal, setVisibleCodeModal] = useState(false) const [authCode, setAuthCode] = useState('') + const confirmAlertRef = useRef<ConfirmAlertType>(null) useEffect(() => { isUnmountedRef.current = false - getSyncHost().then(hostInfo => { + void getSyncHost().then(hostInfo => { if (isUnmountedRef.current) return setHostInfo(hostInfo) }) - getWIFIIPV4Address().then(address => { + void getWIFIIPV4Address().then(address => { if (isUnmountedRef.current) return setAddress(address) }) @@ -98,37 +118,40 @@ export default memo(({ hostInfo, setHostInfo, isWaiting, setIsWaiting }) => { case SYNC_CODE.authFailed: toast(t('setting_sync_code_fail')) case SYNC_CODE.missingAuthCode: - setVisibleCodeModal(true) + confirmAlertRef.current?.setVisible(true) + break + case SYNC_CODE.msgBlockedIp: + toast(t('setting_sync_code_blocked_ip')) break default: break } }, [syncStatus.message, t]) - const handleSetEnableSync = useCallback(flag => { - setIsEnableSync(flag) + const handleSetEnableSync = useCallback((enable: boolean) => { + setIsEnableSync(enable) - if (flag) addSyncHostHistory(hostInfo.host, hostInfo.port) + if (enable) void addSyncHostHistory(hostInfo.host, hostInfo.port) - global.isSyncEnableing = true + global.lx.isSyncEnableing = true setIsWaiting(true) - ;(flag ? connect() : disconnect()).finally(() => { - global.isSyncEnableing = false + ;(enable ? connect() : disconnect()).finally(() => { + global.lx.isSyncEnableing = false setIsWaiting(false) }) }, [hostInfo, setIsEnableSync, setIsWaiting]) - const setHost = useCallback(host => { + const setHost = useCallback((host: string) => { if (host == hostInfo.host) return const newHostInfo = { ...hostInfo, host } - setSyncHost(newHostInfo) + void setSyncHost(newHostInfo) setHostInfo(newHostInfo) }, [hostInfo]) - const setPort = useCallback(port => { + const setPort = useCallback((port: string) => { if (port == hostInfo.host) return const newHostInfo = { ...hostInfo, port } - setSyncHost(newHostInfo) + void setSyncHost(newHostInfo) setHostInfo(newHostInfo) }, [hostInfo]) @@ -136,43 +159,60 @@ export default memo(({ hostInfo, setHostInfo, isWaiting, setIsWaiting }) => { const port = useMemo(() => hostInfo.port, [hostInfo.port]) const status = useMemo(() => { - return `${syncStatus.message ? syncStatus.message : syncStatus.status ? t('setting_sync_status_enabled') : t('sync_status_disabled')}` + let status + switch (syncStatus.message) { + case SYNC_CODE.msgBlockedIp: + status = t('setting_sync_code_blocked_ip') + break + case SYNC_CODE.authFailed: + status = t('setting_sync_code_fail') + break + default: + status = syncStatus.message + ? syncStatus.message + : syncStatus.status + ? t('setting_sync_status_enabled') + : t('sync_status_disabled') + break + } + return status }, [syncStatus.message, syncStatus.status, t]) const handleCancelSetCode = useCallback(() => { - setVisibleCodeModal(false) + setSyncMessage('') + confirmAlertRef.current?.setVisible(false) }, []) const handleSetCode = useCallback(() => { const code = authCode.trim() if (code.length != 6) return - connect(code) + void connect(code) setAuthCode('') - setVisibleCodeModal(false) + confirmAlertRef.current?.setVisible(false) }, [authCode]) return ( <> - <View style={{ marginTop: 5 }}> + <View style={styles.infoContent}> <CheckBoxItem disabled={isWaiting || !port || !host} check={isEnableSync} label={t('setting_sync_enbale')} onChange={handleSetEnableSync} /> - <Text style={{ color: theme.normal, marginLeft: 25, marginTop: 10, fontSize: 12 }}>{t('setting_sync_address', { address })}</Text> - <Text style={{ color: theme.normal, marginLeft: 25, fontSize: 12 }}>{t('setting_sync_status', { status })}</Text> + <Text style={styles.textAddr} size={13}>{t('setting_sync_address', { address })}</Text> + <Text style={styles.text} size={13}>{t('setting_sync_status', { status })}</Text> </View> - <View style={{ marginTop: 10 }} > + <View style={styles.inputContent} > <HostInput setHost={setHost} host={host} disabled={isWaiting || isEnableSync} /> <PortInput setPort={setPort} port={port} disabled={isWaiting || isEnableSync} /> </View> <ConfirmAlert - visible={visibleCodeModal} - onHide={handleCancelSetCode} + onCancel={handleCancelSetCode} onConfirm={handleSetCode} + ref={confirmAlertRef} > <View style={styles.authCodeContent}> - <Text style={{ color: theme.normal, marginBottom: 5 }}>{t('setting_sync_code_label')}</Text> + <Text style={styles.authCodeLabel}>{t('setting_sync_code_label')}</Text> <Input placeholder={t('setting_sync_code_input_tip')} value={authCode} onChangeText={setAuthCode} - style={{ ...styles.authCodeInput, backgroundColor: theme.secondary40 }} + style={{ ...styles.authCodeInput, backgroundColor: theme['c-primary-background'] }} /> </View> </ConfirmAlert> @@ -181,20 +221,36 @@ export default memo(({ hostInfo, setHostInfo, isWaiting, setIsWaiting }) => { }) -const styles = StyleSheet.create({ +const styles = createStyle({ + infoContent: { + marginTop: 5, + }, + textAddr: { + marginLeft: 25, + marginTop: 5, + }, + text: { + marginLeft: 25, + }, + inputContent: { + marginTop: 8, + }, authCodeContent: { flexGrow: 1, flexShrink: 1, flexDirection: 'column', }, + authCodeLabel: { + marginBottom: 5, + }, authCodeInput: { flexGrow: 1, flexShrink: 1, - minWidth: 240, + minWidth: 260, borderRadius: 4, - paddingTop: 2, - paddingBottom: 2, - fontSize: 12, + // paddingTop: 2, + // paddingBottom: 2, + // fontSize: 14, }, // tagTypeList: { diff --git a/src/screens/Home/Setting/Sync/index.js b/src/screens/Home/Views/Setting/Sync/index.tsx similarity index 64% rename from src/screens/Home/Setting/Sync/index.js rename to src/screens/Home/Views/Setting/Sync/index.tsx index da5682740..46329a521 100644 --- a/src/screens/Home/Setting/Sync/index.js +++ b/src/screens/Home/Views/Setting/Sync/index.tsx @@ -2,20 +2,20 @@ import React, { memo, useState } from 'react' import Section from '../components/Section' import IsEnable from './IsEnable' -import History from './History' +// import History from './History' +import { useI18n } from '@/lang' // import SyncHost from './SyncHost' -import { useTranslation } from '@/plugins/i18n' export default memo(() => { - const { t } = useTranslation() + const t = useI18n() const [hostInfo, setHostInfo] = useState({ host: '', port: '' }) - const [isWaiting, setIsWaiting] = useState(global.isSyncEnableing) + const [isWaiting, setIsWaiting] = useState(global.lx.isSyncEnableing) return ( <Section title={t('setting_sync')}> <IsEnable hostInfo={hostInfo} setHostInfo={setHostInfo} isWaiting={isWaiting} setIsWaiting={setIsWaiting} /> - <History setHostInfo={setHostInfo} isWaiting={isWaiting} /> + {/* <History setHostInfo={setHostInfo} isWaiting={isWaiting} /> */} </Section> ) }) diff --git a/src/screens/Home/Views/Setting/Sync/isEnable.tsx.bak b/src/screens/Home/Views/Setting/Sync/isEnable.tsx.bak new file mode 100644 index 000000000..4ce158acd --- /dev/null +++ b/src/screens/Home/Views/Setting/Sync/isEnable.tsx.bak @@ -0,0 +1,240 @@ +import React, { memo, useState, useEffect, useRef } from 'react' +import { View } from 'react-native' + +import CheckBoxItem from '../components/CheckBoxItem' +import ConfirmAlert, { ConfirmAlertType } from '@/components/common/ConfirmAlert' +import Input from '@/components/common/Input' +import { connect, disconnect, SYNC_CODE } from '@/plugins/sync' +import InputItem from '../components/InputItem' +import { getWIFIIPV4Address } from '@/utils/nativeModules/utils' +import { createStyle, toast } from '@/utils/tools' +import { useI18n } from '@/lang' +import { updateSetting } from '@/core/common' +import { addSyncHostHistory, getSyncHost, setSyncHost } from '@/utils/data' +import { setSpText } from '@/utils/pixelRatio' +import { setSyncMessage } from '@/core/sync' +import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' +import { useStatus } from '@/store/sync/hook' +import Text from '@/components/common/Text' + +const addressRxp = /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/ +const portRxp = /(\d+)/ + +const HostInput = ({ setHost, host, disabled }: { + setHost: (host: string) => void + host: string + disabled?: boolean +}) => { + const t = useI18n() + + const hostAddress = useMemo(() => { + return addressRxp.test(host) ? RegExp.$1 : '' + }, [host]) + + const setHostAddress = useCallback((value: string, callback: (host: string) => void) => { + let hostAddress = addressRxp.test(value) ? RegExp.$1 : '' + callback(hostAddress) + if (host == hostAddress) return + setHost(hostAddress) + }, [host, setHost]) + + return ( + <InputItem + editable={!disabled} + value={hostAddress} + label={t('setting_sync_host_label')} + onChanged={setHostAddress} + keyboardType="number-pad" + placeholder={t('setting_sync_host_tip')} /> + ) +} + +const PortInput = ({ setPort, port, disabled }: { + setPort: (port: string) => void + port: string + disabled?: boolean +}) => { + const t = useI18n() + + const portNum = useMemo(() => { + return portRxp.test(port) ? RegExp.$1 : '' + }, [port]) + + const setPortAddress = useCallback((value: string, callback: (port: string) => void) => { + let portNum = portRxp.test(value) ? RegExp.$1 : '' + callback(portNum) + if (port == portNum) return + setPort(portNum) + }, [port, setPort]) + + return ( + <InputItem + editable={!disabled} + value={portNum} + label={t('setting_sync_port_label')} + onChanged={setPortAddress} + keyboardType="number-pad" + placeholder={t('setting_sync_port_tip')} /> + ) +} + +const Status = () => { + const t = useI18n() + const syncStatus = useStatus() + const status = `${syncStatus.message ? syncStatus.message : syncStatus.status ? t('setting_sync_status_enabled') : t('sync_status_disabled')}` + + return <Text style={styles.text} size={13}>{t('setting_sync_status', { status })}</Text> +} + +export default memo(({ isWaiting, setIsWaiting }: { + hostInfo: { host: string, port: string } + isWaiting: boolean + setHostInfo: (hostInfo: { host: string, port: string }) => void + setIsWaiting: (isWaiting: boolean) => void +}) => { + const t = useI18n() + const setIsEnableSync = (enable: boolean) => { + updateSetting({ 'sync.enable': enable }) + } + const isEnableSync = useSettingValue('sync.enable') + const isUnmountedRef = useRef(true) + const theme = useTheme() + const [address, setAddress] = useState('') + const [authCode, setAuthCode] = useState('') + const confirmAlertRef = useRef<ConfirmAlertType>(null) + + useEffect(() => { + isUnmountedRef.current = false + void getSyncHost().then(hostInfo => { + if (isUnmountedRef.current) return + setHostInfo(hostInfo) + }) + void getWIFIIPV4Address().then(address => { + if (isUnmountedRef.current) return + setAddress(address) + }) + + return () => { + isUnmountedRef.current = true + } + }, []) + + useEffect(() => { + switch (syncStatus.message) { + case SYNC_CODE.authFailed: + toast(t('setting_sync_code_fail')) + case SYNC_CODE.missingAuthCode: + confirmAlertRef.current?.setVisible(true) + break + default: + break + } + }, [syncStatus.message, t]) + + const handleSetEnableSync = (enable: boolean) => { + setIsEnableSync(enable) + + if (enable) void addSyncHostHistory(hostInfo.host, hostInfo.port) + + global.lx.isSyncEnableing = true + setIsWaiting(true) + ;(enable ? connect() : disconnect()).finally(() => { + global.lx.isSyncEnableing = false + setIsWaiting(false) + }) + } + + + const setHost = (host: string) => { + if (host == hostInfo.host) return + const newHostInfo = { ...hostInfo, host } + void setSyncHost(newHostInfo) + setHostInfo(newHostInfo) + } + const setPort = (port: string) => { + if (port == hostInfo.host) return + const newHostInfo = { ...hostInfo, port } + void setSyncHost(newHostInfo) + setHostInfo(newHostInfo) + } + + const handleCancelSetCode = () => { + setSyncMessage('') + confirmAlertRef.current?.setVisible(false) + } + const handleSetCode = () => { + const code = authCode.trim() + if (code.length != 6) return + void connect(code) + setAuthCode('') + confirmAlertRef.current?.setVisible(false) + } + + return ( + <> + <View style={{ marginTop: 5 }}> + <CheckBoxItem disabled={isWaiting || !port || !host} check={isEnableSync} label={t('setting_sync_enbale')} onChange={handleSetEnableSync} /> + <Text style={{ ...styles.text, marginTop: setSpText(5) }} size={13}>{t('setting_sync_address', { address })}</Text> + <Status /> + </View> + <View style={{ marginTop: setSpText(10) }} > + <HostInput setHost={setHost} host={hostInfo.host} disabled={isWaiting || isEnableSync} /> + <PortInput setPort={setPort} port={hostInfo.port} disabled={isWaiting || isEnableSync} /> + </View> + <ConfirmAlert + onCancel={handleCancelSetCode} + onConfirm={handleSetCode} + ref={confirmAlertRef} + > + <View style={styles.authCodeContent}> + <Text style={{ marginBottom: setSpText(5) }}>{t('setting_sync_code_label')}</Text> + <Input + placeholder={t('setting_sync_code_input_tip')} + value={authCode} + onChangeText={setAuthCode} + style={{ ...styles.authCodeInput, backgroundColor: theme['c-primary-background'] }} + /> + </View> + </ConfirmAlert> + </> + ) +}) + + +const styles = createStyle({ + authCodeContent: { + flexGrow: 1, + flexShrink: 1, + flexDirection: 'column', + }, + authCodeInput: { + flexGrow: 1, + flexShrink: 1, + minWidth: 240, + borderRadius: 4, + paddingTop: 2, + paddingBottom: 2, + fontSize: 14, + }, + text: { + marginLeft: 25, + }, + + // tagTypeList: { + // flexDirection: 'row', + // flexWrap: 'wrap', + // }, + // tagButton: { + // // marginRight: 10, + // borderRadius: 4, + // marginRight: 10, + // marginBottom: 10, + // }, + // tagButtonText: { + // paddingLeft: 12, + // paddingRight: 12, + // paddingTop: 8, + // paddingBottom: 8, + // }, +}) diff --git a/src/screens/Home/Views/Setting/Version.tsx b/src/screens/Home/Views/Setting/Version.tsx new file mode 100644 index 000000000..08f31a989 --- /dev/null +++ b/src/screens/Home/Views/Setting/Version.tsx @@ -0,0 +1,91 @@ +import React, { memo, useState, useEffect } from 'react' +import { StyleSheet, View } from 'react-native' + +import Section from './components/Section' +import SubTitle from './components/SubTitle' +import Button from './components/Button' +import { sizeFormate } from '@/utils' + +import { useI18n } from '@/lang' +import { useVersionDownloadProgressUpdated, useVersionInfo } from '@/store/version/hook' +import Text from '@/components/common/Text' +import { showModal } from '@/core/version' + +const currentVer = process.versions.app +export default memo(() => { + const t = useI18n() + const versionInfo = useVersionInfo() + // const versionStatus = useVrsionUpdateStatus() + const [title, setTitle] = useState('') + const [tip, setTip] = useState('') + const progress = useVersionDownloadProgressUpdated() + const handleOpenVersionModal = () => { + // setVersionInfo({ showModal: true }) + showModal() + } + + useEffect(() => { + if (versionInfo.isLatest) { + setTitle(t('version_tip_latest')) + setTip('') + } else if (versionInfo.isUnknown) { + setTitle(t('version_title_unknown')) + setTip(t('version_tip_unknown')) + } else { + switch (versionInfo.status) { + case 'downloading': + setTitle(t('version_title_new')) + setTip(t('version_btn_downloading', { + total: sizeFormate(progress.total), + current: sizeFormate(progress.current), + progress: progress.total ? (progress.current / progress.total * 100).toFixed(2) : '0', + })) + break + case 'downloaded': + setTitle(t('version_title_update')) + setTip('') + break + case 'checking': + setTitle(t('version_title_checking')) + setTip('') + break + case 'error': + setTitle(t('version_title_failed')) + setTip(t('version_tip_failed')) + break + // case 'idle': + // break + default: + setTitle(t('version_title_new')) + setTip('') + break + } + } + }, [t, versionInfo, progress]) + + return ( + <Section title={t('setting_version')}> + <SubTitle title={title}> + <View style={styles.desc}> + <Text size={14}>{t('version_label_latest_ver')}{versionInfo.newVersion?.version}</Text> + <Text size={14}>{t('version_label_current_ver')}{currentVer}</Text> + { + tip ? <Text size={14}>{tip}</Text> : null + } + </View> + <View style={styles.btn}> + <Button onPress={handleOpenVersionModal}>{t('setting_version_show_ver_modal')}</Button> + </View> + </SubTitle> + </Section> + ) +}) + +const styles = StyleSheet.create({ + desc: { + marginBottom: 8, + }, + btn: { + flexDirection: 'row', + }, +}) diff --git a/src/screens/Home/Views/Setting/components/Button.tsx b/src/screens/Home/Views/Setting/components/Button.tsx new file mode 100644 index 000000000..6a933f3e5 --- /dev/null +++ b/src/screens/Home/Views/Setting/components/Button.tsx @@ -0,0 +1,29 @@ +import React, { memo } from 'react' + +import Button, { BtnProps } from '@/components/common/Button' +import Text from '@/components/common/Text' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' + +type ButtonProps = BtnProps + +export default memo(({ disabled, onPress, children }: ButtonProps) => { + const theme = useTheme() + + return ( + <Button style={{ ...styles.button, backgroundColor: theme['c-button-background'] }} onPress={onPress} disabled={disabled}> + <Text size={14} color={theme['c-button-font']}>{children}</Text> + </Button> + ) +}) + +const styles = createStyle({ + button: { + paddingLeft: 10, + paddingRight: 10, + paddingTop: 5, + paddingBottom: 5, + borderRadius: 4, + marginRight: 10, + }, +}) diff --git a/src/screens/Home/Views/Setting/components/CheckBoxItem.tsx b/src/screens/Home/Views/Setting/components/CheckBoxItem.tsx new file mode 100644 index 000000000..41377d1b1 --- /dev/null +++ b/src/screens/Home/Views/Setting/components/CheckBoxItem.tsx @@ -0,0 +1,24 @@ +import React, { memo } from 'react' + +import { View } from 'react-native' + +import CheckBox, { CheckBoxProps } from '@/components/common/CheckBox' +import { createStyle } from '@/utils/tools' + + +export default memo((props: CheckBoxProps) => { + return ( + <View style={styles.container}> + <CheckBox {...props} /> + </View> + ) +}) + +const styles = createStyle({ + container: { + paddingLeft: 25, + // marginTop: -10, + // marginBottom: 0, + }, +}) + diff --git a/src/screens/Home/Setting/components/InputItem.js b/src/screens/Home/Views/Setting/components/InputItem.tsx similarity index 63% rename from src/screens/Home/Setting/components/InputItem.js rename to src/screens/Home/Views/Setting/components/InputItem.tsx index 98e5d79f5..9f7c1b4ba 100644 --- a/src/screens/Home/Setting/components/InputItem.js +++ b/src/screens/Home/Views/Setting/components/InputItem.tsx @@ -1,23 +1,32 @@ import React, { memo, useState, useCallback, useEffect, useRef } from 'react' -import { StyleSheet, View, Text, Keyboard } from 'react-native' -import { useGetter } from '@/store' +import { StyleSheet, View, Keyboard } from 'react-native' +import type { InputType, InputProps } from '@/components/common/Input' import Input from '@/components/common/Input' +import { useTheme } from '@/store/theme/hook' +import Text from '@/components/common/Text' -export default memo(({ value, label, onChange, ...props }) => { + +export interface InputItemProps extends InputProps { + value: string + label: string + onChanged: (text: string, callback: (vlaue: string) => void) => void +} + +export default memo(({ value, label, onChanged, ...props }: InputItemProps) => { const [text, setText] = useState(value) const textRef = useRef(value) const isMountRef = useRef(false) - const inputRef = useRef() - const theme = useGetter('common', 'theme') + const inputRef = useRef<InputType>(null) + const theme = useTheme() const saveValue = useCallback(() => { - onChange && onChange(text, value => { + onChanged?.(text, (value: string) => { if (!isMountRef.current) return const newValue = String(value) setText(newValue) textRef.current = newValue }) - }, [onChange, text]) + }, [onChanged, text]) useEffect(() => { isMountRef.current = true return () => { @@ -27,7 +36,7 @@ export default memo(({ value, label, onChange, ...props }) => { useEffect(() => { const handleKeyboardDidHide = () => { if (!inputRef.current?.isFocused()) return - onChange && onChange(textRef.current, value => { + onChanged?.(textRef.current, value => { if (!isMountRef.current) return const newValue = String(value) setText(newValue) @@ -39,7 +48,7 @@ export default memo(({ value, label, onChange, ...props }) => { return () => { keyboardDidHide.remove() } - }, [onChange]) + }, [onChanged]) useEffect(() => { if (value != text) { const newValue = String(value) @@ -47,18 +56,18 @@ export default memo(({ value, label, onChange, ...props }) => { textRef.current = newValue } }, [value]) - const handleSetSelectMode = useCallback(text => { + const handleSetSelectMode = useCallback((text: string) => { setText(text) textRef.current = text }, []) return ( <View style={styles.container}> - <Text style={{ ...styles.label, color: theme.normal }}>{label}</Text> + <Text style={styles.label} size={14}>{label}</Text> <Input value={text} ref={inputRef} onChangeText={handleSetSelectMode} - style={{ ...styles.input, backgroundColor: theme.secondary40 }} + style={{ ...styles.input, backgroundColor: theme['c-primary-input-background'] }} {...props} onBlur={saveValue} /> @@ -72,16 +81,15 @@ const styles = StyleSheet.create({ marginBottom: 15, }, label: { - fontSize: 12, + marginBottom: 2, }, input: { backgroundColor: 'rgba(0,0,0,0.2)', flexGrow: 1, flexShrink: 1, borderRadius: 4, - paddingTop: 2, - paddingBottom: 2, - fontSize: 12, + // paddingTop: 3, + // paddingBottom: 3, maxWidth: 300, }, }) diff --git a/src/screens/Home/Views/Setting/components/Section.tsx b/src/screens/Home/Views/Setting/components/Section.tsx new file mode 100644 index 000000000..e255db554 --- /dev/null +++ b/src/screens/Home/Views/Setting/components/Section.tsx @@ -0,0 +1,39 @@ +import React from 'react' +import { View } from 'react-native' + +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import Text from '@/components/common/Text' + + +interface Props { + title: string + children: React.ReactNode | React.ReactNode[] +} + +export default ({ title, children }: Props) => { + const theme = useTheme() + + return ( + <View style={styles.container}> + <Text style={{ ...styles.title, borderLeftColor: theme['c-primary'] }} size={16} >{title}</Text> + <View> + {children} + </View> + </View> + ) +} + + +const styles = createStyle({ + container: { + // paddingLeft: 10, + // backgroundColor: 'rgba(0,0,0,0.2)', + }, + title: { + borderLeftWidth: 5, + paddingLeft: 12, + marginBottom: 10, + // lineHeight: 16, + }, +}) diff --git a/src/screens/Home/Setting/components/Slider.js b/src/screens/Home/Views/Setting/components/Slider.tsx similarity index 51% rename from src/screens/Home/Setting/components/Slider.js rename to src/screens/Home/Views/Setting/components/Slider.tsx index 61656e219..d59f05737 100644 --- a/src/screens/Home/Setting/components/Slider.js +++ b/src/screens/Home/Views/Setting/components/Slider.tsx @@ -1,11 +1,16 @@ + import React, { memo } from 'react' -import Slider from '@react-native-community/slider' -import { StyleSheet } from 'react-native' -import { useGetter } from '@/store' +import Slider, { type SliderProps } from '@react-native-community/slider' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' + +export type { + SliderProps, +} -export default memo(({ value, minimumValue, maximumValue, onSlidingStart, onSlidingComplete, onValueChange, step }) => { - const theme = useGetter('common', 'theme') +export default memo(({ value, minimumValue, maximumValue, onSlidingStart, onSlidingComplete, onValueChange, step }: SliderProps) => { + const theme = useTheme() return ( <Slider @@ -13,9 +18,9 @@ export default memo(({ value, minimumValue, maximumValue, onSlidingStart, onSlid style={styles.slider} minimumValue={minimumValue} maximumValue={maximumValue} - minimumTrackTintColor={theme.secondary30} - maximumTrackTintColor={theme.secondary30} - thumbTintColor={theme.secondary} + minimumTrackTintColor={theme['c-button-background-active']} + maximumTrackTintColor={theme['c-button-background']} + thumbTintColor={theme['c-primary-light-100']} onSlidingStart={onSlidingStart} onSlidingComplete={onSlidingComplete} onValueChange={onValueChange} @@ -25,7 +30,7 @@ export default memo(({ value, minimumValue, maximumValue, onSlidingStart, onSlid }) -const styles = StyleSheet.create({ +const styles = createStyle({ slider: { flexShrink: 0, flexGrow: 1, diff --git a/src/screens/Home/Views/Setting/components/SubTitle.tsx b/src/screens/Home/Views/Setting/components/SubTitle.tsx new file mode 100644 index 000000000..b540133d9 --- /dev/null +++ b/src/screens/Home/Views/Setting/components/SubTitle.tsx @@ -0,0 +1,30 @@ +import React, { memo } from 'react' + +import { View } from 'react-native' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' + +export default memo(({ title, children }: { + title: string + children: React.ReactNode | React.ReactNode[] +}) => { + return ( + <View style={styles.container}> + <Text style={styles.title}>{title}</Text> + {children} + </View> + ) +}) + + +const styles = createStyle({ + container: { + paddingLeft: 25, + marginBottom: 18, + }, + title: { + marginLeft: -10, + marginBottom: 10, + // lineHeight: 16, + }, +}) diff --git a/src/screens/Home/Setting/index.js b/src/screens/Home/Views/Setting/index.tsx similarity index 67% rename from src/screens/Home/Setting/index.js rename to src/screens/Home/Views/Setting/index.tsx index 04ba9e375..06195a63e 100644 --- a/src/screens/Home/Setting/index.js +++ b/src/screens/Home/Views/Setting/index.tsx @@ -1,6 +1,6 @@ +import { createStyle } from '@/utils/tools' import React from 'react' import { - StyleSheet, View, ScrollView, } from 'react-native' @@ -9,6 +9,7 @@ import { import Basic from './Basic' import Player from './Player' import LyricDesktop from './LyricDesktop' +import Search from './Search' import List from './List' import Sync from './Sync' import Backup from './Backup' @@ -16,11 +17,14 @@ import Other from './Other' import Version from './Version' import About from './About' -const styles = StyleSheet.create({ +const styles = createStyle({ scrollView: { }, content: { - padding: 15, + paddingLeft: 15, + paddingRight: 15, + paddingTop: 15, + paddingBottom: 15, flex: 0, }, }) @@ -32,20 +36,13 @@ export default () => { <Basic /> <Player /> <LyricDesktop /> + <Search /> <List /> <Sync /> <Backup /> <Other /> <Version /> <About /> - {/* <Text>setting</Text> */} - {/* <View><Menu menus={[ - { name: '播放', id: '456' }, - { name: '删除', id: '432' }, - { name: '添加', id: '4561' }, - { name: '打开详情页', id: '4356' }, - { name: '移动', id: '4564' }, - ]}>123</Menu></View> */} </View> </ScrollView> ) diff --git a/src/screens/Home/Views/SongList/Content.tsx b/src/screens/Home/Views/SongList/Content.tsx new file mode 100644 index 000000000..56f58403a --- /dev/null +++ b/src/screens/Home/Views/SongList/Content.tsx @@ -0,0 +1,72 @@ +import { getSongListSetting, saveSongListSetting } from '@/utils/data' +import React, { useEffect, useRef } from 'react' +import { StyleSheet, View } from 'react-native' + +// import List from './List/List' +import HeaderBar, { type HeaderBarProps, type HeaderBarType } from './HeaderBar' +import songlistState, { type InitState, type SortInfo } from '@/store/songlist/state' +import List, { type ListType } from './List' + + +interface SonglistInfo { + source: InitState['sources'][number] + sortId: SortInfo['id'] + tagId: string +} + +export default () => { + const headerBarRef = useRef<HeaderBarType>(null) + const listRef = useRef<ListType>(null) + const songlistInfo = useRef<SonglistInfo>({ source: 'kw', sortId: '5', tagId: '' }) + + useEffect(() => { + void getSongListSetting().then(info => { + songlistInfo.current.source = info.source + songlistInfo.current.sortId = info.sortId + songlistInfo.current.tagId = info.tagId + headerBarRef.current?.setSource(info.source, info.sortId, info.tagName, info.tagId) + listRef.current?.loadList(info.source, info.sortId, info.tagId) + }) + }, []) + + const handleSortChange: HeaderBarProps['onSortChange'] = (id) => { + songlistInfo.current.sortId = id + void saveSongListSetting({ sortId: id }) + listRef.current?.loadList(songlistInfo.current.source, id, songlistInfo.current.tagId) + } + + const handleTagChange: HeaderBarProps['onTagChange'] = (name, id) => { + songlistInfo.current.tagId = id + void saveSongListSetting({ tagName: name, tagId: id }) + listRef.current?.loadList(songlistInfo.current.source, songlistInfo.current.sortId, id) + } + + const handleSourceChange: HeaderBarProps['onSourceChange'] = (source) => { + songlistInfo.current.source = source + songlistInfo.current.tagId = '' + songlistInfo.current.sortId = songlistState.sortList[source]![0].id + void saveSongListSetting({ sortId: songlistInfo.current.sortId, source, tagId: '', tagName: '' }) + headerBarRef.current?.setSource(source, songlistInfo.current.sortId, '', songlistInfo.current.tagId) + listRef.current?.loadList(source, songlistInfo.current.sortId, songlistInfo.current.tagId) + } + + return ( + <View style={styles.container}> + <HeaderBar + ref={headerBarRef} + onSortChange={handleSortChange} + onTagChange={handleTagChange} + onSourceChange={handleSourceChange} + /> + <List ref={listRef} /> + </View> + ) +} + +const styles = StyleSheet.create({ + container: { + position: 'relative', + flex: 1, + }, +}) + diff --git a/src/screens/Home/Views/SongList/HeaderBar/OpenList/Modal.tsx b/src/screens/Home/Views/SongList/HeaderBar/OpenList/Modal.tsx new file mode 100644 index 000000000..d5c7f54fc --- /dev/null +++ b/src/screens/Home/Views/SongList/HeaderBar/OpenList/Modal.tsx @@ -0,0 +1,143 @@ +import React, { useRef, useImperativeHandle, forwardRef, useState } from 'react' +import ConfirmAlert, { type ConfirmAlertType } from '@/components/common/ConfirmAlert' +import Text from '@/components/common/Text' +import { View } from 'react-native' +import Input, { type InputType } from '@/components/common/Input' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' +// import SourceSelector, { type SourceSelectorProps, type SourceSelectorType } from '../SourceSelector' +import { type Source } from '@/store/songlist/state' + +interface IdInputType { + setText: (text: string) => void + getText: () => string + focus: () => void +} +const IdInput = forwardRef<IdInputType, {}>((props, ref) => { + const theme = useTheme() + const t = useI18n() + const [text, setText] = useState('') + const inputRef = useRef<InputType>(null) + + useImperativeHandle(ref, () => ({ + getText() { + return text.trim() + }, + setText(text) { + setText(text) + }, + focus() { + inputRef.current?.focus() + }, + })) + + return ( + <Input + ref={inputRef} + placeholder={t('songlist_open_input_placeholder')} + value={text} + onChangeText={setText} + style={{ ...styles.input, backgroundColor: theme['c-primary-input-background'] }} + /> + ) +}) + + +export interface ModalProps { + onOpenId: (id: string) => void + // onSourceChange: SourceSelectorProps['onSourceChange'] +} +export interface ModalType { + show: (source: Source) => void +} + +export default forwardRef<ModalType, ModalProps>(({ onOpenId }, ref) => { + const alertRef = useRef<ConfirmAlertType>(null) + // const sourceSelectorRef = useRef<SourceSelectorType>(null) + const inputRef = useRef<IdInputType>(null) + const [visible, setVisible] = useState(false) + const theme = useTheme() + const t = useI18n() + + const handleShow = (source: Source) => { + alertRef.current?.setVisible(true) + requestAnimationFrame(() => { + inputRef.current?.setText('') + // sourceSelectorRef.current?.setSource(source) + setTimeout(() => { + inputRef.current?.focus() + }, 300) + }) + } + useImperativeHandle(ref, () => ({ + show(source) { + if (visible) handleShow(source) + else { + setVisible(true) + requestAnimationFrame(() => { + handleShow(source) + }) + } + }, + })) + + const handleConfirm = () => { + let id = inputRef.current?.getText() ?? '' + if (!id.length) return + if (id.length > 500) id = id.substring(0, 500) + alertRef.current?.setVisible(false) + onOpenId(id) + } + + return ( + visible + ? <ConfirmAlert + ref={alertRef} + onConfirm={handleConfirm} + > + <View style={styles.content}> + <View style={styles.col}> + {/* <SourceSelector style={{ ...styles.selector, backgroundColor: theme['c-primary-input-background'] }} ref={sourceSelectorRef} onSourceChange={onSourceChange} /> */} + <IdInput ref={inputRef} /> + </View> + <Text style={styles.inputTipText} size={13} color={theme['c-600']}>{t('songlist_open_input_tip')}</Text> + </View> + </ConfirmAlert> + : null + ) +}) + + +const styles = createStyle({ + content: { + flexGrow: 1, + flexShrink: 1, + flexDirection: 'column', + }, + col: { + flexDirection: 'row', + height: 38, + }, + // selector: { + // borderTopLeftRadius: 4, + // borderBottomLeftRadius: 4, + // }, + input: { + flexGrow: 1, + flexShrink: 1, + minWidth: 290, + // borderRadius: 4, + // borderTopRightRadius: 4, + // borderBottomRightRadius: 4, + // paddingTop: 2, + // paddingBottom: 2, + height: '100%', + }, + inputTipText: { + marginTop: 15, + // lineHeight: 18, + }, +}) + + diff --git a/src/screens/Home/Views/SongList/HeaderBar/OpenList/index.tsx b/src/screens/Home/Views/SongList/HeaderBar/OpenList/index.tsx new file mode 100644 index 000000000..a4de015a0 --- /dev/null +++ b/src/screens/Home/Views/SongList/HeaderBar/OpenList/index.tsx @@ -0,0 +1,70 @@ +import React, { useRef, forwardRef, useImperativeHandle } from 'react' +// import { Icon } from '@/components/common/Icon' +import Button from '@/components/common/Button' +// import { navigations } from '@/navigation' +import Modal, { type ModalType } from './Modal' +import { type Source } from '@/store/songlist/state' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' +import { useI18n } from '@/lang' +import { setSelectListInfo } from '@/core/songlist' +import { navigations } from '@/navigation' +import commonState from '@/store/common/state' + +// export interface OpenListProps { +// onTagChange: (name: string, id: string) => void +// } + +export interface OpenListType { + setInfo: (source: Source) => void +} + +export default forwardRef<OpenListType, {}>((props, ref) => { + const t = useI18n() + const modalRef = useRef<ModalType>(null) + const songlistInfoRef = useRef<{ source: Source }>({ source: 'kw' }) + + useImperativeHandle(ref, () => ({ + setInfo(source) { + songlistInfoRef.current.source = source + }, + })) + + const handleOpenSonglist = (id: string) => { + // console.log(id, songlistInfoRef.current.source) + setSelectListInfo({ + play_count: undefined, + id, + author: '', + name: '', + img: undefined, + desc: undefined, + source: songlistInfoRef.current.source, + }) + navigations.pushSonglistDetailScreen(commonState.componentIds.home as string, id) + } + + // const handleSourceChange: ModalProps['onSourceChange'] = (source) => { + // songlistInfoRef.current.source = source + // } + + + return ( + <> + <Button style={styles.button} onPress={() => modalRef.current?.show(songlistInfoRef.current.source)}> + <Text>{t('songlist_open')}</Text> + </Button> + <Modal ref={modalRef} onOpenId={handleOpenSonglist} /> + </> + ) +}) + +const styles = createStyle({ + button: { + // backgroundColor: '#ccc', + alignItems: 'center', + justifyContent: 'center', + paddingLeft: 12, + paddingRight: 12, + }, +}) diff --git a/src/screens/Home/Views/SongList/HeaderBar/SortTab.tsx b/src/screens/Home/Views/SongList/HeaderBar/SortTab.tsx new file mode 100644 index 000000000..4604ca007 --- /dev/null +++ b/src/screens/Home/Views/SongList/HeaderBar/SortTab.tsx @@ -0,0 +1,78 @@ +import React, { forwardRef, useImperativeHandle, useMemo, useState } from 'react' +import { ScrollView, TouchableOpacity } from 'react-native' +import songlistState, { type SortInfo, type Source } from '@/store/songlist/state' +import { useI18n } from '@/lang' +import { useTheme } from '@/store/theme/hook' +import Text from '@/components/common/Text' +import { createStyle } from '@/utils/tools' + +export interface SortTabProps { + onSortChange: (id: string) => void +} + +export interface SortTabType { + setSource: (source: Source, activeTab: SortInfo['id']) => void +} + + +export default forwardRef<SortTabType, SortTabProps>(({ onSortChange }, ref) => { + const [sortList, setSortList] = useState<SortInfo[]>([]) + const [activeId, setActiveId] = useState<SortInfo['id']>('') + const t = useI18n() + const theme = useTheme() + + useImperativeHandle(ref, () => ({ + setSource(source, activeTab) { + setSortList(songlistState.sortList[source] as SortInfo[]) + setActiveId(activeTab) + }, + })) + + const sorts = useMemo(() => { + return sortList.map(s => ({ label: t(`songlist_${s.tid}`), id: s.id })) + }, [sortList, t]) + + const handleSortChange = (id: string) => { + onSortChange(id) + setActiveId(id) + } + + return ( + <ScrollView style={styles.container} keyboardShouldPersistTaps={'always'} horizontal={true}> + { + sorts.map(s => ( + <TouchableOpacity style={styles.button} onPress={() => { handleSortChange(s.id) }} key={s.id}> + <Text style={styles.buttonText} color={activeId == s.id ? theme['c-primary-font-active'] : theme['c-font']}>{s.label}</Text> + </TouchableOpacity> + )) + } + </ScrollView> + ) +}) + + +const styles = createStyle({ + container: { + flexGrow: 1, + flexShrink: 1, + // paddingLeft: 5, + // paddingRight: 5, + }, + button: { + // height: 38, + // lineHeight: 38, + justifyContent: 'center', + // width: 80, + // backgroundColor: 'rgba(0,0,0,0.1)', + }, + buttonText: { + // height: 38, + // lineHeight: 38, + textAlign: 'center', + paddingLeft: 15, + paddingRight: 15, + // paddingTop: 10, + // paddingBottom: 10, + // width: 80, + }, +}) diff --git a/src/screens/Home/Views/SongList/HeaderBar/SourceSelector.tsx b/src/screens/Home/Views/SongList/HeaderBar/SourceSelector.tsx new file mode 100644 index 000000000..1b16d4504 --- /dev/null +++ b/src/screens/Home/Views/SongList/HeaderBar/SourceSelector.tsx @@ -0,0 +1,45 @@ +import React, { forwardRef, useImperativeHandle, useRef } from 'react' +import { StyleSheet, View, type ViewStyle } from 'react-native' + +import { createStyle } from '@/utils/tools' +import SourceSelector, { + type SourceSelectorType as _SourceSelectorType, + type SourceSelectorProps as _SourceSelectorProps, +} from '@/components/SourceSelector' +import songlistState, { type Source, type InitState } from '@/store/songlist/state' + +type Sources = Readonly<InitState['sources']> +type SourceSelectorCommonProps = _SourceSelectorProps<Sources> +type SourceSelectorCommonType = _SourceSelectorType<Sources> + +export interface SourceSelectorProps { + onSourceChange: SourceSelectorCommonProps['onSourceChange'] + style?: ViewStyle +} + +export interface SourceSelectorType { + setSource: (source: Source) => void +} + +export default forwardRef<SourceSelectorType, SourceSelectorProps>(({ style, onSourceChange }, ref) => { + const sourceSelectorRef = useRef<SourceSelectorCommonType>(null) + + useImperativeHandle(ref, () => ({ + setSource(source) { + sourceSelectorRef.current?.setSourceList(songlistState.sources, source) + }, + }), []) + + + return ( + <View style={StyleSheet.compose<ViewStyle>(styles.selector, style)}> + <SourceSelector ref={sourceSelectorRef} onSourceChange={onSourceChange} center /> + </View> + ) +}) + +const styles = createStyle({ + selector: { + // width: 86, + }, +}) diff --git a/src/screens/Home/Views/SongList/HeaderBar/Tag/CurrentTagBtn.tsx b/src/screens/Home/Views/SongList/HeaderBar/Tag/CurrentTagBtn.tsx new file mode 100644 index 000000000..8a95df084 --- /dev/null +++ b/src/screens/Home/Views/SongList/HeaderBar/Tag/CurrentTagBtn.tsx @@ -0,0 +1,49 @@ +import Button from '@/components/common/Button' +import Text from '@/components/common/Text' +import { useI18n } from '@/lang' +import { createStyle } from '@/utils/tools' +import React, { forwardRef, useImperativeHandle, useState } from 'react' + + +export interface CurrentTagBtnProps { + onShowList: () => void +} + +export interface CurrentTagBtnType { + setCurrentTagInfo: (name: string) => void +} + +export default forwardRef<CurrentTagBtnType, CurrentTagBtnProps>(({ onShowList }, ref) => { + const t = useI18n() + const [name, setName] = useState('') + + useImperativeHandle(ref, () => ({ + setCurrentTagInfo(name) { + if (!name) name = t('songlist_tag_default') + setName(name) + }, + })) + + return ( + <Button style={styles.btn} onPress={onShowList}> + <Text style={styles.sourceMenu}>{name}</Text> + </Button> + ) +}) + + +const styles = createStyle({ + btn: { + paddingLeft: 15, + paddingRight: 15, + justifyContent: 'center', + }, + sourceMenu: { + // height: 38, + // lineHeight: 38, + textAlign: 'center', + // minWidth: 70, + // paddingTop: 10, + // paddingBottom: 10, + }, +}) diff --git a/src/screens/Home/Views/SongList/HeaderBar/Tag/index.tsx b/src/screens/Home/Views/SongList/HeaderBar/Tag/index.tsx new file mode 100644 index 000000000..8ed9ded34 --- /dev/null +++ b/src/screens/Home/Views/SongList/HeaderBar/Tag/index.tsx @@ -0,0 +1,54 @@ +import React, { forwardRef, useEffect, useImperativeHandle, useRef } from 'react' + +// import TagPopup, { type TagPopupProps, type TagPopupType } from './TagPopup' +import CurrentTagBtn, { type CurrentTagBtnType } from './CurrentTagBtn' +import { type Source } from '@/store/songlist/state' + + +export interface TagProps { + onTagChange: (name: string, id: string) => void +} + +export interface TagType { + setSelectedTagInfo: (source: Source, name: string, activeId: string) => void +} + +export default forwardRef<TagType, TagProps>(({ onTagChange }, ref) => { + // console.log('render tag btn') + const currentTagBtnRef = useRef<CurrentTagBtnType>(null) + // const tagPopupRef = useRef<TagPopupType>(null) + const tagInfoRef = useRef<{ source: Source, activeId: string }>({ source: 'kw', activeId: '' }) + + useEffect(() => { + const handleChange = (name: string, id: string) => { + onTagChange(name, id) + tagInfoRef.current.activeId = id + currentTagBtnRef.current?.setCurrentTagInfo(name) + } + + global.app_event.on('songlistTagInfoChange', handleChange) + return () => { + global.app_event.off('songlistTagInfoChange', handleChange) + } + }, [onTagChange]) + + useImperativeHandle(ref, () => ({ + setSelectedTagInfo(source, name, activeId) { + tagInfoRef.current.activeId = activeId + tagInfoRef.current.source = source + currentTagBtnRef.current?.setCurrentTagInfo(name) + }, + })) + + const handleShowList = () => { + global.app_event.showSonglistTagList(tagInfoRef.current.source, tagInfoRef.current.activeId) + } + + // const handleChangeTag: TagProps['onTagChange'] = (name, id) => { + // tagInfoRef.current.activeId = id + // onTagChange(name, id) + // currentTagBtnRef.current?.setCurrentTagInfo(name) + // } + + return <CurrentTagBtn ref={currentTagBtnRef} onShowList={handleShowList} /> +}) diff --git a/src/screens/Home/Views/SongList/HeaderBar/index.tsx b/src/screens/Home/Views/SongList/HeaderBar/index.tsx new file mode 100644 index 000000000..c61f71517 --- /dev/null +++ b/src/screens/Home/Views/SongList/HeaderBar/index.tsx @@ -0,0 +1,69 @@ +import React, { forwardRef, useImperativeHandle, useRef } from 'react' +import { View } from 'react-native' + +// import { useGetter, useDispatch } from '@/store' +import SortTab, { type SortTabProps, type SortTabType } from './SortTab' +// import Tag from './Tag' +// import OpenList from './OpenList' +import { createStyle } from '@/utils/tools' +// import { BorderWidths } from '@/theme' +import SourceSelector, { + type SourceSelectorType, + type SourceSelectorProps, +} from './SourceSelector' +import { type Source } from '@/store/songlist/state' +// import { useTheme } from '@/store/theme/hook' +import Tag, { type TagType, type TagProps } from './Tag' +import OpenList, { type OpenListType } from './OpenList' +// import { BorderWidths } from '@/theme' + +export interface HeaderBarProps { + onSortChange: SortTabProps['onSortChange'] + onTagChange: TagProps['onTagChange'] + onSourceChange: SourceSelectorProps['onSourceChange'] +} + +export interface HeaderBarType { + setSource: (source: Source, sortId: string, tagName: string, tagId: string) => void +} + + +export default forwardRef<HeaderBarType, HeaderBarProps>(({ onSortChange, onTagChange, onSourceChange }, ref) => { + const sortTabRef = useRef<SortTabType>(null) + const tagRef = useRef<TagType>(null) + const openListRef = useRef<OpenListType>(null) + const sourceSelectorRef = useRef<SourceSelectorType>(null) + // const theme = useTheme() + + useImperativeHandle(ref, () => ({ + setSource(source, sortId, tagName, tagId) { + sortTabRef.current?.setSource(source, sortId) + tagRef.current?.setSelectedTagInfo(source, tagName, tagId) + sourceSelectorRef.current?.setSource(source) + openListRef.current?.setInfo(source) + }, + }), []) + + + return ( + <View style={styles.searchBar}> + <SortTab ref={sortTabRef} onSortChange={onSortChange} /> + <Tag ref={tagRef} onTagChange={onTagChange} /> + <OpenList ref={openListRef} /> + <SourceSelector ref={sourceSelectorRef} onSourceChange={onSourceChange} /> + </View> + ) +}) + +const styles = createStyle({ + searchBar: { + flexDirection: 'row', + height: 38, + zIndex: 2, + // paddingRight: 10, + // borderBottomWidth: BorderWidths.normal, + }, + selector: { + width: 86, + }, +}) diff --git a/src/screens/Home/Views/SongList/List.tsx b/src/screens/Home/Views/SongList/List.tsx new file mode 100644 index 000000000..5a697a1a7 --- /dev/null +++ b/src/screens/Home/Views/SongList/List.tsx @@ -0,0 +1,80 @@ +import React, { forwardRef, useEffect, useImperativeHandle, useRef } from 'react' +import Songlist, { type SonglistProps, type SonglistType } from './components/Songlist' +import { getList, setList, setListInfo } from '@/core/songlist' +import songlistState from '@/store/songlist/state' +import { type Source } from '@/store/songlist/state' + + +export interface ListType { + loadList: (source: Source, sortId: string, tagId: string) => void +} + +export default forwardRef<ListType, {}>((props, ref) => { + const listRef = useRef<SonglistType>(null) + const isUnmountedRef = useRef(false) + useImperativeHandle(ref, () => ({ + loadList(source, sortId, tagId) { + const listInfo = songlistState.listInfo + listRef.current?.setList([]) + if (listInfo.tagId == tagId && listInfo.sortId == sortId && listInfo.source == source && listInfo.list.length) { + requestAnimationFrame(() => { + listRef.current?.setList(listInfo.list) + }) + } else { + listRef.current?.setStatus('loading') + setListInfo(source, tagId, sortId) + const page = 1 + return getList(source, tagId, sortId, page).then((info) => { + const result = setList(info, tagId, sortId, page) + if (isUnmountedRef.current) return + requestAnimationFrame(() => { + listRef.current?.setList(result.list) + listRef.current?.setStatus(songlistState.listInfo.maxPage == page ? 'end' : 'idle') + }) + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + }, + }), []) + + useEffect(() => { + isUnmountedRef.current = false + return () => { + isUnmountedRef.current = true + } + }, []) + + + const handleRefresh: SonglistProps['onRefresh'] = () => { + const page = 1 + listRef.current?.setStatus('refreshing') + getList(songlistState.listInfo.source, songlistState.listInfo.tagId, songlistState.listInfo.sortId, page, true).then((info) => { + const result = setList(info, songlistState.listInfo.tagId, songlistState.listInfo.sortId, page) + if (isUnmountedRef.current) return + listRef.current?.setList(result.list) + listRef.current?.setStatus(songlistState.listInfo.maxPage == page ? 'end' : 'idle') + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + const handleLoadMore: SonglistProps['onLoadMore'] = () => { + listRef.current?.setStatus('loading') + const page = songlistState.listInfo.list.length ? songlistState.listInfo.page + 1 : 1 + getList(songlistState.listInfo.source, songlistState.listInfo.tagId, songlistState.listInfo.sortId, page).then((info) => { + const result = setList(info, songlistState.listInfo.tagId, songlistState.listInfo.sortId, page) + if (isUnmountedRef.current) return + listRef.current?.setList(result.list) + listRef.current?.setStatus(songlistState.listInfo.maxPage == page ? 'end' : 'idle') + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + + return <Songlist + ref={listRef} + onRefresh={handleRefresh} + onLoadMore={handleLoadMore} + /> +}) + diff --git a/src/screens/Home/Views/SongList/TagList/List.tsx b/src/screens/Home/Views/SongList/TagList/List.tsx new file mode 100644 index 000000000..e7329a070 --- /dev/null +++ b/src/screens/Home/Views/SongList/TagList/List.tsx @@ -0,0 +1,95 @@ +import React, { useEffect, useState, useRef, forwardRef, useImperativeHandle } from 'react' +import { View, ScrollView } from 'react-native' + +import { createStyle } from '@/utils/tools' +import TagGroup, { type TagGroupProps } from './TagGroup' +import { useI18n } from '@/lang' +import { type TagInfo, type Source } from '@/store/songlist/state' +import { getTags } from '@/core/songlist' +import Text from '@/components/common/Text' +// import { BorderWidths } from '@/theme' + +export interface ListProps { + onTagChange: TagGroupProps['onTagChange'] +} + +export interface ListType { + loadTag: (source: Source, activeId: string) => void +} + +export default forwardRef<ListType, ListProps>(({ onTagChange }, ref) => { + // const theme = useTheme() + const [activeId, setActiveId] = useState('') + const [list, setList] = useState<TagInfo['tags']>([]) + const t = useI18n() + const prevSource = useRef('') + + const isUnmountedRef = useRef(false) + useEffect(() => { + isUnmountedRef.current = false + return () => { + isUnmountedRef.current = true + } + }, []) + + useImperativeHandle(ref, () => ({ + loadTag(source, id) { + if (id != activeId) setActiveId(id) + if (source != prevSource.current) { + setList([{ name: '', list: [{ name: t('songlist_tag_default'), id: '', parent_id: '', parent_name: '', source }] }]) + void getTags(source).then(tagInfo => { + if (isUnmountedRef.current) return + prevSource.current = source + setList([ + { name: '', list: [{ name: t('songlist_tag_default'), id: '', parent_id: '', parent_name: '', source }] }, + { name: t('songlist_tag_hot'), list: [...tagInfo.hotTag] }, + ...tagInfo.tags, + ].filter(t => t.list.length)) + }) + } + }, + })) + + + return ( + <ScrollView style={{ flexShrink: 1, flexGrow: 0 }} keyboardShouldPersistTaps={'always'}> + <View style={styles.tagContainer} onStartShouldSetResponder={() => true}> + { + list.map((type, index) => ( + <TagGroup + key={index} + name={type.name} + list={type.list} + activeId={activeId} + onTagChange={onTagChange} + /> + )) + } + { + list.length == 1 + ? ( + <View style={styles.blankView}> + <Text>{t('list_loading')}</Text> + </View> + ) + : null + } + </View> + </ScrollView> + ) +}) + + +const styles = createStyle({ + tagContainer: { + paddingTop: 15, + paddingLeft: 15, + paddingBottom: 15, + }, + blankView: { + paddingTop: '15%', + paddingBottom: '15%', + alignItems: 'center', + justifyContent: 'center', + }, +}) diff --git a/src/screens/Home/Views/SongList/TagList/TagGroup.tsx b/src/screens/Home/Views/SongList/TagList/TagGroup.tsx new file mode 100644 index 000000000..ee51d16ff --- /dev/null +++ b/src/screens/Home/Views/SongList/TagList/TagGroup.tsx @@ -0,0 +1,72 @@ +import React from 'react' +import { View } from 'react-native' + +import Button from '@/components/common/Button' +import { type TagInfoItem } from '@/store/songlist/state' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' + +export interface TagGroupProps { + name: string + list: TagInfoItem[] + onTagChange: (name: string, id: string) => void + activeId: string +} + +export default ({ name, list, onTagChange, activeId }: TagGroupProps) => { + const theme = useTheme() + return ( + <View> + { + name + ? <Text style={styles.tagTypeTitle} color={theme['c-font-label']}>{name}</Text> + : null + } + <View style={styles.tagTypeList}> + {list.map(item => ( + activeId == item.id + ? ( + <View style={{ ...styles.tagButton, backgroundColor: theme['c-button-background'] }} key={item.id}> + <Text style={styles.tagButtonText} color={theme['c-primary-font-active']}>{item.name}</Text> + </View> + ) + : ( + <Button + style={{ ...styles.tagButton, backgroundColor: theme['c-button-background'] }} + key={item.id} + onPress={() => { onTagChange(item.name, item.id) }} + > + <Text style={styles.tagButtonText} color={theme['c-font']} >{item.name}</Text> + </Button> + ) + + ))} + </View> + </View> + ) +} + +const styles = createStyle({ + tagTypeTitle: { + marginTop: 15, + marginBottom: 10, + }, + tagTypeList: { + flexDirection: 'row', + flexWrap: 'wrap', + }, + tagButton: { + // marginRight: 10, + borderRadius: 4, + marginRight: 10, + marginBottom: 10, + }, + tagButtonText: { + fontSize: 13, + paddingLeft: 12, + paddingRight: 12, + paddingTop: 8, + paddingBottom: 8, + }, +}) diff --git a/src/screens/Home/Views/SongList/TagList/index.tsx b/src/screens/Home/Views/SongList/TagList/index.tsx new file mode 100644 index 000000000..95d4fb462 --- /dev/null +++ b/src/screens/Home/Views/SongList/TagList/index.tsx @@ -0,0 +1,50 @@ +import React, { useEffect, useRef, useState } from 'react' +import { InteractionManager } from 'react-native' + +import { type Source } from '@/store/songlist/state' +import List, { type ListProps, type ListType } from './List' + + +export default () => { + const [visible, setVisible] = useState(false) + const listRef = useRef<ListType>(null) + // const [info, setInfo] = useState({ souce: 'kw', activeId: '' }) + + + useEffect(() => { + let isInited = false + const handleShow = (source: Source, id: string) => { + if (isInited) { + listRef.current?.loadTag(source, id) + } else { + requestAnimationFrame(() => { + void InteractionManager.runAfterInteractions(() => { + setVisible(true) + requestAnimationFrame(() => { + listRef.current?.loadTag(source, id) + }) + }) + }) + isInited = true + } + } + global.app_event.on('showSonglistTagList', handleShow) + + return () => { + global.app_event.off('showSonglistTagList', handleShow) + } + }, []) + + const handleTagChange: ListProps['onTagChange'] = (name, id) => { + global.app_event.hideSonglistTagList() + requestAnimationFrame(() => { + global.app_event.songlistTagInfoChange(name, id) + }) + } + + return ( + visible + ? <List ref={listRef} onTagChange={handleTagChange} /> + : null + ) +} diff --git a/src/screens/Home/Views/SongList/components/Songlist/List.tsx b/src/screens/Home/Views/SongList/components/Songlist/List.tsx new file mode 100644 index 000000000..06dc9b2d0 --- /dev/null +++ b/src/screens/Home/Views/SongList/components/Songlist/List.tsx @@ -0,0 +1,211 @@ +import React, { useRef, useState, useMemo, forwardRef, useImperativeHandle } from 'react' +import { FlatList, View, RefreshControl, type FlatListProps } from 'react-native' + +import ListItem from './ListItem' +// import { navigations } from '@/navigation' +import { type ListInfoItem } from '@/store/songlist/state' +import { useLayout } from '@/utils/hooks' +import { useTheme } from '@/store/theme/hook' +import { useI18n } from '@/lang' +import { scaleSizeW } from '@/utils/pixelRatio' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' + +type FlatListType = FlatListProps<ListInfoItem> + +// const MAX_WIDTH = scaleSizeW(110) +const MIN_WIDTH = scaleSizeW(110) +const GAP = scaleSizeW(20) + +export interface ListProps { + onRefresh: () => void + onLoadMore: () => void + onOpenDetail: (item: ListInfoItem, index: number) => void +} +export type Status = 'loading' | 'refreshing' | 'end' | 'error' | 'idle' + +export interface ListType { + setList: (list: ListInfoItem[], showSource?: boolean) => void + setStatus: (val: Status) => void +} + +export default forwardRef<ListType, ListProps>(({ onRefresh, onLoadMore, onOpenDetail }, ref) => { + const flatListRef = useRef<FlatList>(null) + const [currentList, setList] = useState<ListInfoItem[]>([]) + const [showSource, setShowSource] = useState(false) + const [status, setStatus] = useState<Status>('idle') + const { onLayout, width } = useLayout() + const theme = useTheme() + // console.log('render songlist') + + useImperativeHandle(ref, () => ({ + setList(list, showSource = false) { + // rawListRef.current = list + setList(list) + setShowSource(showSource) + }, + setStatus(val) { + setStatus(val) + }, + })) + + const handleLoadMore = () => { + switch (status) { + case 'end': + case 'loading': + case 'refreshing': return + } + onLoadMore() + } + + const renderItem: FlatListType['renderItem'] = ({ item, index }) => ( + <ListItem + item={item} + index={index} + width={itemWidth} + showSource={showSource} + onPress={onOpenDetail} + /> + ) + const getkey: FlatListType['keyExtractor'] = item => item.id + // const getItemLayout: FlatListType['getItemLayout'] = (data, index) => { + // return { length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index } + // } + const refreshControl = useMemo(() => ( + <RefreshControl + colors={[theme['c-primary']]} + // progressBackgroundColor={theme.primary} + refreshing={status == 'refreshing'} + onRefresh={onRefresh} /> + ), [status, onRefresh, theme]) + const footerComponent = useMemo(() => { + let label: FooterLabel + switch (status) { + case 'refreshing': return null + case 'loading': + label = 'list_loading' + break + case 'end': + label = 'list_end' + break + case 'error': + label = 'list_error' + break + case 'idle': + label = null + break + } + return ( + <View style={{ width: '100%' }}> + <Footer label={label} onLoadMore={onLoadMore} /> + </View> + ) + }, [onLoadMore, status]) + + + // const itemWidth = useMemo(() => { + // let itemWidth = Math.max(Math.trunc(width * 0.125), MAX_WIDTH) + // // if (itemWidth < ) + // }, [width]) + const itemWidth = useMemo(() => { + let w = width * 0.9 - GAP + let n = width / (MIN_WIDTH + GAP) + if (n > 10) n = 10 + return Math.floor(w / n) + }, [width]) + // console.log(Math.trunc(width * 0.125), itemWidth) + // console.log(itemWidth, MIN_WIDTH, GAP, width) + const rowNum = useMemo(() => Math.max(Math.floor(width / itemWidth), 2), [itemWidth, width]) + // console.log(rowNum) + const list = useMemo(() => { + const list = [...currentList] + let whiteItemNum = (list.length % rowNum) + if (whiteItemNum > 0) whiteItemNum = rowNum - whiteItemNum + for (let i = 0; i < whiteItemNum; i++) { + list.push({ + id: `white__${i}`, + play_count: '', + author: '', + name: '', + img: '', + desc: '', + // @ts-expect-error + source: '', + }) + } + return list + }, [currentList, rowNum]) + // console.log(listInfo.list.map((item) => item.id)) + + return ( + <View style={styles.container} onLayout={onLayout}> + { + width == 0 + ? null + : ( + <FlatList + key={String(rowNum)} + ref={flatListRef} + style={styles.list} + columnWrapperStyle={{ justifyContent: 'space-evenly' }} + numColumns={rowNum} + data={list} + maxToRenderPerBatch={4} + // updateCellsBatchingPeriod={80} + windowSize={8} + removeClippedSubviews={true} + // initialNumToRender={12} + renderItem={renderItem} + keyExtractor={getkey} + // getItemLayout={getItemLayout} + // onRefresh={onRefresh} + // refreshing={refreshing} + onEndReachedThreshold={0.6} + onEndReached={handleLoadMore} + refreshControl={refreshControl} + ListFooterComponent={footerComponent} + /> + ) + } + </View> + ) +}) + +type FooterLabel = 'list_loading' | 'list_end' | 'list_error' | null +const Footer = ({ label, onLoadMore }: { + label: FooterLabel + onLoadMore: () => void +}) => { + const theme = useTheme() + const t = useI18n() + const handlePress = () => { + if (label != 'list_error') return + onLoadMore() + } + return ( + label + ? ( + <View> + <Text onPress={handlePress} style={styles.footer} color={theme['c-font-label']}>{t(label)}</Text> + </View> + ) + : null + ) +} + + +const styles = createStyle({ + container: { + flex: 1, + overflow: 'hidden', + }, + list: { + flex: 1, + paddingLeft: 10, + paddingRight: 10, + }, + footer: { + textAlign: 'center', + padding: 10, + }, +}) diff --git a/src/screens/Home/Views/SongList/components/Songlist/ListItem.tsx b/src/screens/Home/Views/SongList/components/Songlist/ListItem.tsx new file mode 100644 index 000000000..c7ced8223 --- /dev/null +++ b/src/screens/Home/Views/SongList/components/Songlist/ListItem.tsx @@ -0,0 +1,83 @@ +import React, { memo } from 'react' +import { View, Image, Platform, TouchableOpacity } from 'react-native' +import { createStyle } from '@/utils/tools' +import { type ListInfoItem } from '@/store/songlist/state' +import Text from '@/components/common/Text' +import { scaleSizeW } from '@/utils/pixelRatio' +import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant' +import { useTheme } from '@/store/theme/hook' + +const gap = scaleSizeW(15) +export default memo(({ item, index, width, showSource, onPress }: { + item: ListInfoItem + index: number + showSource: boolean + width: number + onPress: (item: ListInfoItem, index: number) => void +}) => { + const theme = useTheme() + const itemWidth = width - gap + const handlePress = () => { + onPress(item, index) + } + return ( + item.source + ? ( + <View style={{ ...styles.listItem, width: itemWidth }}> + <View style={{ ...styles.listItemImg, backgroundColor: theme['c-content-background'] }}> + <TouchableOpacity activeOpacity={0.5} onPress={handlePress}> + <Image source={{ uri: item.img }} nativeID={`${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_from_${item.id}`} style={{ width: itemWidth, height: itemWidth }} borderRadius={4} /> + { showSource ? <Text style={styles.sourceLabel} size={9} color="#fff" >{item.source}</Text> : null } + </TouchableOpacity> + </View> + <TouchableOpacity activeOpacity={0.5} onPress={handlePress}> + <Text style={styles.listItemTitle} numberOfLines={ 2 }>{item.name}</Text> + </TouchableOpacity> + {/* <Text>{JSON.stringify(item)}</Text> */} + </View> + ) + : <View style={{ ...styles.listItem, width: itemWidth }} /> + ) +}) + +const styles = createStyle({ + listItem: { + // width: 90, + margin: 10, + }, + listItemImg: { + // backgroundColor: '#eee', + borderRadius: 4, + marginBottom: 5, + overflow: 'hidden', + ...Platform.select({ + ios: { + shadowColor: '#000', + shadowOffset: { + width: 0, + height: 1, + }, + shadowOpacity: 0.20, + shadowRadius: 1.41, + }, + android: { + elevation: 2, + }, + }), + }, + sourceLabel: { + paddingLeft: 4, + paddingBottom: 2, + paddingRight: 4, + position: 'absolute', + top: 0, + right: 0, + borderBottomLeftRadius: 3, + backgroundColor: 'rgba(0, 0, 0, 0.3)', + }, + listItemTitle: { + fontSize: 12, + // overflow: 'hidden', + marginBottom: 5, + }, +}) diff --git a/src/screens/Home/Views/SongList/components/Songlist/index.tsx b/src/screens/Home/Views/SongList/components/Songlist/index.tsx new file mode 100644 index 000000000..931201ad7 --- /dev/null +++ b/src/screens/Home/Views/SongList/components/Songlist/index.tsx @@ -0,0 +1,48 @@ +import React, { useRef, forwardRef, useImperativeHandle } from 'react' +import { type ListInfoItem } from '@/store/songlist/state' +// import LoadingMask, { LoadingMaskType } from '@/components/common/LoadingMask' +import List, { type ListProps, type ListType, type Status } from './List' +import { setSelectListInfo } from '@/core/songlist' +import { navigations } from '@/navigation' +import commonState from '@/store/common/state' + +export interface SonglistProps { + onRefresh: ListProps['onRefresh'] + onLoadMore: ListProps['onLoadMore'] +} +export interface SonglistType { + setList: (list: ListInfoItem[], showSource?: boolean) => void + setStatus: (val: Status) => void +} + +export default forwardRef<SonglistType, SonglistProps>(({ + onRefresh, + onLoadMore, +}, ref) => { + const listRef = useRef<ListType>(null) + // const loadingMaskRef = useRef<LoadingMaskType>(null) + + useImperativeHandle(ref, () => ({ + setList(list, showSource) { + listRef.current?.setList(list, showSource) + }, + setStatus(val) { + listRef.current?.setStatus(val) + }, + })) + + const handleOpenDetail = (item: ListInfoItem, index: number) => { + // console.log(item) + setSelectListInfo(item) + navigations.pushSonglistDetailScreen(commonState.componentIds.home as string, item.id) + } + + return ( + <List + ref={listRef} + onRefresh={onRefresh} + onLoadMore={onLoadMore} + onOpenDetail={handleOpenDetail} + /> + ) +}) diff --git a/src/screens/Home/Views/SongList/index.tsx b/src/screens/Home/Views/SongList/index.tsx new file mode 100644 index 000000000..810b7d6dd --- /dev/null +++ b/src/screens/Home/Views/SongList/index.tsx @@ -0,0 +1,53 @@ +import React, { useEffect, useRef } from 'react' +import { type DrawerLayoutAndroid } from 'react-native' +import settingState from '@/store/setting/state' +import Content from './Content' +import TagList from './TagList' +import { useTheme } from '@/store/theme/hook' +import DrawerLayoutFixed from '@/components/common/DrawerLayoutFixed' +import { COMPONENT_IDS } from '@/config/constant' +import { scaleSizeW } from '@/utils/pixelRatio' + +const MAX_WIDTH = scaleSizeW(560) + +export default () => { + const drawer = useRef<DrawerLayoutAndroid>(null) + const theme = useTheme() + + useEffect(() => { + const handleShow = () => { + requestAnimationFrame(() => { + drawer.current?.openDrawer() + }) + } + const handleHide = () => { + drawer.current?.closeDrawer() + } + + global.app_event.on('showSonglistTagList', handleShow) + global.app_event.on('hideSonglistTagList', handleHide) + + return () => { + global.app_event.off('showSonglistTagList', handleShow) + global.app_event.off('hideSonglistTagList', handleHide) + } + }, []) + + const navigationView = () => <TagList /> + // console.log('render drawer content') + + return ( + <DrawerLayoutFixed + ref={drawer} + visibleNavNames={[COMPONENT_IDS.home]} + widthPercentage={0.8} + widthPercentageMax={MAX_WIDTH} + drawerPosition={settingState.setting['common.drawerLayoutPosition']} + renderNavigationView={navigationView} + drawerBackgroundColor={theme['c-content-background']} + style={{ elevation: 1 }} + > + <Content /> + </DrawerLayoutFixed> + ) +} diff --git a/src/screens/Home/components/Aside.js b/src/screens/Home/components/Aside.js deleted file mode 100644 index a803b7e43..000000000 --- a/src/screens/Home/components/Aside.js +++ /dev/null @@ -1,172 +0,0 @@ -import React, { Component } from 'react' -import { View, StyleSheet, ScrollView, Dimensions } from 'react-native' -import { Icon } from '@/components/common/Icon' -import Button from '@/components/common/Button' - -import { STATUS } from '@/store/modules/player' - -import { connect } from '@/store' - -import { AppColors, BorderWidths } from '@/theme' - -import PlayerPortrait from './PlayerPortrait' -import PlayerLandscape from './PlayerLandscape' - -const playNextModes = [ - 'listLoop', - 'random', - 'list', - 'singleLoop', -] - -const mapStateToProps = state => ({ - homeViewPageIndex: state.common.nav.homeViewPageIndex, - common: state.common, - player: state.player, -}) - -const actions = [ - ['common', ['updateNavHomeViewPageIndex', 'setPlayNextMode']], - ['player', ['playPrev', 'playNext', 'pauseMusic', 'playMusic']], -] - -let timeout - -class Header extends Component { - state = { - menu: [ - { - icon: 'search-2', - name: '搜索', - }, - { - icon: 'album', - name: '歌单', - }, - // { - // icon: 'leaderboard', - // name: '榜单', - // }, - { - icon: 'love', - name: '收藏', - }, - // { - // icon: 'download-2', - // name: '下载', - // }, - { - icon: 'setting', - name: '设置', - }, - ], - asideWidth: 40, - orientation: 'portrait', - } - - componentDidMount() { - const window = Dimensions.get('window') - this.setState({ - orientation: window.width > window.height ? 'landscape' : 'portrait', - }) - } - - handleLayout = event => { - const { width } = event.nativeEvent.layout - const window = Dimensions.get('window') - - this.setState({ - asideWidth: width, - orientation: window.width > window.height ? 'landscape' : 'portrait', - }) - } - - toggleNextPlayMode = () => { - let index = playNextModes.indexOf(this.props.common.setting.player.togglePlayMethod) - if (++index >= playNextModes.length) index = -1 - this.props.actions.setPlayNextMode(playNextModes[index] || '') - } - - handlePress = (item, index) => { - // console.log(item) - this.props.actions.updateNavHomeViewPageIndex(index) - // console.log(this.props.homeViewPageIndex) - } - - render() { - let targetMusic = this.props.player.listInfo.list[this.props.player.playIndex] - if (timeout) { - clearInterval(timeout) - timeout = null - } - if (!targetMusic) { - targetMusic = { - img: null, - name: '~v~', - singer: '~', - } - } - // if (!targetMusic.img) { - // timeout = setInterval(() => { - // let musicInfo = this.props.player.listInfo.list[this.props.player.playIndex] - // if (musicInfo.img) { - // musicInfo.img - // } - // }, 1000) - // } - - let playModeIcon = null - switch (this.props.common.setting.player.togglePlayMethod) { - case 'listLoop': - playModeIcon = 'list-loop' - break - case 'random': - playModeIcon = 'list-random' - break - case 'list': - playModeIcon = 'list-order' - break - case 'singleLoop': - playModeIcon = 'single-loop' - break - default: - playModeIcon = 'single' - break - } - - let playIcon = this.props.player.status === STATUS.playing ? 'pause' : 'play' - // console.log(this.state.orientation) - - const playerProps = { - asideWidth: this.state.asideWidth, - targetMusic, - playIcon, - playModeIcon, - actions: this.props.actions, - menu: this.state.menu, - homeViewPageIndex: this.props.homeViewPageIndex, - togglePlay: () => { - switch (this.props.player.status) { - case STATUS.playing: - this.props.actions.pauseMusic() - break - case STATUS.pause: - this.props.actions.playMusic() - break - default: - this.props.actions.playMusic(this.props.player.playIndex) - break - } - }, - toggleNextPlayMode: () => { - this.toggleNextPlayMode() - }, - } - - return this.state.orientation == 'portrait' - ? <PlayerPortrait {...playerProps} onLayout={this.handleLayout} navPress={this.handlePress} /> - : <PlayerLandscape {...playerProps} onLayout={this.handleLayout} navPress={this.handlePress} /> - } -} - -export default connect(mapStateToProps, actions)(Header) diff --git a/src/screens/Home/components/FooterPlayer.js b/src/screens/Home/components/FooterPlayer.js deleted file mode 100644 index d85ef1875..000000000 --- a/src/screens/Home/components/FooterPlayer.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react' -import PlayerPortrait from './PlayerPortrait' - -// const playNextModes = [ -// 'listLoop', -// 'random', -// 'list', -// 'singleLoop', -// ] - -export default () => <PlayerPortrait /> diff --git a/src/screens/Home/components/Header.js b/src/screens/Home/components/Header.js deleted file mode 100644 index 289c10b3b..000000000 --- a/src/screens/Home/components/Header.js +++ /dev/null @@ -1,102 +0,0 @@ -import React, { useMemo } from 'react' -import { View, StyleSheet, TouchableOpacity } from 'react-native' -// import Button from '@/components/common/Button' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -// import { navigations } from '@/navigation' -import StatusBar from '@/components/common/StatusBar' - -const useActive = index => { - const activeIndex = useGetter('common', 'navActiveIndex') - return index === activeIndex -} - -const HeaderItem = ({ info, index, onPress }) => { - const theme = useGetter('common', 'theme') - const isActive = useActive(index) - // console.log(theme) - const components = useMemo(() => ( - <TouchableOpacity style={styles.btn} onPress={() => !isActive && onPress(index)}> - <Icon name={info.icon} style={{ ...styles.icon, color: isActive ? theme.secondary : theme.normal10 }} size={18} /> - {/* <Text style={{ ...style.btnText, color: isActive ? theme.secondary : theme.normal10 }}>{info.name}</Text> */} - </TouchableOpacity> - ), [isActive, theme, index, info.icon, onPress]) - - return components -} - -// const settingItem = { -// icon: 'setting', -// } -const Header = ({ componentId }) => { - const menus = useGetter('common', 'navMenus') - const setNavActiveIndex = useDispatch('common', 'setNavActiveIndex') - const theme = useGetter('common', 'theme') - - return ( - <View style={{ ...styles.header, backgroundColor: theme.primary }}> - <StatusBar /> - <View style={styles.container}> - {/* <View style={styles.left}> */} - {menus.map((item, index) => <HeaderItem info={item} index={index} key={item.id} onPress={setNavActiveIndex} />)} - {/* </View> - <View style={styles.right}> - <HeaderItem info={settingItem} index={-1} onPress={() => navigations.pushSettingScreen(componentId)} /> - </View> */} - </View> - </View> - ) -} - - -const styles = StyleSheet.create({ - header: { - // backgroundColor: '#fff', - height: 36 + StatusBar.currentHeight, - paddingTop: StatusBar.currentHeight, - // borderBottomWidth: BorderWidths.normal, - // borderBottomColor: AppColors.borderColor, - // Android shadow - // shadowColor: '#000', - // shadowOffset: { - // width: 0, - // height: 2, - // }, - // shadowOpacity: 0.23, - // shadowRadius: 2.62, - // elevation: 4, - }, - container: { - // width: '100%', - flexDirection: 'row', - justifyContent: 'center', - }, - left: { - flex: 1, - flexDirection: 'row', - paddingLeft: 5, - }, - btn: { - // flex: 1, - paddingLeft: 10, - paddingRight: 10, - backgroundColor: 'rgba(0,0,0,0)', - alignItems: 'center', - justifyContent: 'center', - height: 36, - }, - btnActive: { - color: 'green', - }, - btnText: { - fontSize: 16, - // color: 'white', - }, - icon: { - paddingLeft: 4, - paddingRight: 4, - }, -}) - - -export default Header diff --git a/src/screens/Home/components/HeaderLandscape.js b/src/screens/Home/components/HeaderLandscape.js deleted file mode 100644 index 02e5eaf2a..000000000 --- a/src/screens/Home/components/HeaderLandscape.js +++ /dev/null @@ -1,84 +0,0 @@ -import React, { useMemo } from 'react' -import { View, Text, StyleSheet, StatusBar, TouchableOpacity } from 'react-native' -// import Button from '@/components/common/Button' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -// import { navigations } from '@/navigation' -import { BorderWidths } from '@/theme' - -const useActive = index => { - const activeIndex = useGetter('common', 'navActiveIndex') - return index === activeIndex -} - -const HeaderItem = ({ info, index, onPress }) => { - const theme = useGetter('common', 'theme') - const isActive = useActive(index) - // console.log(theme) - const components = useMemo(() => ( - <TouchableOpacity style={styles.btn} onPress={() => !isActive && onPress(index)}> - <Icon name={info.icon} style={{ ...styles.icon, color: isActive ? theme.secondary : theme.normal10 }} size={18} /> - {/* <Text style={{ ...style.btnText, color: isActive ? theme.secondary : theme.normal10 }}>{info.name}</Text> */} - </TouchableOpacity> - ), [isActive, theme, index, info.icon, onPress]) - - return components -} - -// const settingItem = { -// icon: 'setting', -// } -const Header = ({ componentId }) => { - const menus = useGetter('common', 'navMenus') - const setNavActiveIndex = useDispatch('common', 'setNavActiveIndex') - const theme = useGetter('common', 'theme') - - return ( - <View style={{ ...styles.container, borderRightColor: theme.borderColor, backgroundColor: theme.primary }}> - {/* <View style={styles.left}> */} - {menus.map((item, index) => <HeaderItem info={item} index={index} key={item.id} onPress={setNavActiveIndex} />)} - {/* </View> - <View style={styles.right}> - <HeaderItem info={settingItem} index={-1} onPress={() => navigations.pushSettingScreen(componentId)} /> - </View> */} - </View> - ) -} - - -const styles = StyleSheet.create({ - container: { - // height: 36, - // width: '100%', - // flexDirection: 'row', - borderRightWidth: BorderWidths.normal, - justifyContent: 'center', - zIndex: 10, - }, - left: { - flex: 1, - flexDirection: 'row', - paddingLeft: 5, - }, - btn: { - // flex: 1, - padding: 15, - backgroundColor: 'rgba(0,0,0,0)', - alignItems: 'center', - justifyContent: 'center', - }, - btnActive: { - color: 'green', - }, - btnText: { - fontSize: 16, - // color: 'white', - }, - icon: { - paddingLeft: 4, - paddingRight: 4, - }, -}) - - -export default Header diff --git a/src/screens/Home/components/Main.js b/src/screens/Home/components/Main.js deleted file mode 100644 index f04a531fc..000000000 --- a/src/screens/Home/components/Main.js +++ /dev/null @@ -1,216 +0,0 @@ -import React, { useEffect, useRef, useMemo, useCallback, memo } from 'react' -import { View, StyleSheet, SafeAreaView } from 'react-native' -import PagerView from 'react-native-pager-view' -import Search from '../Search' -import SongList from '../SongList' -import Top from '../Top' -import List from '../List' -import Download from '../Download' -import Setting from '../Setting' -import { subscribe, useGetter, useDispatch, getStore } from '@/store' -import { AppColors, BorderWidths } from '@/theme' - -// import musicSearch from '../../utils/music/tx/musicSearch' - -const SearchPage = () => { - const activeIndex = useGetter('common', 'navActiveIndex') - const initedRef = useRef(false) - const search = useMemo(() => <Search />, []) - switch (activeIndex) { - case 0: - // case 1: - if (!initedRef.current) initedRef.current = true - return search - case 4: - initedRef.current = false - return null - default: - return initedRef.current ? search : null - } -} -const SongListPage = () => { - const activeIndex = useGetter('common', 'navActiveIndex') - const initedRef = useRef(false) - const songList = useMemo(() => <SongList />, []) - switch (activeIndex) { - // case 0: - case 1: - // case 2: - if (!initedRef.current) initedRef.current = true - return songList - case 4: - initedRef.current = false - return null - default: - return initedRef.current ? songList : null - } - // return activeIndex == 1 || activeIndex == 0 ? SongList : null -} -const TopPage = () => { - const activeIndex = useGetter('common', 'navActiveIndex') - const initedRef = useRef(false) - const top = useMemo(() => <Top />, []) - switch (activeIndex) { - // case 1: - case 2: - // case 3: - if (!initedRef.current) initedRef.current = true - return top - case 4: - initedRef.current = false - return null - default: - return initedRef.current ? top : null - } - // return activeIndex == 0 || activeIndex == 1 ? top : null -} -const ListPage = () => { - const activeIndex = useGetter('common', 'navActiveIndex') - const initedRef = useRef(false) - const list = useMemo(() => <List />, []) - switch (activeIndex) { - // case 2: - case 3: - // case 4: - if (!initedRef.current) initedRef.current = true - return list - default: - return initedRef.current ? list : null - } - // return activeIndex == 0 || activeIndex == 1 ? list : null -} -const SettingPage = () => { - const activeIndex = useGetter('common', 'navActiveIndex') - const initedRef = useRef(false) - const setting = useMemo(() => <Setting />, []) - switch (activeIndex) { - // case 3: - case 4: - if (!initedRef.current) initedRef.current = true - return setting - default: - return initedRef.current ? setting : null - } - // return activeIndex == 0 || activeIndex == 1 ? setting : null -} - - -const Main = () => { - const unSubscribeRef = useRef() - const pagerViewRef = useRef() - // const isScrollingRef = useRef(false) - const scrollPositionRef = useRef(-1) - const activeIndexRef = useRef(getStore().getState().common.nav.activeIndex) - const setNavActiveIndex = useDispatch('common', 'setNavActiveIndex') - - // const handlePageScroll = useCallback(({ nativeEvent }) => { - // console.log(nativeEvent.offset, activeIndexRef.current) - // // if (activeIndexRef.current == -1) return - // // if (nativeEvent.offset == 0) { - // // isScrollingRef.current = false - - // // const index = nativeEvent.position - // // if (activeIndexRef.current == index) return - // // activeIndexRef.current = index - // // setNavActiveIndex(index) - // // } else if (!isScrollingRef.current) { - // // isScrollingRef.current = true - // // } - // }, [setNavActiveIndex]) - - const onPageSelected = useCallback(({ nativeEvent }) => { - scrollPositionRef.current = nativeEvent.position - }, []) - - const onPageScrollStateChanged = useCallback(({ nativeEvent }) => { - // console.log(nativeEvent) - if (nativeEvent.pageScrollState != 'idle') return - if (scrollPositionRef.current != getStore().getState().common.nav.activeIndex) { - setNavActiveIndex(scrollPositionRef.current) - } - // if (activeIndexRef.current == -1) return - // if (nativeEvent.offset == 0) { - // isScrollingRef.current = false - - // const index = nativeEvent.position - // if (activeIndexRef.current == index) return - // activeIndexRef.current = index - // setNavActiveIndex(index) - // } else if (!isScrollingRef.current) { - // isScrollingRef.current = true - // } - }, [setNavActiveIndex]) - - const setActivePage = index => { - // console.log('setActivePage', index) - if (activeIndexRef.current == index) return - activeIndexRef.current = index - // if (index >= pagerViewRef.current.props.children.length) return - pagerViewRef.current.setPage(index) - } - - useEffect(() => { - // window.requestAnimationFrame(() => pagerViewRef.current && pagerViewRef.current.setPage(activeIndexRef.current)) - unSubscribeRef.current = subscribe('common.nav.activeIndex', ({ common: { nav } }) => { - // console.log('subscribe', nav.activeIndex) - setActivePage(nav.activeIndex) - }) - return () => { - unSubscribeRef.current() - } - }, []) - - - const component = useMemo(() => ( - <View style={{ ...styles.container }}> - <PagerView ref={pagerViewRef} - initialPage={activeIndexRef.current} - // onPageScroll={handlePageScroll} - // offscreenPageLimit={2} - onPageSelected={onPageSelected} - onPageScrollStateChanged={onPageScrollStateChanged} - style={styles.pagerView} - > - <View collapsable={false} key="1" style={styles.pageStyle}> - <SearchPage /> - </View> - <View collapsable={false} key="2" style={styles.pageStyle}> - <SongListPage /> - </View> - <View collapsable={false} key="3" style={styles.pageStyle}> - <TopPage /> - </View> - <View collapsable={false} key="4" style={styles.pageStyle}> - <ListPage /> - </View> - {/* <View collapsable={false} key="5" style={styles.pageStyle}> - <Download /> - </View> */} - <View collapsable={false} key="6" style={styles.pageStyle}> - <SettingPage /> - </View> - </PagerView> - </View> - ), [onPageSelected, onPageScrollStateChanged]) - - return component -} - -const styles = StyleSheet.create({ - container: { - flexGrow: 1, - flexShrink: 1, - // backgroundColor: '#fff', - }, - pagerView: { - flex: 1, - overflow: 'hidden', - }, - pageStyle: { - // alignItems: 'center', - // padding: 20, - }, -}) - -export default Main - diff --git a/src/screens/Home/components/Main.tsx b/src/screens/Home/components/Main.tsx new file mode 100644 index 000000000..43ca6cacf --- /dev/null +++ b/src/screens/Home/components/Main.tsx @@ -0,0 +1,59 @@ +import React, { useEffect, useMemo, useState } from 'react' +import { InteractionManager, KeyboardAvoidingView } from 'react-native' +import Search from '../Views/Search' +import SongList from '../Views/SongList' +import Mylist from '../Views/Mylist' +import Leaderboard from '../Views/Leaderboard' +import Setting from '../Views/Setting' +import { createStyle } from '@/utils/tools' +import commonState, { type InitState as CommonState } from '@/store/common/state' + + +const Main = () => { + const [id, setId] = useState(commonState.navActiveId) + + useEffect(() => { + const handleUpdate = (id: CommonState['navActiveId']) => { + requestAnimationFrame(() => { + void InteractionManager.runAfterInteractions(() => { + setId(id) + }) + }) + } + global.state_event.on('navActiveIdUpdated', handleUpdate) + return () => { + global.state_event.off('navActiveIdUpdated', handleUpdate) + } + }, []) + + const component = useMemo(() => { + switch (id) { + case 'nav_songlist': return <SongList /> + case 'nav_top': return <Leaderboard /> + case 'nav_love': return <Mylist /> + case 'nav_setting': return <Setting /> + case 'nav_search': + default: return <Search /> + } + }, [id]) + + return ( + <KeyboardAvoidingView + behavior="padding" + style={styles.container} + > + {component} + </KeyboardAvoidingView> + ) +} + +const styles = createStyle({ + container: { + flexGrow: 1, + flexShrink: 1, + // backgroundColor: '#fff', + }, +}) + +export default Main + diff --git a/src/screens/Home/components/PlayerBar/components/ControlBtn.tsx b/src/screens/Home/components/PlayerBar/components/ControlBtn.tsx new file mode 100644 index 000000000..d1b1ce3cc --- /dev/null +++ b/src/screens/Home/components/PlayerBar/components/ControlBtn.tsx @@ -0,0 +1,63 @@ +import React from 'react' +import { TouchableOpacity } from 'react-native' +import { Icon } from '@/components/common/Icon' +import { useIsPlay } from '@/store/player/hook' +import { useTheme } from '@/store/theme/hook' +import { playNext, togglePlay } from '@/core/player/player' +import { createStyle } from '@/utils/tools' + +const BTN_SIZE = 24 +const handlePlayNext = () => { + void playNext() +} + +const PlayNextBtn = () => { + const theme = useTheme() + + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={handlePlayNext}> + <Icon name='nextMusic' color={theme['c-button-font']} size={BTN_SIZE} /> + </TouchableOpacity> + ) +} + +const TogglePlayBtn = () => { + const isPlay = useIsPlay() + const theme = useTheme() + + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={togglePlay}> + <Icon name={isPlay ? 'pause' : 'play'} color={theme['c-button-font']} size={BTN_SIZE} /> + </TouchableOpacity> + ) +} + +export default () => { + return ( + <> + {/* <TouchableOpacity activeOpacity={0.5} onPress={toggleNextPlayMode}> + <Text style={{ ...styles.cotrolBtn }}> + <Icon name={playModeIcon} style={{ color: theme.secondary10 }} size={18} /> + </Text> + </TouchableOpacity> + */} + {/* {btnPrev} */} + <TogglePlayBtn /> + <PlayNextBtn /> + </> + ) +} + + +const styles = createStyle({ + cotrolBtn: { + width: 46, + height: 46, + justifyContent: 'center', + alignItems: 'center', + + // backgroundColor: '#ccc', + shadowOpacity: 1, + textShadowRadius: 1, + }, +}) diff --git a/src/screens/Home/components/PlayerBar/components/Pic.tsx b/src/screens/Home/components/PlayerBar/components/Pic.tsx new file mode 100644 index 000000000..e54c105c6 --- /dev/null +++ b/src/screens/Home/components/PlayerBar/components/Pic.tsx @@ -0,0 +1,83 @@ +import React, { memo } from 'react' +import { View, Image, TouchableOpacity } from 'react-native' +import { navigations } from '@/navigation' +import { usePlayerMusicInfo } from '@/store/player/hook' +import { useTheme } from '@/store/theme/hook' +import { scaleSizeH } from '@/utils/pixelRatio' +import { createStyle } from '@/utils/tools' +import { BorderRadius } from '@/theme' +import commonState from '@/store/common/state' +import playerState from '@/store/player/state' +import Text from '@/components/common/Text' +import { LIST_IDS, NAV_SHEAR_NATIVE_IDS } from '@/config/constant' + +const PIC_HEIGHT = scaleSizeH(46) + +const styles = createStyle({ + // content: { + // marginBottom: 3, + // },/ + emptyPic: { + borderRadius: BorderRadius.normal, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + }, + text: { + paddingLeft: 2, + }, +}) + +const EmptyPic = memo(() => { + const theme = useTheme() + return ( + <View nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={{ ...styles.emptyPic, width: PIC_HEIGHT, height: PIC_HEIGHT, backgroundColor: theme['c-primary-light-900-alpha-200'] }}> + <Text size={20} color={theme['c-primary-light-400-alpha-200']}>L</Text> + <Text size={20} color={theme['c-primary-light-400-alpha-200']} style={styles.text}>X</Text> + </View> + ) +}) + +export default () => { + const musicInfo = usePlayerMusicInfo() + const handlePress = () => { + // console.log('') + // console.log(playMusicInfo) + if (!musicInfo.id) return + navigations.pushPlayDetailScreen(commonState.componentIds.home as string) + + // toast(global.i18n.t('play_detail_todo_tip'), 'long') + } + + const handleLongPress = () => { + const listId = playerState.playMusicInfo.listId + if (!listId || listId == LIST_IDS.DOWNLOAD) return + global.app_event.jumpListPosition() + } + + // console.log('render pic') + + return ( + <TouchableOpacity onLongPress={handleLongPress} onPress={handlePress} activeOpacity={0.7} > + { + musicInfo.pic + ? ( + <Image source={{ uri: musicInfo.pic }} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} progressiveRenderingEnabled={true} borderRadius={2} style={{ + // ...styles.playInfoImg, + // backgroundColor: theme.primary, + width: PIC_HEIGHT, + height: PIC_HEIGHT, + }} /> + ) + : <EmptyPic /> + } + </TouchableOpacity> + ) +} + + +// const styles = StyleSheet.create({ +// playInfoImg: { + +// }, +// }) diff --git a/src/screens/Home/components/PlayerBar/components/PlayInfo.tsx b/src/screens/Home/components/PlayerBar/components/PlayInfo.tsx new file mode 100644 index 000000000..6c3ef2ebd --- /dev/null +++ b/src/screens/Home/components/PlayerBar/components/PlayInfo.tsx @@ -0,0 +1,79 @@ +import React, { memo, useState } from 'react' +import { View } from 'react-native' + +import Progress from '@/components/player/Progress' +import Status from './Status' +import { useProgress } from '@/store/player/hook' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' +import { COMPONENT_IDS } from '@/config/constant' +import { usePageVisible } from '@/store/common/hook' + +const FONT_SIZE = 13 + +const PlayTimeCurrent = ({ timeStr }: { timeStr: string }) => { + const theme = useTheme() + // console.log(timeStr) + return <Text size={FONT_SIZE} color={theme['c-500']}>{timeStr}</Text> +} + +const PlayTimeMax = memo(({ timeStr }: { timeStr: string }) => { + const theme = useTheme() + return <Text size={FONT_SIZE} color={theme['c-500']}>{timeStr}</Text> +}) + +export default () => { + const theme = useTheme() + const [autoUpdate, setAutoUpdate] = useState(true) + const { maxPlayTimeStr, nowPlayTimeStr, progress, maxPlayTime } = useProgress(autoUpdate) + usePageVisible([COMPONENT_IDS.home], setAutoUpdate) + + return ( + <> + <View style={styles.progress}><Progress progress={progress} duration={maxPlayTime} /></View> + <View style={styles.info}> + {/* <MusicName /> */} + <View style={styles.status}> + <Status autoUpdate={autoUpdate} /> + </View> + <View style={{ flexGrow: 0, flexShrink: 0, flexDirection: 'row' }} > + <PlayTimeCurrent timeStr={nowPlayTimeStr} /> + <Text size={FONT_SIZE} color={theme['c-500']}> / </Text> + <PlayTimeMax timeStr={maxPlayTimeStr} /> + </View> + </View> + </> + ) +} + + +const styles = createStyle({ + progress: { + height: 16, + // flexGrow: 0, + flexShrink: 0, + // flexDirection: 'column', + justifyContent: 'center', + // alignItems: 'center', + // marginBottom: -1, + // backgroundColor: '#ccc', + // overflow: 'hidden', + // height: + // position: 'absolute', + // width: '100%', + // top: 0, + }, + info: { + // flex: 1, + flexDirection: 'row', + justifyContent: 'space-between', + // alignItems: 'center', + // backgroundColor: '#ccc', + }, + status: { + flexGrow: 1, + flexShrink: 1, + paddingRight: 5, + }, +}) diff --git a/src/screens/Home/components/PlayerBar/components/Status.tsx b/src/screens/Home/components/PlayerBar/components/Status.tsx new file mode 100644 index 000000000..a77bfdc92 --- /dev/null +++ b/src/screens/Home/components/PlayerBar/components/Status.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import { useLrcPlay } from '@/plugins/lyric' +import { useIsPlay, useStatusText } from '@/store/player/hook' +// import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' + + +export default ({ autoUpdate }: { autoUpdate: boolean }) => { + const { text } = useLrcPlay(autoUpdate) + const statusText = useStatusText() + const isPlay = useIsPlay() + // console.log('render status') + + const status = isPlay ? text : statusText + + return <Text numberOfLines={1} size={12}>{status}</Text> +} + +// const styles = createStyle({ +// text: { +// fontSize: 10, +// }, +// }) diff --git a/src/screens/Home/components/PlayerBar/components/Title.tsx b/src/screens/Home/components/PlayerBar/components/Title.tsx new file mode 100644 index 000000000..908038a1b --- /dev/null +++ b/src/screens/Home/components/PlayerBar/components/Title.tsx @@ -0,0 +1,66 @@ +import React from 'react' +import { TouchableOpacity } from 'react-native' +import { navigations } from '@/navigation' +import { usePlayerMusicInfo } from '@/store/player/hook' +// import { toast } from '@/utils/tools' +import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' +import commonState from '@/store/common/state' +import playerState from '@/store/player/state' +import Text from '@/components/common/Text' +import { LIST_IDS } from '@/config/constant' + + +export default () => { + // const { t } = useTranslation() + const musicInfo = usePlayerMusicInfo() + const downloadFileName = useSettingValue('download.fileName') + const theme = useTheme() + + const handlePress = () => { + // console.log('') + // console.log(playMusicInfo) + if (!musicInfo.id) return + navigations.pushPlayDetailScreen(commonState.componentIds.home as string) + // toast(global.i18n.t('play_detail_todo_tip'), 'long') + } + + const handleLongPress = () => { + const listId = playerState.playMusicInfo.listId + if (!listId || listId == LIST_IDS.DOWNLOAD) return + global.app_event.jumpListPosition() + } + // console.log('render title') + + const title = musicInfo.id ? downloadFileName.replace('歌手', musicInfo.singer).replace('歌名', musicInfo.name) : '' + // console.log(playMusicInfo) + return ( + <TouchableOpacity style={{ width: '100%' }} onLongPress={handleLongPress} onPress={handlePress} activeOpacity={0.7} > + <Text color={theme['c-font-label']} numberOfLines={1}>{title}</Text> + </TouchableOpacity> + ) +} +// const Singer = () => { +// const playMusicInfo = useGetter('player', 'playMusicInfo') +// return ( +// <View style={{ flexGrow: 0, flexShrink: 0 }}> +// <Text style={{ width: '100%', color: AppColors.normal }} numberOfLines={1}> +// {playMusicInfo ? playMusicInfo.musicInfo.singer : ''} +// </Text> +// </View> +// ) +// } +// const MusicName = () => { +// const playMusicInfo = useGetter('player', 'playMusicInfo') +// return ( +// <View style={{ flexGrow: 0, flexShrink: 1 }}> +// <Text style={{ width: '100%', color: AppColors.normal }} numberOfLines={1}> +// {playMusicInfo ? playMusicInfo.musicInfo.name : '^-^'} +// </Text> +// </View> +// ) +// } + +// const styles = StyleSheet.create({ + +// }) diff --git a/src/screens/Home/components/PlayerPortrait/index.js b/src/screens/Home/components/PlayerBar/index.tsx similarity index 51% rename from src/screens/Home/components/PlayerPortrait/index.js rename to src/screens/Home/components/PlayerBar/index.tsx index 0df952107..347657e81 100644 --- a/src/screens/Home/components/PlayerPortrait/index.js +++ b/src/screens/Home/components/PlayerBar/index.tsx @@ -1,47 +1,46 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { View, Text, StyleSheet } from 'react-native' -import { useLayout, useKeyboard } from '@/utils/hooks' -import { useGetter, useDispatch } from '@/store' +import React, { memo } from 'react' +import { View } from 'react-native' +// import { useKeyboard } from '@/utils/hooks' import Pic from './components/Pic' import Title from './components/Title' import PlayInfo from './components/PlayInfo' import ControlBtn from './components/ControlBtn' +import { createStyle } from '@/utils/tools' +// import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' export default memo(() => { // const { onLayout, ...layout } = useLayout() - const { keyboardShown } = useKeyboard() - const theme = useGetter('common', 'theme') - const autoHidePlayBar = useGetter('common', 'autoHidePlayBar') - const componentIds = useGetter('common', 'componentIds') + // const { keyboardShown } = useKeyboard() + const theme = useTheme() + // const autoHidePlayBar = useSettingValue('common.autoHidePlayBar') + // console.log('render pb') - const playerComponent = useMemo(() => ( - <View style={{ ...styles.container, backgroundColor: theme.primary }}> - <View style={styles.left} elevation={1}><Pic /></View> + return ( + <View style={{ ...styles.container, backgroundColor: theme['c-content-background'] }}> + <Pic /> <View style={styles.center}> - <View style={{ ...styles.row, justifyContent: 'space-between', fontSize: 12 }}> - <Title /> - {/* <PlayTime /> */} - </View> - {(componentIds.playDetail || componentIds.songlistDetail) ? null : <PlayInfo />} + <Title /> + {/* <View style={{ ...styles.row, justifyContent: 'space-between' }}> + <PlayTime /> + </View> */} + <PlayInfo /> </View> <View style={styles.right}> <ControlBtn /> </View> </View> - ), [theme, componentIds]) - - // console.log(layout) - - return autoHidePlayBar && keyboardShown ? null : playerComponent + ) }) -const styles = StyleSheet.create({ + +const styles = createStyle({ container: { width: '100%', - // height: 59, + // height: 100, // paddingTop: progressContentPadding, // marginTop: -progressContentPadding, // backgroundColor: 'rgba(0, 0, 0, .1)', @@ -58,7 +57,7 @@ const styles = StyleSheet.create({ elevation: 10, }, left: { - borderRadius: 3, + // borderRadius: 3, flexGrow: 0, flexShrink: 0, }, @@ -67,7 +66,7 @@ const styles = StyleSheet.create({ flexGrow: 1, flexShrink: 1, paddingLeft: 5, - height: '100%', + // height: '100%', // justifyContent: 'space-evenly', // height: 48, }, @@ -79,9 +78,9 @@ const styles = StyleSheet.create({ paddingLeft: 5, paddingRight: 5, }, - row: { - flexDirection: 'row', - flexGrow: 0, - flexShrink: 0, - }, + // row: { + // flexDirection: 'row', + // flexGrow: 0, + // flexShrink: 0, + // }, }) diff --git a/src/screens/Home/components/PlayerLandscape.js b/src/screens/Home/components/PlayerLandscape.js deleted file mode 100644 index d770d5bed..000000000 --- a/src/screens/Home/components/PlayerLandscape.js +++ /dev/null @@ -1,125 +0,0 @@ -import React from 'react' -import { View, ScrollView, Text, StyleSheet, Image, TouchableOpacity, useGetter } from 'react-native' -import Button from '@/components/common/Button' -import { Icon } from '@/components/common/Icon' - -export default ({ - asideWidth, targetMusic, toggleNextPlayMode, - togglePlay, playIcon, playModeIcon, actions, - menu, homeViewPageIndex, onLayout = () => {}, navPress = () => {}, -}) => { - const theme = useGetter('common', 'theme') - const navBtnWidth = asideWidth * 0.5 - 0.1 - const imgWidth = asideWidth * 0.3 - const paddingBottom = asideWidth * 0.05 - const btnStyle = { - width: asideWidth * 0.3, - height: asideWidth * 0.32, - lineHeight: asideWidth * 0.32, - } - const navIconSize = asideWidth * 0.15 - const iconSize = asideWidth * 0.15 - - return <View style={{ ...styles.header, backgroundColor: theme.primary }} onLayout={onLayout}> - <ScrollView style={{ ...styles.navBtnContainer }}> - <View style={{ width: '100%', flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between' }}> - { - menu.map((item, index) => - <Button style={{ ...styles.btn, width: navBtnWidth, height: navBtnWidth }} key={index} onPress={() => navPress(item, index)}> - <Icon name={item.icon} style={{ color: homeViewPageIndex == index ? theme.secondary : theme.normal10 }} size={navIconSize} /> - </Button>) - } - </View> - </ScrollView> - - <View style={{ flexGrow: 0, flexShrink: 1, paddingBottom: paddingBottom, paddingTop: paddingBottom / 2 }}> - <View style={{ flexShrink: 0, width: '100%', flexDirection: 'row', flexWrap: 'wrap' }}> - <TouchableOpacity activeOpacity={0.5} onPress={toggleNextPlayMode}> - <Text style={{ ...styles.cotrolBtn, ...btnStyle }}> - <Icon name={playModeIcon} style={{ color: theme.secondary10 }} size={iconSize} /> - </Text> - </TouchableOpacity> - </View> - <View style={{ flexShrink: 0, width: '100%', flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-evenly' }}> - <TouchableOpacity activeOpacity={0.5} onPress={actions.playPrev}> - <Text style={{ ...styles.cotrolBtn, ...btnStyle, transform: [{ rotate: '180deg' }] }}> - <Icon name='nextMusic' style={{ color: theme.secondary10 }} size={iconSize} /> - </Text> - </TouchableOpacity> - <TouchableOpacity activeOpacity={0.5} onPress={togglePlay}> - <Text style={{ ...styles.cotrolBtn, ...btnStyle }}> - <Icon name={playIcon} style={{ color: theme.secondary10 }} size={iconSize} /> - </Text> - </TouchableOpacity> - <TouchableOpacity activeOpacity={0.5} onPress={actions.playNext}> - <Text style={{ ...styles.cotrolBtn, ...btnStyle }}> - <Icon name='nextMusic' style={{ color: theme.secondary10 }} size={iconSize} /> - </Text> - </TouchableOpacity> - </View> - <View style={{ flexDirection: 'row', paddingLeft: paddingBottom }}> - <View style={{ borderRadius: 4, marginTop: paddingBottom / 2 }} elevation={1}> - <Image source={{ uri: targetMusic.img }} borderRadius={4} style={{ - ...styles.playInfoImg, - backgroundColor: theme.primary, - width: imgWidth, - height: imgWidth, - }} /> - </View> - <View style={{ flexShrink: 1, flexGrow: 1, flexDirection: 'column', justifyContent: 'space-evenly', paddingLeft: paddingBottom, paddingRight: paddingBottom }}> - <Text style={{ width: '100%', fontSize: 12 }} numberOfLines={1}>{targetMusic.singer}</Text> - <Text style={{ width: '100%', fontSize: 12 }} numberOfLines={1}>{targetMusic.name}</Text> - </View> - </View> - </View> - </View> -} - - -const styles = StyleSheet.create({ - header: { - width: '18%', - minWidth: 40, - height: '100%', - // paddingTop: StatusBar.currentHeight, - // borderRightWidth: 0.4, - // borderLeftWidth: 0.4, - // borderRightColor: '#eee', - // Android shadow - // shadowColor: '#000', - // shadowOffset: { - // width: 0, - // height: 2, - // }, - // shadowOpacity: 0.23, - // shadowRadius: 2.62, - // elevation: 2, - justifyContent: 'space-between', - }, - container: { - // width: '100%', - flexDirection: 'column', - }, - navBtnContainer: { - flexGrow: 0, - flexShrink: 1, - }, - btn: { - // flex: 1, - backgroundColor: 'rgba(0,0,0,0)', - alignItems: 'center', - justifyContent: 'center', - }, - - cotrolBtn: { - width: 32, - height: 32, - textAlign: 'center', - lineHeight: 32, - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 2, - // textShadowOffset: { width: 2, height: 2 }, - }, -}) diff --git a/src/screens/Home/components/PlayerPortrait/components/ControlBtn.js b/src/screens/Home/components/PlayerPortrait/components/ControlBtn.js deleted file mode 100644 index df8238133..000000000 --- a/src/screens/Home/components/PlayerPortrait/components/ControlBtn.js +++ /dev/null @@ -1,84 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, StyleSheet, TouchableOpacity } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import { STATUS } from '@/store/modules/player' - - -export default () => { - const playStatus = useGetter('player', 'status') - const playNext = useDispatch('player', 'playNext') - // const playPrev = useDispatch('player', 'playPrev') - // const playMusicInfo = useGetter('player', 'playMusicInfo') - const pauseMusic = useDispatch('player', 'pauseMusic') - const playMusic = useDispatch('player', 'playMusic') - const theme = useGetter('common', 'theme') - - // const togglePlayMethod = useGetter('common', 'togglePlayMethod') - // const setPlayNextMode = useDispatch('common', 'setPlayNextMode') - // const toggleNextPlayMode = useCallback(() => { - // let index = playNextModes.indexOf(togglePlayMethod) - // if (++index >= playNextModes.length) index = -1 - // setPlayNextMode(playNextModes[index] || '') - // }, [setPlayNextMode, togglePlayMethod, playNextModes]) - - // const btnPrev = useMemo(() => ( - // <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playPrev}> - // <Icon name='prevMusic' style={{ color: theme.secondary10 }} size={20} /> - // </TouchableOpacity> - // ), [playPrev, theme]) - - const togglePlay = useCallback(playStatus => { - switch (playStatus) { - case STATUS.playing: - pauseMusic() - break - case STATUS.pause: - case STATUS.stop: - case STATUS.none: - playMusic() - break - // default: - // playMusic(playMusicInfo) - // break - } - }, []) - const btnPlay = useMemo(() => ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={() => togglePlay(playStatus)}> - <Icon name={playStatus == STATUS.playing ? 'pause' : 'play'} style={{ color: theme.secondary10 }} size={24} /> - </TouchableOpacity> - ), [playStatus, theme, togglePlay]) - const btnNext = useMemo(() => ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playNext}> - <Icon name='nextMusic' style={{ color: theme.secondary10 }} size={24} /> - </TouchableOpacity> - ), [playNext, theme]) - - return ( - <> - {/* <TouchableOpacity activeOpacity={0.5} onPress={toggleNextPlayMode}> - <Text style={{ ...styles.cotrolBtn }}> - <Icon name={playModeIcon} style={{ color: theme.secondary10 }} size={18} /> - </Text> - </TouchableOpacity> - */} - {/* {btnPrev} */} - {btnPlay} - {btnNext} - </> - ) -} - - -const styles = StyleSheet.create({ - cotrolBtn: { - width: 50, - height: 50, - justifyContent: 'center', - alignItems: 'center', - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 1, - }, -}) diff --git a/src/screens/Home/components/PlayerPortrait/components/Pic.js b/src/screens/Home/components/PlayerPortrait/components/Pic.js deleted file mode 100644 index 454e5df23..000000000 --- a/src/screens/Home/components/PlayerPortrait/components/Pic.js +++ /dev/null @@ -1,56 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect, useState } from 'react' -import { View, Text, StyleSheet, Image, TouchableOpacity } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import { toast } from '@/utils/tools' -import { useTranslation } from '@/plugins/i18n' -import { LIST_ID_PLAY_TEMP, LIST_ID_PLAY_LATER, NAV_VIEW_NAMES } from '@/config/constant' -import { navigations } from '@/navigation' - -export default () => { - const playMusicInfo = useGetter('player', 'playMusicInfo') - const theme = useGetter('common', 'theme') - const setNavActiveIndex = useDispatch('common', 'setNavActiveIndex') - const setPrevSelectListId = useDispatch('common', 'setPrevSelectListId') - const setJumpPosition = useDispatch('list', 'setJumpPosition') - // const { t } = useTranslation() - const componentIds = useGetter('common', 'componentIds') - const musicInfo = useMemo(() => { - return (playMusicInfo && playMusicInfo.musicInfo) || {} - }, [playMusicInfo]) - const handlePress = useCallback(() => { - // console.log('') - // console.log(playMusicInfo) - if (!playMusicInfo) return - navigations.pushPlayDetailScreen(componentIds.home, musicInfo.songmid) - // toast(t('play_detail_todo_tip'), 'long') - }, [componentIds.home, musicInfo, playMusicInfo]) - - const handleLongPress = useCallback(() => { - if (!playMusicInfo || playMusicInfo.listId == LIST_ID_PLAY_TEMP || playMusicInfo.listId == LIST_ID_PLAY_LATER) return - setNavActiveIndex(NAV_VIEW_NAMES.list) - setPrevSelectListId(playMusicInfo.listId) - global.requestAnimationFrame(() => { - setJumpPosition(true) - }) - }, [playMusicInfo, setJumpPosition, setNavActiveIndex, setPrevSelectListId]) - - - const component = useMemo(() => ( - <TouchableOpacity onLongPress={handleLongPress} onPress={handlePress} activeOpacity={0.7} > - <Image source={{ uri: musicInfo.img }} nativeID={`pic${musicInfo.songmid}`} progressiveRenderingEnabled={true} borderRadius={2} style={{ - // ...styles.playInfoImg, - backgroundColor: theme.primary, - width: 50, - height: 50, - }} /> - </TouchableOpacity> - ), [handleLongPress, handlePress, musicInfo, theme]) - return component -} - - -// const styles = StyleSheet.create({ -// playInfoImg: { - -// }, -// }) diff --git a/src/screens/Home/components/PlayerPortrait/components/PlayInfo.js b/src/screens/Home/components/PlayerPortrait/components/PlayInfo.js deleted file mode 100644 index 83878c373..000000000 --- a/src/screens/Home/components/PlayerPortrait/components/PlayInfo.js +++ /dev/null @@ -1,56 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, StyleSheet, View } from 'react-native' -import { usePlayTime } from '@/utils/hooks' -import { useGetter } from '@/store' - -import Progress from '@/components/player/Progress' -import Status from './Status' - -const PlayTimeCurrent = ({ timeStr }) => { - const theme = useGetter('common', 'theme') - // console.log(timeStr) - return <Text style={{ fontSize: 12, color: theme.normal10 }}>{timeStr}</Text> -} - -const PlayTimeMax = memo(({ timeStr }) => { - const theme = useGetter('common', 'theme') - return <Text style={{ fontSize: 12, color: theme.normal10 }}>{timeStr}</Text> -}) - -export default () => { - const { curTimeStr, maxTimeStr, progress, bufferedProgress, duration } = usePlayTime() - const theme = useGetter('common', 'theme') - - return ( - <> - <View style={styles.progress}><Progress progress={progress} bufferedProgress={bufferedProgress} duration={duration} /></View> - <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}> - {/* <MusicName /> */} - <View style={{ flexGrow: 1, flexShrink: 1, paddingRight: 5 }} > - <Status /> - </View> - <View style={{ flexGrow: 0, flexShrink: 0, flexDirection: 'row' }} > - <PlayTimeCurrent timeStr={curTimeStr} /> - <Text style={{ fontSize: 12, color: theme.normal }}> / </Text> - <PlayTimeMax timeStr={maxTimeStr} /> - </View> - </View> - </> - ) -} - - -const styles = StyleSheet.create({ - progress: { - height: 14, - flexGrow: 1, - flexShrink: 0, - flexDirection: 'column', - justifyContent: 'center', - marginBottom: -2, - // height: - // position: 'absolute', - // width: '100%', - // top: 0, - }, -}) diff --git a/src/screens/Home/components/PlayerPortrait/components/Status.js b/src/screens/Home/components/PlayerPortrait/components/Status.js deleted file mode 100644 index dc515d6d7..000000000 --- a/src/screens/Home/components/PlayerPortrait/components/Status.js +++ /dev/null @@ -1,25 +0,0 @@ -import React, { memo, useMemo } from 'react' -import { Text } from 'react-native' -import { useGetter } from '@/store' -import { STATUS } from '@/store/modules/player' -import { useLrcPlay } from '@/plugins/lyric' - - -export default memo(() => { - const theme = useGetter('common', 'theme') - const playStatus = useGetter('player', 'status') - const statusText = useGetter('player', 'statusText') - const { text } = useLrcPlay() - const status = useMemo(() => playStatus == STATUS.playing - ? text - : ( - playStatus == STATUS.pause && text - ? text - : statusText - ), [playStatus, statusText, text]) - return <Text numberOfLines={1} style={{ fontSize: 10, color: theme.normal10 }}>{status}</Text> -}) - -// const styles = StyleSheet.create({ - -// }) diff --git a/src/screens/Home/components/PlayerPortrait/components/Title.js b/src/screens/Home/components/PlayerPortrait/components/Title.js deleted file mode 100644 index 96d8226e5..000000000 --- a/src/screens/Home/components/PlayerPortrait/components/Title.js +++ /dev/null @@ -1,74 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, StyleSheet, TouchableOpacity } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import { navigations } from '@/navigation' -import { LIST_ID_PLAY_TEMP, LIST_ID_PLAY_LATER, NAV_VIEW_NAMES } from '@/config/constant' - - -export default () => { - const playMusicInfo = useGetter('player', 'playMusicInfo') - const theme = useGetter('common', 'theme') - const setNavActiveIndex = useDispatch('common', 'setNavActiveIndex') - const setPrevSelectListId = useDispatch('common', 'setPrevSelectListId') - const setJumpPosition = useDispatch('list', 'setJumpPosition') - // const { t } = useTranslation() - const componentIds = useGetter('common', 'componentIds') - const musicInfo = useMemo(() => { - return (playMusicInfo && playMusicInfo.musicInfo) || {} - }, [playMusicInfo]) - const handlePress = useCallback(() => { - // console.log('') - // console.log(playMusicInfo) - if (!playMusicInfo) return - navigations.pushPlayDetailScreen(componentIds.home, musicInfo.songmid) - // toast(t('play_detail_todo_tip'), 'long') - }, [componentIds.home, musicInfo, playMusicInfo]) - - const handleLongPress = useCallback(() => { - if (!playMusicInfo || playMusicInfo.listId == LIST_ID_PLAY_TEMP || playMusicInfo.listId == LIST_ID_PLAY_LATER) return - setNavActiveIndex(NAV_VIEW_NAMES.list) - setPrevSelectListId(playMusicInfo.listId) - global.requestAnimationFrame(() => { - setJumpPosition(true) - }) - }, [playMusicInfo, setJumpPosition, setNavActiveIndex, setPrevSelectListId]) - - const downloadFileName = useGetter('common', 'downloadFileName') - const title = useMemo(() => { - let title = '^-^' - if (playMusicInfo && playMusicInfo.musicInfo) { - title = downloadFileName.replace('歌手', playMusicInfo.musicInfo.singer).replace('歌名', playMusicInfo.musicInfo.name) - } - return title - }, [downloadFileName, playMusicInfo]) - // console.log(playMusicInfo) - return ( - <TouchableOpacity style={{ width: '100%' }} onLongPress={handleLongPress} onPress={handlePress} activeOpacity={0.7} > - <Text style={{ fontSize: 14, color: theme.normal }} numberOfLines={1}>{title}</Text> - </TouchableOpacity> - ) -} -// const Singer = () => { -// const playMusicInfo = useGetter('player', 'playMusicInfo') -// return ( -// <View style={{ flexGrow: 0, flexShrink: 0 }}> -// <Text style={{ width: '100%', color: AppColors.normal }} numberOfLines={1}> -// {playMusicInfo ? playMusicInfo.musicInfo.singer : ''} -// </Text> -// </View> -// ) -// } -// const MusicName = () => { -// const playMusicInfo = useGetter('player', 'playMusicInfo') -// return ( -// <View style={{ flexGrow: 0, flexShrink: 1 }}> -// <Text style={{ width: '100%', color: AppColors.normal }} numberOfLines={1}> -// {playMusicInfo ? playMusicInfo.musicInfo.name : '^-^'} -// </Text> -// </View> -// ) -// } - -// const styles = StyleSheet.create({ - -// }) diff --git a/src/screens/Home/index.js b/src/screens/Home/index.js deleted file mode 100644 index ea85ca3d5..000000000 --- a/src/screens/Home/index.js +++ /dev/null @@ -1,58 +0,0 @@ -import React, { useEffect } from 'react' - -import { View, StyleSheet } from 'react-native' -import Header from './components/Header' -import HeaderLandscape from './components/HeaderLandscape' -// import Aside from './components/Aside' -import Main from './components/Main' -import FooterPlayer from './components/FooterPlayer' -import { useGetter, useDispatch } from '@/store' -import { useDimensions } from '@/utils/hooks' -import StatusBar from '@/components/common/StatusBar' - -const styles = StyleSheet.create({ - container: { - flex: 1, - paddingTop: StatusBar.currentHeight, - flexDirection: 'row', - }, -}) - -const Landscape = (props) => { - return ( - <> - <StatusBar /> - <View style={{ ...styles.container, backgroundColor: props.theme.primary }}> - <HeaderLandscape componentId={props.componentId} /> - <View style={{ flex: 1, flexDirection: 'column', height: '100%', overflow: 'hidden' }}> - {/* <Aside /> */} - <Main /> - <FooterPlayer /> - </View> - </View> - </> - ) -} - -export default (props) => { - const theme = useGetter('common', 'theme') - const { window } = useDimensions() - const setComponentId = useDispatch('common', 'setComponentId') - useEffect(() => { - setComponentId({ name: 'home', id: props.componentId }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - return ( - window.height > window.width - ? <> - <Header componentId={props.componentId} /> - <View style={{ flex: 1, flexDirection: 'column', height: '100%', backgroundColor: theme.primary }}> - {/* <Aside /> */} - <Main /> - <FooterPlayer /> - </View> - </> - : <Landscape componentId={props.componentId} theme={theme} /> - ) -} diff --git a/src/screens/Home/index.tsx b/src/screens/Home/index.tsx new file mode 100644 index 000000000..a2d641985 --- /dev/null +++ b/src/screens/Home/index.tsx @@ -0,0 +1,30 @@ +import React, { useEffect } from 'react' +import { useDimensions } from '@/utils/hooks' +import PageContent from '@/components/PageContent' +import { setComponentId } from '@/core/common' +import { COMPONENT_IDS } from '@/config/constant' +import Vertical from './Vertical' +import Horizontal from './Horizontal' + +interface Props { + componentId: string +} + + +export default ({ componentId }: Props) => { + const { window } = useDimensions() + useEffect(() => { + setComponentId(COMPONENT_IDS.home, componentId) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + return ( + <PageContent> + { + window.height > window.width + ? <Vertical /> + : <Horizontal /> + } + </PageContent> + ) +} diff --git a/src/screens/PlayDetail/Portrait/Lyric.js b/src/screens/PlayDetail/Horizontal/Lyric.tsx similarity index 56% rename from src/screens/PlayDetail/Portrait/Lyric.js rename to src/screens/PlayDetail/Horizontal/Lyric.tsx index 468a965e4..136f7e5fa 100644 --- a/src/screens/PlayDetail/Portrait/Lyric.js +++ b/src/screens/PlayDetail/Horizontal/Lyric.tsx @@ -1,52 +1,61 @@ -import React, { memo, useMemo, useCallback, useEffect, useRef } from 'react' -import { View, Text, StyleSheet, FlatList } from 'react-native' -import { useGetter } from '@/store' +import React, { memo, useMemo, useEffect, useRef } from 'react' +import { View, FlatList, type FlatListProps } from 'react-native' // import { useLayout } from '@/utils/hooks' -import { useLrcPlay, useLrcSet } from '@/plugins/lyric' +import { type Line, useLrcPlay, useLrcSet } from '@/plugins/lyric' +import { createStyle } from '@/utils/tools' +// import { useComponentIds } from '@/store/common/hook' +import { useTheme } from '@/store/theme/hook' +import { useSettingValue } from '@/store/setting/hook' +import Text from '@/components/common/Text' +import { scaleSizeH, setSpText } from '@/utils/pixelRatio' +// import { screenkeepAwake } from '@/utils/nativeModules/utils' // import { log } from '@/utils/log' // import { toast } from '@/utils/tools' -const LrcLine = memo(({ lrc, line, activeLine }) => { - const theme = useGetter('common', 'theme') - const playerPortraitStyle = useGetter('common', 'playerPortraitStyle') +type FlatListType = FlatListProps<Line> + + +const LrcLine = memo(({ line, lineNum, activeLine }: { + line: Line + lineNum: number + activeLine: number +}) => { + const theme = useTheme() + const playerPortraitStyle = useSettingValue('player.horizontal.style.lrcFontSize') + const lineHeight = scaleSizeH(setSpText(playerPortraitStyle) / 10 * 1.25) return ( <View style={styles.line}> <Text style={{ ...styles.lineText, - fontSize: playerPortraitStyle.lrcFontSize / 10, - lineHeight: playerPortraitStyle.lrcFontSize / 10 * 1.25, - color: activeLine == line ? theme.secondary : theme.normal50, - }}>{lrc.text}</Text> + lineHeight, + }} color={activeLine == lineNum ? theme['c-primary'] : theme['c-300']} size={playerPortraitStyle / 10}>{line.text}</Text> { - lrc.extendedLyrics.map((lrc, index) => { + line.extendedLyrics.map((lrc, index) => { return (<Text style={{ ...styles.lineTranslationText, - fontSize: playerPortraitStyle.lrcFontSize / 10 * 0.8, - lineHeight: playerPortraitStyle.lrcFontSize / 10 * 0.8 * 1.25, - color: activeLine == line ? theme.secondary : theme.normal50, - }} key={index}>{lrc}</Text>) + lineHeight: lineHeight * 0.8, + }} key={index} color={activeLine == lineNum ? theme['c-primary-alpha-200'] : theme['c-300']} size={playerPortraitStyle / 10 * 0.8}>{lrc}</Text>) }) } </View> ) }, (prevProps, nextProps) => { - return prevProps.text == nextProps.text && - prevProps.line == nextProps.line && - prevProps.activeLine != nextProps.line && - nextProps.activeLine != nextProps.line + return prevProps.line === nextProps.line && + prevProps.activeLine != nextProps.lineNum && + nextProps.activeLine != nextProps.lineNum }) -const wait = () => new Promise(resolve => setTimeout(resolve, 100)) +const wait = async() => new Promise(resolve => setTimeout(resolve, 100)) -export default memo(() => { +export default () => { const lyricLines = useLrcSet() const { line } = useLrcPlay() - const scrollViewRef = useRef() + const flatListRef = useRef<FlatList>(null) const isPauseScrollRef = useRef(true) - const scrollTimoutRef = useRef(null) + const scrollTimoutRef = useRef<NodeJS.Timeout | null>(null) const lineRef = useRef(0) - const linesRef = useRef([]) const isFirstSetLrc = useRef(true) + // useLock() // const [imgUrl, setImgUrl] = useState(null) // const theme = useGetter('common', 'theme') // const { onLayout, ...layout } = useLayout() @@ -59,22 +68,18 @@ export default memo(() => { // }, [playMusicInfo]) // const imgWidth = useMemo(() => layout.width * 0.75, [layout.width]) - const handleScrollToActive = useCallback((index = lineRef.current) => { + const handleScrollToActive = (index = lineRef.current) => { if (index < 0) return - if (scrollViewRef.current) { + if (flatListRef.current) { try { - scrollViewRef.current.scrollToIndex({ + flatListRef.current.scrollToIndex({ index, animated: true, viewPosition: 0.4, }) - } catch (err) { - console.log(err) - // toast('出了点意外...你可以去错误日志查看错误', 'long') - // log.warn('Scroll failed: ', err.message) - } + } catch {} } - }, []) + } const handleScrollBeginDrag = () => { isPauseScrollRef.current = true @@ -86,12 +91,6 @@ export default memo(() => { }, 3000) } - const handleScrollToIndexFailed = (info) => { - // console.log(info) - wait().then(() => { - handleScrollToActive(info.index) - }) - } useEffect(() => { return () => { @@ -103,9 +102,9 @@ export default memo(() => { }, []) useEffect(() => { - linesRef.current = lyricLines - if (!scrollViewRef.current || !scrollViewRef.current.props.data.length) return - scrollViewRef.current.scrollToOffset({ + // linesRef.current = lyricLines + if (!flatListRef.current) return + flatListRef.current.scrollToOffset({ offset: 0, animated: false, }) @@ -118,20 +117,27 @@ export default memo(() => { } else { handleScrollToActive(0) } - }, [handleScrollToActive, lyricLines]) + }, [lyricLines]) useEffect(() => { lineRef.current = line - if (!scrollViewRef.current || isPauseScrollRef.current) return + if (!flatListRef.current || isPauseScrollRef.current) return handleScrollToActive() - }, [handleScrollToActive, line]) + }, [line]) + const handleScrollToIndexFailed: FlatListType['onScrollToIndexFailed'] = (info) => { + // console.log(info) + void wait().then(() => { + handleScrollToActive(info.index) + }) + } - const handleRenderItem = ({ item, index }) => { + const renderItem: FlatListType['renderItem'] = ({ item, index }) => { return ( - <LrcLine lrc={item} line={index} activeLine={line} /> + <LrcLine line={item} lineNum={index} activeLine={line} /> ) } + const getkey: FlatListType['keyExtractor'] = (item, index) => `${index}${item.text}` const spaceComponent = useMemo(() => ( <View style={styles.space}></View> @@ -140,10 +146,10 @@ export default memo(() => { return ( <FlatList data={lyricLines} - renderItem={handleRenderItem} - keyExtractor={(item, index) => index} + renderItem={renderItem} + keyExtractor={getkey} style={styles.container} - ref={scrollViewRef} + ref={flatListRef} showsVerticalScrollIndicator={false} ListHeaderComponent={spaceComponent} ListFooterComponent={spaceComponent} @@ -153,9 +159,9 @@ export default memo(() => { onScrollToIndexFailed={handleScrollToIndexFailed} /> ) -}) +} -const styles = StyleSheet.create({ +const styles = createStyle({ container: { flex: 1, paddingLeft: 10, diff --git a/src/screens/PlayDetail/Horizontal/Pic.tsx b/src/screens/PlayDetail/Horizontal/Pic.tsx new file mode 100644 index 000000000..fda7eb2d7 --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/Pic.tsx @@ -0,0 +1,80 @@ +import React, { memo, useState } from 'react' +import { View, Image, StyleSheet } from 'react-native' +// import { useLayout } from '@/utils/hooks' +import { useTheme } from '@/store/theme/hook' +import { BorderRadius } from '@/theme' +import Text from '@/components/common/Text' +import { usePlayerMusicInfo } from '@/store/player/hook' +import { useDimensions } from '@/utils/hooks' +import { useNavigationComponentDidAppear } from '@/navigation' +import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant' + +const EmptyPic = memo(({ width }: { width: number }) => { + const theme = useTheme() + const size = width * 0.2 + return ( + <View style={{ ...styles.emptyPic, width, height: width, backgroundColor: theme['c-primary-light-900-alpha-200'] }}> + <Text size={size} color={theme['c-primary-light-400-alpha-200']}>L</Text> + <Text size={size} color={theme['c-primary-light-400-alpha-200']} style={styles.text}>X</Text> + </View> + ) +}) + +export default memo(({ componentId }: { componentId: string }) => { + const musicInfo = usePlayerMusicInfo() + const { window: { width: winWidth, height: winHeight } } = useDimensions() + + const [animated, setAnimated] = useState(false) + + useNavigationComponentDidAppear(componentId, () => { + setAnimated(true) + }) + + const imgWidth = Math.min(winWidth * 0.6 * 0.5, winHeight * 0.5) + + return ( + <View style={styles.container}> + <View style={{ ...styles.content, elevation: animated ? 3 : 0 }}> + { + musicInfo.pic + ? ( + <Image source={{ uri: musicInfo.pic }} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} progressiveRenderingEnabled={true} borderRadius={2} style={{ + ...styles.img, + width: imgWidth, + height: imgWidth, + }} /> + ) + : <EmptyPic width={imgWidth} /> + } + </View> + </View> + ) +}) + +const styles = StyleSheet.create({ + container: { + flexGrow: 1, + flexShrink: 1, + justifyContent: 'center', + alignItems: 'center', + // backgroundColor: 'rgba(0,0,0,0.1)', + }, + content: { + // elevation: 3, + backgroundColor: 'rgba(0,0,0,0)', + borderRadius: 4, + }, + img: { + borderRadius: 4, + // opacity: 0, + }, + emptyPic: { + borderRadius: BorderRadius.normal, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + }, + text: { + paddingLeft: 2, + }, +}) diff --git a/src/screens/PlayDetail/Horizontal/Player/ControlBtn.tsx b/src/screens/PlayDetail/Horizontal/Player/ControlBtn.tsx new file mode 100644 index 000000000..6e3693396 --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/Player/ControlBtn.tsx @@ -0,0 +1,70 @@ +import React from 'react' +import { StyleSheet, TouchableOpacity, View } from 'react-native' +import { Icon } from '@/components/common/Icon' +import { useTheme } from '@/store/theme/hook' +// import { useIsPlay } from '@/store/player/hook' +import { playNext, playPrev, togglePlay } from '@/core/player/player' +import { scaleSizeW } from '@/utils/pixelRatio' +import { useIsPlay } from '@/store/player/hook' + +const WIDTH = scaleSizeW(50) + +const PrevBtn = () => { + const theme = useTheme() + const handlePlayPrev = () => { + void playPrev() + } + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn, width: WIDTH, height: WIDTH }} activeOpacity={0.5} onPress={handlePlayPrev}> + <Icon name='prevMusic' color={theme['c-button-font']} size={32} /> + </TouchableOpacity> + ) +} +const NextBtn = () => { + const theme = useTheme() + const handlePlayNext = () => { + void playNext() + } + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn, width: WIDTH, height: WIDTH }} activeOpacity={0.5} onPress={handlePlayNext}> + <Icon name='nextMusic' color={theme['c-button-font']} size={32} /> + </TouchableOpacity> + ) +} + +const TogglePlayBtn = () => { + const theme = useTheme() + const isPlay = useIsPlay() + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn, width: WIDTH, height: WIDTH }} activeOpacity={0.5} onPress={togglePlay}> + <Icon name={isPlay ? 'pause' : 'play'} color={theme['c-button-font']} size={32} /> + </TouchableOpacity> + ) +} + +export default () => { + return ( + <View style={styles.content}> + <PrevBtn /> + <TogglePlayBtn /> + <NextBtn /> + </View> + ) +} + + +const styles = StyleSheet.create({ + content: { + flexGrow: 0, + flexDirection: 'row', + }, + cotrolBtn: { + justifyContent: 'center', + alignItems: 'center', + + // backgroundColor: '#ccc', + shadowOpacity: 1, + textShadowRadius: 1, + marginLeft: 10, + }, +}) diff --git a/src/screens/PlayDetail/Horizontal/Player/MoreBtn/Btn.tsx b/src/screens/PlayDetail/Horizontal/Player/MoreBtn/Btn.tsx new file mode 100644 index 000000000..9f7e2fbc1 --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/Player/MoreBtn/Btn.tsx @@ -0,0 +1,34 @@ +import React from 'react' +import { TouchableOpacity } from 'react-native' +import { Icon } from '@/components/common/Icon' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { scaleSizeW } from '@/utils/pixelRatio' + +export const BTN_WIDTH = scaleSizeW(32) +export const BTN_ICON_SIZE = 22 + +export default ({ icon, color, onPress }: { + icon: string + color?: string + onPress: () => void +}) => { + const theme = useTheme() + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn, width: BTN_WIDTH, height: BTN_WIDTH }} activeOpacity={0.5} onPress={onPress}> + <Icon name={icon} color={color ?? theme['c-font-label']} size={BTN_ICON_SIZE} /> + </TouchableOpacity> + ) +} + +const styles = createStyle({ + cotrolBtn: { + marginLeft: 5, + justifyContent: 'center', + alignItems: 'center', + + // backgroundColor: '#ccc', + shadowOpacity: 1, + textShadowRadius: 1, + }, +}) diff --git a/src/screens/PlayDetail/Horizontal/Player/MoreBtn/MusicAddBtn.tsx b/src/screens/PlayDetail/Horizontal/Player/MoreBtn/MusicAddBtn.tsx new file mode 100644 index 000000000..ed2e3c3bb --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/Player/MoreBtn/MusicAddBtn.tsx @@ -0,0 +1,26 @@ +import React, { useRef } from 'react' +import MusicAddModal, { MusicAddModalType } from '@/components/MusicAddModal' +import playerState from '@/store/player/state' +import Btn from './Btn' + + +export default () => { + const musicAddModalRef = useRef<MusicAddModalType>(null) + + const handleShowMusicAddModal = () => { + const musicInfo = playerState.playMusicInfo.musicInfo + if (!musicInfo) return + musicAddModalRef.current?.show({ + musicInfo: 'progress' in musicInfo ? musicInfo.metadata.musicInfo : musicInfo, + isMove: false, + listId: playerState.playMusicInfo.listId as string, + }) + } + + return ( + <> + <Btn icon="add-music" onPress={handleShowMusicAddModal} /> + <MusicAddModal ref={musicAddModalRef} /> + </> + ) +} diff --git a/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/PlayModeBtn.js b/src/screens/PlayDetail/Horizontal/Player/MoreBtn/PlayModeBtn.tsx similarity index 58% rename from src/screens/PlayDetail/Portrait/Player/components/MoreBtn/PlayModeBtn.js rename to src/screens/PlayDetail/Horizontal/Player/MoreBtn/PlayModeBtn.tsx index 3765d5634..35227f819 100644 --- a/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/PlayModeBtn.js +++ b/src/screens/PlayDetail/Horizontal/Player/MoreBtn/PlayModeBtn.tsx @@ -1,23 +1,22 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, StyleSheet, TouchableOpacity } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' +import React, { memo, useMemo } from 'react' import { toast } from '@/utils/tools' -import { useTranslation } from '@/plugins/i18n' import { MUSIC_TOGGLE_MODE_LIST, MUSIC_TOGGLE_MODE } from '@/config/constant' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { updateSetting } from '@/core/common' +import Btn from './Btn' + export default memo(() => { - const togglePlayMethod = useGetter('common', 'togglePlayMethod') - const theme = useGetter('common', 'theme') - const setPlayNextMode = useDispatch('common', 'setPlayNextMode') - const { t } = useTranslation() + const togglePlayMethod = useSettingValue('player.togglePlayMethod') + const t = useI18n() const toggleNextPlayMode = () => { let index = MUSIC_TOGGLE_MODE_LIST.indexOf(togglePlayMethod) if (++index >= MUSIC_TOGGLE_MODE_LIST.length) index = 0 const mode = MUSIC_TOGGLE_MODE_LIST[index] - setPlayNextMode(mode) - let modeName + updateSetting({ 'player.togglePlayMethod': mode }) + let modeName: 'play_list_loop' | 'play_list_random' | 'play_list_order' | 'play_single_loop' | 'play_single' switch (mode) { case MUSIC_TOGGLE_MODE.listLoop: modeName = 'play_list_loop' @@ -60,23 +59,5 @@ export default memo(() => { return playModeIcon }, [togglePlayMethod]) - return ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={toggleNextPlayMode}> - <Icon name={playModeIcon} style={{ color: theme.normal30 }} size={24} /> - </TouchableOpacity> - ) -}) - -const styles = StyleSheet.create({ - cotrolBtn: { - marginLeft: 5, - width: 32, - height: 32, - justifyContent: 'center', - alignItems: 'center', - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 1, - }, + return <Btn icon={playModeIcon} onPress={toggleNextPlayMode} /> }) diff --git a/src/screens/PlayDetail/Horizontal/Player/MoreBtn/TimeoutExitBtn.tsx b/src/screens/PlayDetail/Horizontal/Player/MoreBtn/TimeoutExitBtn.tsx new file mode 100644 index 000000000..cd6083e3d --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/Player/MoreBtn/TimeoutExitBtn.tsx @@ -0,0 +1,23 @@ +import React, { memo, useRef } from 'react' +import TimeoutExitEditModal, { type TimeoutExitEditModalType, useTimeInfo } from '@/components/TimeoutExitEditModal' +import { useTheme } from '@/store/theme/hook' +import Btn from './Btn' + + +export default memo(() => { + const theme = useTheme() + const modalRef = useRef<TimeoutExitEditModalType>(null) + + const timeInfo = useTimeInfo() + + const handleShow = () => { + modalRef.current?.show() + } + + return ( + <> + <Btn icon="music_time" color={timeInfo.active ? theme['c-primary-font-active'] : theme['c-font-label']} onPress={handleShow} /> + <TimeoutExitEditModal ref={modalRef} timeInfo={timeInfo} /> + </> + ) +}) diff --git a/src/screens/PlayDetail/Horizontal/Player/MoreBtn/index.tsx b/src/screens/PlayDetail/Horizontal/Player/MoreBtn/index.tsx new file mode 100644 index 000000000..110c66c94 --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/Player/MoreBtn/index.tsx @@ -0,0 +1,27 @@ +import { createStyle } from '@/utils/tools' +import React from 'react' +import { View } from 'react-native' +import PlayModeBtn from './PlayModeBtn' +import MusicAddBtn from './MusicAddBtn' +import TimeoutExitBtn from './TimeoutExitBtn' + +export default () => { + return ( + <View style={styles.container}> + <TimeoutExitBtn /> + <MusicAddBtn /> + <PlayModeBtn /> + </View> + ) +} + + +const styles = createStyle({ + container: { + flexShrink: 0, + flexGrow: 0, + flexDirection: 'row', + alignItems: 'center', + // backgroundColor: 'rgba(0,0,0,0.1)', + }, +}) diff --git a/src/screens/PlayDetail/Horizontal/Player/PlayInfo.tsx b/src/screens/PlayDetail/Horizontal/Player/PlayInfo.tsx new file mode 100644 index 000000000..1fceaf737 --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/Player/PlayInfo.tsx @@ -0,0 +1,65 @@ +import React, { memo } from 'react' +import { View } from 'react-native' + +import Progress from './Progress' +import Status from './Status' +import { useProgress } from '@/store/player/hook' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' + +// const FONT_SIZE = 13 + +const PlayTimeCurrent = ({ timeStr }: { timeStr: string }) => { + const theme = useTheme() + // console.log(timeStr) + return <Text color={theme['c-500']}>{timeStr}</Text> +} + +const PlayTimeMax = memo(({ timeStr }: { timeStr: string }) => { + const theme = useTheme() + return <Text color={theme['c-500']}>{timeStr}</Text> +}) + +export default () => { + const theme = useTheme() + const { maxPlayTimeStr, nowPlayTimeStr, progress, maxPlayTime } = useProgress() + // console.log('render playInfo') + + return ( + <> + <View style={styles.progress}><Progress progress={progress} duration={maxPlayTime} /></View> + <View style={styles.info}> + <View style={styles.status} > + <Status /> + </View> + <View style={{ flexGrow: 0, flexShrink: 0, flexDirection: 'row' }} > + <PlayTimeCurrent timeStr={nowPlayTimeStr} /> + <Text color={theme['c-500']}> / </Text> + <PlayTimeMax timeStr={maxPlayTimeStr} /> + </View> + </View> + </> + ) +} + + +const styles = createStyle({ + progress: { + flexGrow: 1, + flexShrink: 0, + flexDirection: 'column', + justifyContent: 'center', + }, + info: { + flexDirection: 'row', + justifyContent: 'space-between', + // alignItems: 'center', + // backgroundColor: '#ccc', + }, + status: { + flexGrow: 1, + flexShrink: 1, + paddingRight: 5, + }, +}) diff --git a/src/screens/PlayDetail/Horizontal/Player/Progress.tsx b/src/screens/PlayDetail/Horizontal/Player/Progress.tsx new file mode 100644 index 000000000..2940104f9 --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/Player/Progress.tsx @@ -0,0 +1,104 @@ +import React, { memo, useMemo } from 'react' +import { View, Pressable, GestureResponderEvent } from 'react-native' +import { useLayout } from '@/utils/hooks' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { scaleSizeW } from '@/utils/pixelRatio' +// import { AppColors } from '@/theme' + + +const DefaultBar = memo(() => { + const theme = useTheme() + + return <View style={{ ...styles.progressBar, backgroundColor: theme['c-primary-light-100-alpha-800'], position: 'absolute', width: '100%', left: 0, top: 0 }}></View> +}) + +// const BufferedBar = memo(({ bufferedProgress }) => { +// // console.log(bufferedProgress) +// const theme = useTheme() +// return <View style={{ ...styles.progressBar, backgroundColor: theme.secondary45, position: 'absolute', width: bufferedProgress + '%', left: 0, top: 0 }}></View> +// }) + +const PreassBar = memo(({ duration }: { duration: number }) => { + const { onLayout, ...layout } = useLayout() + const handlePress = (event: GestureResponderEvent) => { + global.app_event.setProgress(event.nativeEvent.locationX / layout.width * duration) + } + + return <Pressable onPress={handlePress} onLayout={onLayout} style={styles.pressBar} /> +}) + + +const Progress = ({ progress, duration }: { + progress: number + duration: number +}) => { + // const { progress } = usePlayTimeBuffer() + const theme = useTheme() + // console.log(progress) + const progressStr = `${progress * 100}%` + + const progressDotStyle = useMemo(() => { + return { + width: progressDotSize, + height: progressDotSize, + borderRadius: progressDotSize, + position: 'absolute', + right: -progressDotSize / 2, + top: -(progressDotSize - progressHeight) / 2, + backgroundColor: theme['c-primary-light-100'], + zIndex: 9, + } as const + }, [theme]) + + return ( + <View style={styles.progress}> + <View> + <DefaultBar /> + {/* <BufferedBar bufferedProgress={bufferedProgress} /> */} + <View style={{ ...styles.progressBar, backgroundColor: theme['c-primary-light-100-alpha-400'], width: progressStr, position: 'absolute', left: 0, top: 0 }}> + <Pressable style={{ ...styles.progressDot, ...progressDotStyle }}></Pressable> + </View> + </View> + <PreassBar duration={duration} /> + {/* <View style={{ ...styles.progressBar, height: '100%', width: progressStr }}><Pressable style={styles.progressDot}></Pressable></View> */} + </View> + ) +} + +const progressContentPadding = 10 +const progressHeight = 3.6 +const progressDotSize = scaleSizeW(12) +const styles = createStyle({ + progress: { + width: '100%', + height: progressContentPadding * 2 + progressHeight, + // backgroundColor: 'rgba(0,0,0,0.5)', + paddingTop: progressContentPadding, + paddingBottom: progressContentPadding, + zIndex: 1, + }, + progressBar: { + height: progressHeight, + borderRadius: 4, + }, + progressDot: { + width: progressDotSize, + height: progressDotSize, + borderRadius: progressDotSize, + position: 'absolute', + right: -progressDotSize / 2, + top: -(progressDotSize - progressHeight) / 2, + zIndex: 9, + }, + pressBar: { + position: 'absolute', + // backgroundColor: 'rgba(0,0,0,0.5)', + left: 0, + top: 0, + height: progressContentPadding * 2 + progressHeight, + width: '100%', + }, +}) + +export default Progress diff --git a/src/screens/PlayDetail/Horizontal/Player/Status.tsx b/src/screens/PlayDetail/Horizontal/Player/Status.tsx new file mode 100644 index 000000000..2c473f93e --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/Player/Status.tsx @@ -0,0 +1,22 @@ +import React from 'react' +// import { useLrcPlay } from '@/plugins/lyric' +import { useStatusText } from '@/store/player/hook' +// import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' + + +export default () => { + // const { text } = useLrcPlay() + const statusText = useStatusText() + // console.log('render status') + + // const status = playerStatus.isPlay ? text : playerStatus.statusText + + return <Text numberOfLines={1} size={13}>{statusText}</Text> +} + +// const styles = createStyle({ +// text: { +// fontSize: 10, +// }, +// }) diff --git a/src/screens/PlayDetail/Horizontal/Player/index.tsx b/src/screens/PlayDetail/Horizontal/Player/index.tsx new file mode 100644 index 000000000..3039f8a5a --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/Player/index.tsx @@ -0,0 +1,38 @@ +import React, { memo } from 'react' +import { View } from 'react-native' + +// import Title from './components/Title' +import { createStyle } from '@/utils/tools' +import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant' +import PlayInfo from './PlayInfo' +import MoreBtn from './MoreBtn' +import ControlBtn from './ControlBtn' + + +export default memo(() => { + return ( + <View style={styles.container} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_player}> + <View style={styles.controlBtn}> + <MoreBtn /> + <ControlBtn /> + </View> + <PlayInfo /> + </View> + ) +}) + +const styles = createStyle({ + container: { + flexShrink: 0, + flexGrow: 0, + paddingLeft: 15, + // paddingRight: 15, + }, + controlBtn: { + flexDirection: 'row', + // alignItems: 'flex-end', + justifyContent: 'space-between', + paddingTop: 8, + // paddingBottom: 10, + }, +}) diff --git a/src/screens/PlayDetail/Horizontal/components/Btn.tsx b/src/screens/PlayDetail/Horizontal/components/Btn.tsx new file mode 100644 index 000000000..9c8759094 --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/components/Btn.tsx @@ -0,0 +1,35 @@ +import React from 'react' +import { TouchableOpacity } from 'react-native' +import { Icon } from '@/components/common/Icon' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { scaleSizeW } from '@/utils/pixelRatio' + +import { HEADER_HEIGHT } from '@/config/constant' +export const BTN_WIDTH = scaleSizeW(HEADER_HEIGHT) +export const BTN_ICON_SIZE = 18 + +export default ({ icon, color, onPress }: { + icon: string + color?: string + onPress: () => void +}) => { + const theme = useTheme() + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn, width: BTN_WIDTH, height: BTN_WIDTH }} activeOpacity={0.5} onPress={onPress}> + <Icon name={icon} color={color ?? theme['c-550']} size={BTN_ICON_SIZE} /> + </TouchableOpacity> + ) +} + +const styles = createStyle({ + cotrolBtn: { + // marginLeft: 5, + justifyContent: 'center', + alignItems: 'center', + + // backgroundColor: '#ccc', + shadowOpacity: 1, + textShadowRadius: 1, + }, +}) diff --git a/src/screens/PlayDetail/Horizontal/components/CommentBtn.tsx b/src/screens/PlayDetail/Horizontal/components/CommentBtn.tsx new file mode 100644 index 000000000..4cb35e320 --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/components/CommentBtn.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import Btn from './Btn' +import { useComponentIds } from '@/store/common/hook' +import { navigations } from '@/navigation' + + +export default () => { + const componentIds = useComponentIds() + + const handleShowCommentScreen = () => { + navigations.pushCommentScreen(componentIds.playDetail as string) + } + + return <Btn icon="comment" onPress={handleShowCommentScreen} /> +} diff --git a/src/screens/PlayDetail/Horizontal/components/Header.tsx b/src/screens/PlayDetail/Horizontal/components/Header.tsx new file mode 100644 index 000000000..1405b149f --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/components/Header.tsx @@ -0,0 +1,143 @@ +import React, { memo, useRef, useState } from 'react' + +import { View, StyleSheet, TouchableOpacity } from 'react-native' + +import { Icon } from '@/components/common/Icon' +import { pop } from '@/navigation' +// import { AppColors } from '@/theme' +// import commonState from '@/store/common/state' +import { useTheme } from '@/store/theme/hook' +import { usePlayerMusicInfo } from '@/store/player/hook' +import Text from '@/components/common/Text' +import { scaleSizeH } from '@/utils/pixelRatio' +import { HEADER_HEIGHT as _HEADER_HEIGHT, NAV_SHEAR_NATIVE_IDS } from '@/config/constant' +import commonState from '@/store/common/state' +import { createStyle } from '@/utils/tools' +import { useSettingValue } from '@/store/setting/hook' +import Slider, { type SliderProps } from '@/components/common/Slider' +import { updateSetting } from '@/core/common' +import Popup, { type PopupType } from '@/components/common/Popup' +import { useI18n } from '@/lang' +import CommentBtn from './CommentBtn' +import Btn from './Btn' + +const HEADER_HEIGHT = scaleSizeH(_HEADER_HEIGHT) + +const LrcFontSizeStyles = createStyle({ + content: { + flexGrow: 0, + flexShrink: 1, + flexDirection: 'row', + flexWrap: 'nowrap', + alignItems: 'center', + paddingLeft: 15, + paddingRight: 15, + }, +}) +const LrcFontSize = () => { + const theme = useTheme() + const lrcFontSize = useSettingValue('player.horizontal.style.lrcFontSize') + const [sliderSize, setSliderSize] = useState(lrcFontSize) + const [isSliding, setSliding] = useState(false) + + const handleSlidingStart: SliderProps['onSlidingStart'] = value => { + setSliding(true) + } + const handleValueChange: SliderProps['onValueChange'] = value => { + setSliderSize(value) + } + const handleSlidingComplete: SliderProps['onSlidingComplete'] = value => { + if (lrcFontSize == value) return + updateSetting({ 'player.horizontal.style.lrcFontSize': value }) + setSliding(false) + } + + return ( + <View style={LrcFontSizeStyles.content}> + <Text color={theme['c-font-label']}>{isSliding ? sliderSize : lrcFontSize}</Text> + <Slider + minimumValue={100} + maximumValue={300} + onSlidingComplete={handleSlidingComplete} + onValueChange={handleValueChange} + onSlidingStart={handleSlidingStart} + step={2} + value={lrcFontSize} + /> + </View> + ) +} + +const Title = () => { + const theme = useTheme() + const musicInfo = usePlayerMusicInfo() + + + return ( + <View style={styles.titleContent}> + <Text numberOfLines={1} style={styles.title} size={14}>{musicInfo.name}</Text> + <Text numberOfLines={1} style={styles.title} size={12} color={theme['c-font-label']}>{musicInfo.singer}</Text> + </View> + ) +} + +export default memo(() => { + const t = useI18n() + // const theme = useTheme() + + // const [settingVisible, setSettingVisible] = useState(false) + const popupRef = useRef<PopupType>(null) + + const back = () => { + // navigation.goBack() + void pop(commonState.componentIds.playDetail as string) + } + const showSetting = () => { + popupRef.current?.setVisible(true) + } + + return ( + <View style={{ height: HEADER_HEIGHT }} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_header}> + <View style={styles.container}> + <TouchableOpacity onPress={back} style={{ ...styles.button, width: HEADER_HEIGHT }}> + <Icon name="chevron-left" size={18} /> + </TouchableOpacity> + <Title /> + <CommentBtn /> + <Btn icon="font-size" onPress={showSetting} /> + </View> + <Popup ref={popupRef} position="left" title={t('player_setting_lrc_font_size')}> + <LrcFontSize /> + </Popup> + </View> + ) +}) + + +const styles = StyleSheet.create({ + container: { + // backgroundColor: '#ccc', + flexDirection: 'row', + // justifyContent: 'center', + height: '100%', + }, + button: { + justifyContent: 'center', + alignItems: 'center', + height: '100%', + flex: 0, + }, + titleContent: { + flex: 1, + // alignItems: 'center', + justifyContent: 'center', + }, + title: { + // flex: 1, + // textAlign: 'center', + }, + icon: { + paddingLeft: 4, + paddingRight: 4, + }, +}) diff --git a/src/screens/PlayDetail/Horizontal/index.tsx b/src/screens/PlayDetail/Horizontal/index.tsx new file mode 100644 index 000000000..9b5fabee5 --- /dev/null +++ b/src/screens/PlayDetail/Horizontal/index.tsx @@ -0,0 +1,93 @@ +import React, { memo, useEffect } from 'react' +import { View, StyleSheet, AppState } from 'react-native' +import { screenkeepAwake, screenUnkeepAwake } from '@/utils/nativeModules/utils' +import StatusBar from '@/components/common/StatusBar' + +import Header from './components/Header' +import { setComponentId } from '@/core/common' +import { COMPONENT_IDS } from '@/config/constant' +import PageContent from '@/components/PageContent' +import commonState, { type InitState as CommonState } from '@/store/common/state' + +import Pic from './Pic' +// import ControlBtn from './ControlBtn' +import Lyric from './Lyric' +import Player from './Player' +// import MoreBtn from './MoreBtn2' + +export default memo(({ componentId }: { componentId: string }) => { + useEffect(() => { + setComponentId(COMPONENT_IDS.playDetail, componentId) + screenkeepAwake() + let appstateListener = AppState.addEventListener('change', (state) => { + switch (state) { + case 'active': + if (!commonState.componentIds.comment) screenkeepAwake() + break + case 'background': + screenUnkeepAwake() + break + } + }) + + const handleComponentIdsChange = (ids: CommonState['componentIds']) => { + if (ids.comment) screenUnkeepAwake() + else if (AppState.currentState == 'active') screenkeepAwake() + } + + global.state_event.on('componentIdsUpdated', handleComponentIdsChange) + + return () => { + global.state_event.off('componentIdsUpdated', handleComponentIdsChange) + appstateListener.remove() + screenUnkeepAwake() + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + return ( + <PageContent> + <StatusBar /> + <View style={{ ...styles.container, paddingTop: StatusBar.currentHeight }}> + <View style={styles.left}> + <Header /> + <Pic componentId={componentId} /> + {/* <View style={styles.controlBtn} nativeID="pageIndicator"> + <MoreBtn /> + <ControlBtn /> + </View> */} + <Player /> + </View> + <View style={styles.right}> + <Lyric /> + </View> + </View> + </PageContent> + ) +}) + +const styles = StyleSheet.create({ + container: { + flex: 1, + flexDirection: 'row', + }, + left: { + flex: 1, + width: '45%', + // paddingLeft: 15, + paddingBottom: 10, + // backgroundColor: '#eee', + }, + right: { + width: '55%', + flexGrow: 0, + flexShrink: 0, + }, + controlBtn: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + // backgroundColor: '#eee', + }, +}) diff --git a/src/screens/PlayDetail/Landscape/ControlBtn.js b/src/screens/PlayDetail/Landscape/ControlBtn.js deleted file mode 100644 index 3ae9228d2..000000000 --- a/src/screens/PlayDetail/Landscape/ControlBtn.js +++ /dev/null @@ -1,95 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { View, StyleSheet, TouchableOpacity } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import { STATUS } from '@/store/modules/player' -import { useDimensions } from '@/utils/hooks' - - -export default ({ playNextModes }) => { - const playStatus = useGetter('player', 'status') - const playNext = useDispatch('player', 'playNext') - const playPrev = useDispatch('player', 'playPrev') - // const playMusicInfo = useGetter('player', 'playMusicInfo') - const pauseMusic = useDispatch('player', 'pauseMusic') - const playMusic = useDispatch('player', 'playMusic') - const theme = useGetter('common', 'theme') - - // const togglePlayMethod = useGetter('common', 'togglePlayMethod') - // const setPlayNextMode = useDispatch('common', 'setPlayNextMode') - // const toggleNextPlayMode = useCallback(() => { - // let index = playNextModes.indexOf(togglePlayMethod) - // if (++index >= playNextModes.length) index = -1 - // setPlayNextMode(playNextModes[index] || '') - // }, [setPlayNextMode, togglePlayMethod, playNextModes]) - - const { window } = useDimensions() - const width = useMemo(() => window.width * 0.4 * 0.56 * 0.33 * 0.56, [window.width]) - - const btnPrev = useMemo(() => ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playPrev}> - <Icon name='prevMusic' style={{ color: theme.secondary10 }} size={width} /> - </TouchableOpacity> - ), [playPrev, theme, width]) - - const togglePlay = useCallback(playStatus => { - switch (playStatus) { - case STATUS.playing: - pauseMusic() - break - case STATUS.pause: - case STATUS.stop: - case STATUS.none: - playMusic() - break - // default: - // playMusic(playMusicInfo) - // break - } - }, []) - const btnPlay = useMemo(() => ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={() => togglePlay(playStatus)}> - <Icon name={playStatus == STATUS.playing ? 'pause' : 'play'} style={{ color: theme.secondary10 }} size={width} /> - </TouchableOpacity> - ), [playStatus, theme, togglePlay, width]) - const btnNext = useMemo(() => ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playNext}> - <Icon name='nextMusic' style={{ color: theme.secondary10 }} size={width} /> - </TouchableOpacity> - ), [playNext, theme, width]) - - return ( - <View style={styles.container}> - {/* <TouchableOpacity activeOpacity={0.5} onPress={toggleNextPlayMode}> - <Text style={{ ...styles.cotrolBtn }}> - <Icon name={playModeIcon} style={{ color: theme.secondary10 }} size={18} /> - </Text> - </TouchableOpacity> - */} - {btnPrev} - {btnPlay} - {btnNext} - </View> - ) -} - - -const styles = StyleSheet.create({ - container: { - flex: 0, - flexDirection: 'row', - paddingLeft: 15, - // paddingRight: 15, - width: '56%', - }, - cotrolBtn: { - width: '33.33%', - aspectRatio: 1, - justifyContent: 'center', - alignItems: 'center', - - shadowOpacity: 1, - textShadowRadius: 1, - // backgroundColor: '#eee', - }, -}) diff --git a/src/screens/PlayDetail/Landscape/Lyric.js b/src/screens/PlayDetail/Landscape/Lyric.js deleted file mode 100644 index 3a37c9da2..000000000 --- a/src/screens/PlayDetail/Landscape/Lyric.js +++ /dev/null @@ -1,203 +0,0 @@ -import React, { memo, useMemo, useCallback, useEffect, useRef } from 'react' -import { View, Text, StyleSheet, FlatList } from 'react-native' -import { useGetter, useDispatch } from '@/store' -// import { useLayout } from '@/utils/hooks' -import { useLrcPlay, useLrcSet } from '@/plugins/lyric' -// import { log } from '@/utils/log' -// import { toast } from '@/utils/tools' -import { onNavigationComponentDidDisappearEvent } from '@/navigation' - -const LrcLine = memo(({ lrc, line, activeLine }) => { - const theme = useGetter('common', 'theme') - const playerLandscapeStyle = useGetter('common', 'playerLandscapeStyle') - - return ( - <View style={styles.line}> - <Text style={{ - ...styles.lineText, - fontSize: playerLandscapeStyle.lrcFontSize / 10, - lineHeight: playerLandscapeStyle.lrcFontSize / 10 * 1.25, - color: activeLine == line ? theme.secondary : theme.normal50, - }}>{lrc.text}</Text> - { - lrc.extendedLyrics.map((lrc, index) => { - return (<Text style={{ - ...styles.lineTranslationText, - fontSize: playerLandscapeStyle.lrcFontSize / 10 * 0.8, - lineHeight: playerLandscapeStyle.lrcFontSize / 10 * 0.8 * 1.25, - color: activeLine == line ? theme.secondary : theme.normal50, - }} key={index}>{lrc}</Text>) - }) - } - </View> - ) -}, (prevProps, nextProps) => { - return prevProps.text == nextProps.text && - prevProps.line == nextProps.line && - prevProps.activeLine != nextProps.line && - nextProps.activeLine != nextProps.line -}) -const wait = () => new Promise(resolve => setTimeout(resolve, 100)) - -export default memo(() => { - const lyricLines = useLrcSet() - const { line } = useLrcPlay() - const scrollViewRef = useRef() - const isPauseScrollRef = useRef(true) - const scrollTimoutRef = useRef(null) - const lineRef = useRef(0) - const linesRef = useRef([]) - const isFirstSetLrc = useRef(true) - const componentIds = useGetter('common', 'componentIds') - // const playMusicInfo = useGetter('player', 'playMusicInfo') - // const [imgUrl, setImgUrl] = useState(null) - // const theme = useGetter('common', 'theme') - // const { onLayout, ...layout } = useLayout() - - // useEffect(() => { - // const url = playMusicInfo ? playMusicInfo.musicInfo.img : null - // if (imgUrl == url) return - // setImgUrl(url) - // // eslint-disable-next-line react-hooks/exhaustive-deps - // }, [playMusicInfo]) - - // const imgWidth = useMemo(() => layout.width * 0.75, [layout.width]) - const handleScrollToActive = useCallback((index = lineRef.current) => { - if (index < 0) return - if (scrollViewRef.current) { - try { - scrollViewRef.current.scrollToIndex({ - index, - animated: true, - viewPosition: 0.4, - }) - } catch (err) { - console.log(err) - // toast('出了点意外...你可以去错误日志查看错误', 'long') - // log.warn('Scroll failed: ', err.message) - } - } - }, []) - - const handleScrollBeginDrag = () => { - isPauseScrollRef.current = true - if (scrollTimoutRef.current) clearTimeout(scrollTimoutRef.current) - scrollTimoutRef.current = setTimeout(() => { - scrollTimoutRef.current = null - isPauseScrollRef.current = false - handleScrollToActive() - }, 3000) - } - - const handleScrollToIndexFailed = (info) => { - // console.log(info) - wait().then(() => { - handleScrollToActive(info.index) - }) - } - - useEffect(() => { - return () => { - if (scrollTimoutRef.current) { - clearTimeout(scrollTimoutRef.current) - scrollTimoutRef.current = null - } - } - }, []) - - useEffect(() => { - let listener - if (componentIds.comment) { - listener = onNavigationComponentDidDisappearEvent(componentIds.comment, () => { - - }) - } - return () => { - if (listener) listener.remove() - } - }, [componentIds]) - - useEffect(() => { - linesRef.current = lyricLines - if (!scrollViewRef.current || !scrollViewRef.current.props.data.length) return - scrollViewRef.current.scrollToOffset({ - offset: 0, - animated: false, - }) - if (isFirstSetLrc.current) { - isFirstSetLrc.current = false - setTimeout(() => { - isPauseScrollRef.current = false - handleScrollToActive() - }, 100) - } else { - handleScrollToActive(0) - } - }, [handleScrollToActive, lyricLines]) - - useEffect(() => { - lineRef.current = line - if (!scrollViewRef.current || isPauseScrollRef.current) return - handleScrollToActive() - }, [handleScrollToActive, line]) - - - const handleRenderItem = ({ item, index }) => { - return ( - <LrcLine lrc={item} line={index} activeLine={line} /> - ) - } - - const spaceComponent = useMemo(() => ( - <View style={styles.space}></View> - ), []) - - return ( - <FlatList - data={lyricLines} - renderItem={handleRenderItem} - keyExtractor={(item, index) => index} - style={styles.container} - ref={scrollViewRef} - showsVerticalScrollIndicator={false} - ListHeaderComponent={spaceComponent} - ListFooterComponent={spaceComponent} - onScrollBeginDrag={handleScrollBeginDrag} - fadingEdgeLength={200} - initialNumToRender={Math.max(line + 10, 10)} - onScrollToIndexFailed={handleScrollToIndexFailed} - /> - ) -}) - -const styles = StyleSheet.create({ - container: { - flex: 1, - paddingLeft: 10, - paddingRight: 10, - // backgroundColor: 'rgba(0,0,0,0.1)', - }, - space: { - paddingTop: '80%', - }, - line: { - paddingTop: 8, - paddingBottom: 8, - // opacity: 0, - }, - lineText: { - textAlign: 'center', - fontSize: 18, - lineHeight: 20, - // paddingTop: 5, - // paddingBottom: 5, - // opacity: 0, - }, - lineTranslationText: { - textAlign: 'center', - fontSize: 13, - lineHeight: 17, - paddingTop: 5, - // paddingBottom: 5, - }, -}) diff --git a/src/screens/PlayDetail/Landscape/MoreBtn/MusicAddBtn.js b/src/screens/PlayDetail/Landscape/MoreBtn/MusicAddBtn.js deleted file mode 100644 index 411524fe9..000000000 --- a/src/screens/PlayDetail/Landscape/MoreBtn/MusicAddBtn.js +++ /dev/null @@ -1,47 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect, useState, useRef } from 'react' -import { Text, StyleSheet, TouchableOpacity } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import MusicAddModal from '@/components/MusicAddModal' - - -export default memo(({ width }) => { - const theme = useGetter('common', 'theme') - const [visibleMusicAddModal, setVisibleMusicAddModal] = useState(false) - const playMusicInfo = useGetter('player', 'playMusicInfo') - const selectedDataRef = useRef() - const hideMusicAddModal = () => { - setVisibleMusicAddModal(false) - } - - const handleShowMusicAddModal = () => { - selectedDataRef.current = playMusicInfo.musicInfo - setVisibleMusicAddModal(true) - } - - return ( - <> - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={handleShowMusicAddModal}> - <Icon name="add-music" style={{ color: theme.normal30 }} size={width} /> - </TouchableOpacity> - <MusicAddModal - visible={visibleMusicAddModal} - hideModal={hideMusicAddModal} - musicInfo={selectedDataRef.current} /> - </> - ) -}) - -const styles = StyleSheet.create({ - cotrolBtn: { - marginRight: '1%', - width: '25%', - aspectRatio: 1, - justifyContent: 'center', - alignItems: 'center', - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 1, - }, -}) diff --git a/src/screens/PlayDetail/Landscape/MoreBtn/TimeoutExit.js b/src/screens/PlayDetail/Landscape/MoreBtn/TimeoutExit.js deleted file mode 100644 index 758ed13ec..000000000 --- a/src/screens/PlayDetail/Landscape/MoreBtn/TimeoutExit.js +++ /dev/null @@ -1,184 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect, useState, useRef } from 'react' -import { Text, StyleSheet, TouchableOpacity, View } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import ConfirmAlert from '@/components/common/ConfirmAlert' -import { useTranslation } from '@/plugins/i18n' -import Input from '@/components/common/Input' -import { startTimeoutExit, stopTimeoutExit, useTimeoutExitTimeInfo, getTimeoutExitTime, cancelTimeoutExit } from '@/utils/timeoutExit' -import { toast } from '@/utils/tools' -import CheckBox from '@/components/common/CheckBox' - -const MAX_MIN = 1440 -const formatTime = time => { - // let d = parseInt(time / 86400) - // d = d ? d.toString() + ':' : '' - // time = time % 86400 - let h = parseInt(time / 3600) - h = h ? h.toString() + ':' : '' - time = time % 3600 - const m = parseInt(time / 60).toString().padStart(2, '0') - const s = parseInt(time % 60).toString().padStart(2, '0') - return `${h}${m}:${s}` -} -const rxp = /([1-9]\d*)/ -const Status = ({ exitTimeInfo }) => { - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - return ( - <View style={styles.tip}> - { - exitTimeInfo.time < 0 - ? ( - <Text style={{ color: theme.normal }}>{t('timeout_exit_tip_off')}</Text> - ) - : ( - <Text style={{ color: theme.normal }}>{t('timeout_exit_tip_on', { time: formatTime(exitTimeInfo.time) })}</Text> - ) - } - {exitTimeInfo.isPlayedExit ? <Text style={{ fontSize: 12, color: theme.normal40 }}>{t('timeout_exit_btn_wait_tip')}</Text> : null} - </View> - ) -} - -export default memo(() => { - const theme = useGetter('common', 'theme') - const [visibleAlert, setVisibleAlert] = useState(false) - const { t } = useTranslation() - const [text, setText] = useState('') - const exitTimeInfo = useTimeoutExitTimeInfo() - const inputRef = useRef() - const timeoutExit = useGetter('common', 'timeoutExit') - const timeoutExitPlayed = useGetter('common', 'timeoutExitPlayed') - const setTimeoutExit = useDispatch('common', 'setTimeoutExit') - const timeInfo = useMemo(() => { - return exitTimeInfo.time < 0 - ? { cancelText: exitTimeInfo.isPlayedExit ? t('timeout_exit_btn_wait_cancel') : '', confirmText: '', active: false } - : { - cancelText: t('timeout_exit_btn_cancel'), - confirmText: t('timeout_exit_btn_update'), - active: true, - } - }, [exitTimeInfo, t]) - - const handleShowTimeoutAlert = () => { - setText(timeoutExit) - setVisibleAlert(true) - // global.requestAnimationFrame(() => { - // inputRef.current.focus() - // }) - } - const handleAlertHide = () => { - setVisibleAlert(false) - } - const handleAlertCancel = () => { - setVisibleAlert(false) - if (exitTimeInfo.isPlayedExit) { - cancelTimeoutExit() - return - } - if (!timeInfo.active) return - stopTimeoutExit() - toast(t('timeout_exit_tip_cancel')) - } - const handleAlertConfirm = () => { - // if (filterFileName.test(text)) { - // toast(t('create_new_folder_error_tip'), 'long') - // return - // } - const time = parseInt(text) - if (!time) return - cancelTimeoutExit() - startTimeoutExit(time * 60) - setVisibleAlert(false) - toast(t('timeout_exit_tip_on', { time: formatTime(getTimeoutExitTime()) })) - setTimeoutExit({ time: String(time) }) - } - const onChangeText = useCallback(text => { - if (rxp.test(text)) { - if (text != RegExp.$1) toast(t('input_error')) - text = RegExp.$1 - if (parseInt(text) > MAX_MIN) { - toast(t('timeout_exit_tip_max', { num: MAX_MIN })) - text = text.substring(0, text.length - 1) - } - } else { - if (text.length) toast(t('input_error')) - text = '' - } - setText(text) - }, [t]) - - const onCheckChange = check => { - setTimeoutExit({ isPlayed: check }) - } - - - return ( - <> - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={handleShowTimeoutAlert}> - <Icon name="alarm-snooze" style={{ color: timeInfo.active ? theme.secondary20 : theme.normal30 }} size={24} /> - </TouchableOpacity> - <ConfirmAlert - visible={visibleAlert} - onHide={handleAlertHide} - onCancel={handleAlertCancel} - onConfirm={handleAlertConfirm} - cancelText={timeInfo.cancelText} - confirmText={timeInfo.confirmText} - > - <View style={styles.alertContent}> - <Status exitTimeInfo={exitTimeInfo} /> - <View style={styles.inputContent}> - <Input - ref={inputRef} - value={text} - onChangeText={onChangeText} - style={{ ...styles.input, backgroundColor: theme.secondary40 }} /> - <Text style={{ marginLeft: 5, color: theme.normal }}>{t('timeout_exit_min')}</Text> - </View> - <View style={styles.checkbox}> - <CheckBox check={timeoutExitPlayed} label={t('timeout_exit_label_isPlayed')} onChange={onCheckChange} /> - </View> - </View> - </ConfirmAlert> - </> - ) -}) - -const styles = StyleSheet.create({ - cotrolBtn: { - marginLeft: 5, - width: 32, - height: 32, - justifyContent: 'center', - alignItems: 'center', - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 1, - }, - alertContent: { - flexShrink: 1, - flexDirection: 'column', - }, - tip: { - marginBottom: 8, - }, - checkbox: { - marginTop: 5, - }, - inputContent: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - }, - input: { - flexGrow: 1, - flexShrink: 1, - borderRadius: 4, - paddingTop: 2, - paddingBottom: 2, - fontSize: 12, - }, -}) diff --git a/src/screens/PlayDetail/Landscape/MoreBtn/index.js b/src/screens/PlayDetail/Landscape/MoreBtn/index.js deleted file mode 100644 index ae5c0e419..000000000 --- a/src/screens/PlayDetail/Landscape/MoreBtn/index.js +++ /dev/null @@ -1,34 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { View, StyleSheet } from 'react-native' -import PlayModeBtn from './PlayModeBtn' -import MusicAddBtn from './MusicAddBtn' -import TimeoutExit from './TimeoutExit' -import { useDimensions } from '@/utils/hooks' - -export default () => { - const { window } = useDimensions() - const width = useMemo(() => window.width * 0.4 * 0.4 * 0.3 * 0.6, [window.width]) - - return ( - <View style={styles.container}> - <TimeoutExit width={width} /> - <PlayModeBtn width={width} /> - <MusicAddBtn width={width} /> - </View> - ) -} - - -const styles = StyleSheet.create({ - container: { - width: '40%', - flexShrink: 0, - flexGrow: 0, - flexDirection: 'row', - alignItems: 'center', - paddingLeft: 10, - paddingTop: 5, - paddingBottom: 5, - // backgroundColor: 'rgba(0,0,0,0.1)', - }, -}) diff --git a/src/screens/PlayDetail/Landscape/Pic.js b/src/screens/PlayDetail/Landscape/Pic.js deleted file mode 100644 index b0e892bc2..000000000 --- a/src/screens/PlayDetail/Landscape/Pic.js +++ /dev/null @@ -1,49 +0,0 @@ -import React, { memo, useMemo } from 'react' -import { View, Image, StyleSheet } from 'react-native' -import { useGetter } from '@/store' -// import { useLayout } from '@/utils/hooks' -import { getWindowSise } from '@/utils/tools' - -export default memo(({ componentId, animated }) => { - const playMusicInfo = useGetter('player', 'playMusicInfo') - const theme = useGetter('common', 'theme') - - const musicInfo = useMemo(() => { - return (playMusicInfo && playMusicInfo.musicInfo) || {} - }, [playMusicInfo]) - - const { width: winWidth, height: winHeight } = getWindowSise() - const imgWidth = Math.min(winWidth * 0.6 * 0.45, winHeight * 0.5) - - return ( - <View style={styles.container}> - <View style={{ ...styles.content, elevation: animated ? 3 : 0 }}> - <Image source={{ uri: musicInfo.img }} nativeID={`pic${musicInfo.songmid}Dest`} progressiveRenderingEnabled={true} borderRadius={2} style={{ - ...styles.img, - backgroundColor: theme.primary, - width: imgWidth, - height: imgWidth, - }} /> - </View> - </View> - ) -}) - -const styles = StyleSheet.create({ - container: { - flexGrow: 1, - flexShrink: 1, - justifyContent: 'center', - alignItems: 'center', - // backgroundColor: 'rgba(0,0,0,0.1)', - }, - content: { - // elevation: 3, - backgroundColor: 'rgba(0,0,0,0)', - borderRadius: 4, - }, - img: { - borderRadius: 4, - // opacity: 0, - }, -}) diff --git a/src/screens/PlayDetail/Landscape/PlayBar/Progress.js b/src/screens/PlayDetail/Landscape/PlayBar/Progress.js deleted file mode 100644 index a2abad91a..000000000 --- a/src/screens/PlayDetail/Landscape/PlayBar/Progress.js +++ /dev/null @@ -1,89 +0,0 @@ -import React, { memo } from 'react' -import { View, StyleSheet, TouchableOpacity, Pressable } from 'react-native' -import { useLayout } from '@/utils/hooks' -import { useGetter, useDispatch } from '@/store' -// import { AppColors } from '@/theme' -import { getWindowSise } from '@/utils/tools' - - -const DefaultBar = memo(() => { - const theme = useGetter('common', 'theme') - - return <View style={{ ...styles.progressBar, backgroundColor: theme.borderColor2, position: 'absolute', width: '100%', left: 0, top: 0 }}></View> -}) - -const BufferedBar = memo(({ bufferedProgress }) => { - const theme = useGetter('common', 'theme') - return <View style={{ ...styles.progressBar, backgroundColor: theme.borderColor2, position: 'absolute', width: bufferedProgress + '%', left: 0, top: 0 }}></View> -}) - -const PreassBar = memo(({ duration }) => { - const { onLayout, ...layout } = useLayout() - const setProgress = useDispatch('player', 'setProgress') - const handlePress = event => { - setProgress(event.nativeEvent.locationX / layout.width * duration) - } - - return <Pressable onPress={handlePress} onLayout={onLayout} style={styles.pressBar} /> -}) - - -const Progress = ({ progress, bufferedProgress, duration }) => { - // const { progress } = usePlayTimeBuffer() - const theme = useGetter('common', 'theme') - // console.log(progress) - const progressStr = progress + '%' - - return ( - <View style={styles.progress}> - <View> - <DefaultBar /> - <BufferedBar bufferedProgress={bufferedProgress} /> - <View style={{ ...styles.progressBar, backgroundColor: theme.secondary30, width: progressStr, position: 'absolute', left: 0, top: 0 }}> - <Pressable style={{ ...styles.progressDot, backgroundColor: theme.secondary10 }}></Pressable> - </View> - </View> - <PreassBar duration={duration} /> - {/* <View style={{ ...styles.progressBar, height: '100%', width: progressStr }}><Pressable style={styles.progressDot}></Pressable></View> */} - </View> - ) -} - - -const { width } = getWindowSise() -const progressContentPadding = width * 0.0140625 -const progressHeight = width * 0.005 -const progressDotSize = progressHeight * 3.8 -const styles = StyleSheet.create({ - progress: { - width: '100%', - height: progressContentPadding * 2 + progressHeight, - // backgroundColor: 'rgba(0,0,0,0.5)', - paddingTop: progressContentPadding, - paddingBottom: progressContentPadding, - zIndex: 1, - }, - progressBar: { - height: progressHeight, - borderRadius: 4, - }, - progressDot: { - width: progressDotSize, - height: progressDotSize, - borderRadius: progressDotSize, - position: 'absolute', - right: -progressDotSize / 2, - top: -(progressDotSize - progressHeight) / 2, - zIndex: 9, - }, - pressBar: { - position: 'absolute', - // backgroundColor: 'rgba(0,0,0,0.5)', - left: 0, - top: 0, - height: progressContentPadding * 2 + progressHeight, - width: '100%', - }, -}) - -export default Progress diff --git a/src/screens/PlayDetail/Landscape/PlayBar/Status.js b/src/screens/PlayDetail/Landscape/PlayBar/Status.js deleted file mode 100644 index 43f2a45fb..000000000 --- a/src/screens/PlayDetail/Landscape/PlayBar/Status.js +++ /dev/null @@ -1,25 +0,0 @@ -import React, { memo, useMemo } from 'react' -import { Text } from 'react-native' -import { useGetter } from '@/store' -import { STATUS } from '@/store/modules/player' - - -export default memo(() => { - const theme = useGetter('common', 'theme') - const playStatus = useGetter('player', 'status') - const statusText = useGetter('player', 'statusText') - const status = useMemo(() => { - switch (playStatus) { - case STATUS.playing: - case STATUS.pause: - case STATUS.stop: - return '' - default: return statusText - } - }, [playStatus, statusText]) - return <Text numberOfLines={1} style={{ fontSize: 13, color: theme.normal10 }}>{status}</Text> -}) - -// const styles = StyleSheet.create({ - -// }) diff --git a/src/screens/PlayDetail/Landscape/PlayBar/index.js b/src/screens/PlayDetail/Landscape/PlayBar/index.js deleted file mode 100644 index 1ec12e8f5..000000000 --- a/src/screens/PlayDetail/Landscape/PlayBar/index.js +++ /dev/null @@ -1,60 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, StyleSheet, View } from 'react-native' -import { usePlayTime, useDimensions } from '@/utils/hooks' -import { useGetter } from '@/store' - -import Progress from './Progress' -import Status from './Status' - -const PlayTimeCurrent = ({ timeStr, size }) => { - const theme = useGetter('common', 'theme') - // console.log(timeStr) - return <Text style={{ fontSize: size, color: theme.normal10 }}>{timeStr}</Text> -} - -const PlayTimeMax = memo(({ timeStr, size }) => { - const theme = useGetter('common', 'theme') - return <Text style={{ fontSize: size, color: theme.normal10 }}>{timeStr}</Text> -}) - -export default () => { - const { curTimeStr, maxTimeStr, progress, bufferedProgress, duration } = usePlayTime() - const { window } = useDimensions() - const size = useMemo(() => window.width * 0.4 * 0.4 * 0.125, [window.width]) - const theme = useGetter('common', 'theme') - - return ( - <View style={styles.container} nativeID="player"> - <View style={styles.progress}><Progress progress={progress} bufferedProgress={bufferedProgress} duration={duration} /></View> - <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}> - <View style={{ flexGrow: 1, flexShrink: 1, paddingRight: 5 }} > - <Status /> - </View> - <View style={{ flexGrow: 0, flexShrink: 0, flexDirection: 'row' }} > - <PlayTimeCurrent size={size} timeStr={curTimeStr} /> - <Text style={{ fontSize: size, color: theme.normal }}> / </Text> - <PlayTimeMax size={size} timeStr={maxTimeStr} /> - </View> - </View> - </View> - ) -} - - -const styles = StyleSheet.create({ - container: { - flexGrow: 0, - paddingLeft: 15, - // paddingRight: 15, - }, - progress: { - flexGrow: 1, - flexShrink: 0, - flexDirection: 'column', - justifyContent: 'center', - // height: - // position: 'absolute', - // width: '100%', - // top: 0, - }, -}) diff --git a/src/screens/PlayDetail/Landscape/Title.js b/src/screens/PlayDetail/Landscape/Title.js deleted file mode 100644 index 65fe4a23b..000000000 --- a/src/screens/PlayDetail/Landscape/Title.js +++ /dev/null @@ -1,35 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, View, StyleSheet } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' - -export default () => { - const theme = useGetter('common', 'theme') - const playMusicInfo = useGetter('player', 'playMusicInfo') - const { t } = useTranslation() - const titleInfo = useMemo(() => { - const info = { - name: '', - singer: '', - } - if (playMusicInfo) { - info.name = t('name', { name: playMusicInfo.musicInfo.name }) - info.singer = t('singer', { name: playMusicInfo.musicInfo.singer }) - } - return info - }, [playMusicInfo, t]) - // console.log(playMusicInfo) - return ( - <View style={styles.container}> - <Text style={{ width: '100%', fontSize: 12, color: theme.normal20 }} numberOfLines={1}>{titleInfo.name}</Text> - <Text style={{ width: '100%', fontSize: 12, color: theme.normal20 }} numberOfLines={1}>{titleInfo.singer}</Text> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - flexShrink: 1, - flexGrow: 1, - }, -}) diff --git a/src/screens/PlayDetail/Landscape/components/CommentBtn.js b/src/screens/PlayDetail/Landscape/components/CommentBtn.js deleted file mode 100644 index 01a82ff5f..000000000 --- a/src/screens/PlayDetail/Landscape/components/CommentBtn.js +++ /dev/null @@ -1,35 +0,0 @@ -import React, { memo } from 'react' -import { StyleSheet, TouchableOpacity } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import { navigations } from '@/navigation' - - -export default memo(() => { - const theme = useGetter('common', 'theme') - const componentIds = useGetter('common', 'componentIds') - - const handleShowCommentScreen = () => { - navigations.pushCommentScreen(componentIds.home) - } - - return ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={handleShowCommentScreen}> - <Icon name="comment" style={{ color: theme.normal30 }} size={24} /> - </TouchableOpacity> - ) -}) - -const styles = StyleSheet.create({ - cotrolBtn: { - marginLeft: 5, - width: 40, - height: 40, - justifyContent: 'center', - alignItems: 'center', - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 1, - }, -}) diff --git a/src/screens/PlayDetail/Landscape/components/Header.js b/src/screens/PlayDetail/Landscape/components/Header.js deleted file mode 100644 index dd0a22d7f..000000000 --- a/src/screens/PlayDetail/Landscape/components/Header.js +++ /dev/null @@ -1,137 +0,0 @@ -import React, { memo, useState, useCallback } from 'react' - -import { View, StyleSheet, StatusBar, TouchableOpacity, Text } from 'react-native' - -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import { pop } from '@/navigation' -import Popup from '@/components/common/Popup' -import Slider from '@/components/common/Slider' -import { useTranslation } from '@/plugins/i18n' -// import { AppColors } from '@/theme' -import CommentBtn from './CommentBtn' - -const LrcFontSizeStyles = StyleSheet.create({ - content: { - flexGrow: 0, - flexShrink: 1, - flexDirection: 'row', - flexWrap: 'nowrap', - alignItems: 'center', - paddingLeft: 15, - paddingRight: 15, - paddingTop: 15, - }, -}) -const LrcFontSize = () => { - const theme = useGetter('common', 'theme') - const playerLandscapeStyle = useGetter('common', 'playerLandscapeStyle') - const setPlayerLandscapeStyle = useDispatch('common', 'setPlayerLandscapeStyle') - const [sliderSize, setSliderSize] = useState(playerLandscapeStyle.lrcFontSize) - const [isSliding, setSliding] = useState(false) - - const handleSlidingStart = useCallback(value => { - setSliding(true) - }, []) - const handleValueChange = useCallback(value => { - setSliderSize(value) - }, []) - const handleSlidingComplete = useCallback(value => { - if (playerLandscapeStyle.lrcFontSize == value) return - setPlayerLandscapeStyle({ ...playerLandscapeStyle, lrcFontSize: value }) - setSliding(false) - }, [playerLandscapeStyle, setPlayerLandscapeStyle]) - - return ( - <View style={LrcFontSizeStyles.content}> - <Text style={{ color: theme.secondary10 }}>{isSliding ? sliderSize : playerLandscapeStyle.lrcFontSize}</Text> - <Slider - minimumValue={120} - maximumValue={380} - onSlidingComplete={handleSlidingComplete} - onValueChange={handleValueChange} - onSlidingStart={handleSlidingStart} - step={2} - value={playerLandscapeStyle.lrcFontSize} - /> - </View> - ) -} - -const Setting = ({ visible, hide }) => { - const { t } = useTranslation() - return ( - <Popup - visible={visible} - hide={hide} - position='left' - title={t('player_setting_lrc_font_size')} - > - <LrcFontSize /> - </Popup> - ) -} - -export default memo(() => { - const theme = useGetter('common', 'theme') - const playMusicInfo = useGetter('player', 'playMusicInfo') - const componentIds = useGetter('common', 'componentIds') - - const [settingVisible, setSettingVisible] = useState(false) - - const back = () => { - pop(componentIds.playDetail) - } - const showSetting = () => { - setSettingVisible(true) - } - - return ( - <View style={{ ...styles.header, backgroundColor: theme.primary }} nativeID="header"> - <View style={{ ...styles.container }}> - <TouchableOpacity onPress={back} style={styles.button}> - <Icon name="chevron-left" style={{ color: theme.normal }} size={24} /> - </TouchableOpacity> - <View style={styles.titleContent}> - <Text numberOfLines={1} style={{ ...styles.title, color: theme.normal10 }}>{playMusicInfo.musicInfo?.name}</Text> - <Text numberOfLines={1} style={{ ...styles.title, color: theme.normal20, fontSize: 12 }}>{playMusicInfo.musicInfo?.singer}</Text> - </View> - <CommentBtn /> - <TouchableOpacity onPress={showSetting} style={styles.button}> - <Icon name="font-size" style={{ color: theme.normal30 }} size={24} /> - </TouchableOpacity> - </View> - <Setting visible={settingVisible} hide={() => setSettingVisible(false)} /> - </View> - ) -}) - - -const styles = StyleSheet.create({ - header: { - height: 40, - }, - container: { - flexDirection: 'row', - // justifyContent: 'center', - height: 40, - }, - button: { - width: 40, - justifyContent: 'center', - alignItems: 'center', - flex: 0, - }, - titleContent: { - flex: 1, - }, - title: { - flex: 1, - // textAlign: 'center', - fontSize: 14, - }, - icon: { - paddingLeft: 4, - paddingRight: 4, - }, -}) diff --git a/src/screens/PlayDetail/Landscape/index.js b/src/screens/PlayDetail/Landscape/index.js deleted file mode 100644 index 198c41a7e..000000000 --- a/src/screens/PlayDetail/Landscape/index.js +++ /dev/null @@ -1,100 +0,0 @@ -import React, { memo, useEffect, useCallback, useMemo, useRef } from 'react' -import { View, Text, StyleSheet, AppState } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import { screenkeepAwake, screenUnkeepAwake } from '@/utils/utils' -import { onNavigationComponentDidDisappearEvent } from '@/navigation' -import StatusBar from '@/components/common/StatusBar' - -import Header from './components/Header' -import Pic from './Pic' -import ControlBtn from './ControlBtn' -import Lyric from './Lyric' -import PlayBar from './PlayBar' -import MoreBtn from './MoreBtn' - -export default memo(({ componentId, animated }) => { - const theme = useGetter('common', 'theme') - const componentIds = useGetter('common', 'componentIds') - const showCommentRef = useRef(false) - - useEffect(() => { - let listener - showCommentRef.current = !!componentIds.comment - if (showCommentRef.current) { - screenUnkeepAwake() - listener = onNavigationComponentDidDisappearEvent(componentIds.comment, () => { - if (AppState.currentState == 'active') screenkeepAwake() - }) - } - return () => { - if (listener) listener.remove() - } - }, [componentIds]) - - useEffect(() => { - screenkeepAwake() - let appstateListener = AppState.addEventListener('change', (state) => { - switch (state) { - case 'active': - if (!showCommentRef.current) screenkeepAwake() - break - case 'background': - screenUnkeepAwake() - break - } - }) - return () => { - screenUnkeepAwake() - appstateListener.remove() - } - }, []) - const component = useMemo(() => { - return ( - <> - <StatusBar /> - <View style={{ ...styles.container, backgroundColor: theme.primary }}> - <View style={styles.left}> - <Header /> - <Pic componentId={componentId} animated={animated} /> - <View style={styles.controlBtn} nativeID="pageIndicator"> - <MoreBtn /> - <ControlBtn /> - </View> - <PlayBar /> - </View> - <View style={styles.right}> - <Lyric /> - </View> - </View> - </> - ) - }, [animated, componentId, theme]) - return component -}) - -const styles = StyleSheet.create({ - container: { - paddingTop: StatusBar.currentHeight, - flex: 1, - flexDirection: 'row', - }, - left: { - flex: 1, - width: '45%', - // paddingLeft: 15, - paddingBottom: 10, - // backgroundColor: '#eee', - }, - right: { - width: '55%', - flexGrow: 0, - flexShrink: 0, - }, - controlBtn: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - // backgroundColor: '#eee', - }, -}) diff --git a/src/screens/PlayDetail/Portrait/Pic.js b/src/screens/PlayDetail/Portrait/Pic.js deleted file mode 100644 index 44b6a0738..000000000 --- a/src/screens/PlayDetail/Portrait/Pic.js +++ /dev/null @@ -1,46 +0,0 @@ -import React, { memo, useMemo } from 'react' -import { View, Image, StyleSheet } from 'react-native' -import { useGetter, useDispatch } from '@/store' -// import { useLayout } from '@/utils/hooks' -import { getWindowSise } from '@/utils/tools' - -export default memo(({ componentId, animated }) => { - const playMusicInfo = useGetter('player', 'playMusicInfo') - const theme = useGetter('common', 'theme') - const musicInfo = useMemo(() => { - return (playMusicInfo && playMusicInfo.musicInfo) || {} - }, [playMusicInfo]) - - const imgWidth = getWindowSise().width * 0.8 - - return ( - <View style={styles.container}> - <View style={{ ...styles.content, elevation: animated ? 3 : 0 }}> - <Image source={{ uri: musicInfo.img }} nativeID={`pic${musicInfo.songmid}Dest`} progressiveRenderingEnabled={true} borderRadius={2} style={{ - ...styles.img, - backgroundColor: theme.primary, - width: imgWidth, - height: imgWidth, - }} /> - </View> - </View> - ) -}) - -const styles = StyleSheet.create({ - container: { - flexGrow: 1, - flexShrink: 1, - justifyContent: 'center', - alignItems: 'center', - }, - content: { - // elevation: 3, - backgroundColor: 'rgba(0,0,0,0)', - borderRadius: 4, - }, - img: { - borderRadius: 4, - // opacity: 0, - }, -}) diff --git a/src/screens/PlayDetail/Portrait/Player/components/ControlBtn.js b/src/screens/PlayDetail/Portrait/Player/components/ControlBtn.js deleted file mode 100644 index f6fbea1bb..000000000 --- a/src/screens/PlayDetail/Portrait/Player/components/ControlBtn.js +++ /dev/null @@ -1,84 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, StyleSheet, TouchableOpacity } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import { STATUS } from '@/store/modules/player' - - -export default ({ playNextModes }) => { - const playStatus = useGetter('player', 'status') - const playNext = useDispatch('player', 'playNext') - const playPrev = useDispatch('player', 'playPrev') - // const playMusicInfo = useGetter('player', 'playMusicInfo') - const pauseMusic = useDispatch('player', 'pauseMusic') - const playMusic = useDispatch('player', 'playMusic') - const theme = useGetter('common', 'theme') - - // const togglePlayMethod = useGetter('common', 'togglePlayMethod') - // const setPlayNextMode = useDispatch('common', 'setPlayNextMode') - // const toggleNextPlayMode = useCallback(() => { - // let index = playNextModes.indexOf(togglePlayMethod) - // if (++index >= playNextModes.length) index = -1 - // setPlayNextMode(playNextModes[index] || '') - // }, [setPlayNextMode, togglePlayMethod, playNextModes]) - - const btnPrev = useMemo(() => ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playPrev}> - <Icon name='prevMusic' style={{ color: theme.secondary10 }} size={32} /> - </TouchableOpacity> - ), [playPrev, theme]) - - const togglePlay = useCallback(playStatus => { - switch (playStatus) { - case STATUS.playing: - pauseMusic() - break - case STATUS.pause: - case STATUS.stop: - case STATUS.none: - playMusic() - break - // default: - // playMusic(playMusicInfo) - // break - } - }, []) - const btnPlay = useMemo(() => ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={() => togglePlay(playStatus)}> - <Icon name={playStatus == STATUS.playing ? 'pause' : 'play'} style={{ color: theme.secondary10 }} size={32} /> - </TouchableOpacity> - ), [playStatus, theme, togglePlay]) - const btnNext = useMemo(() => ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playNext}> - <Icon name='nextMusic' style={{ color: theme.secondary10 }} size={32} /> - </TouchableOpacity> - ), [playNext, theme]) - - return ( - <> - {/* <TouchableOpacity activeOpacity={0.5} onPress={toggleNextPlayMode}> - <Text style={{ ...styles.cotrolBtn }}> - <Icon name={playModeIcon} style={{ color: theme.secondary10 }} size={18} /> - </Text> - </TouchableOpacity> - */} - {btnPrev} - {btnPlay} - {btnNext} - </> - ) -} - - -const styles = StyleSheet.create({ - cotrolBtn: { - width: 46, - height: 46, - justifyContent: 'center', - alignItems: 'center', - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 1, - }, -}) diff --git a/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/CommentBtn.js b/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/CommentBtn.js deleted file mode 100644 index 586c1b5c8..000000000 --- a/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/CommentBtn.js +++ /dev/null @@ -1,35 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect, useState, useRef } from 'react' -import { Text, StyleSheet, TouchableOpacity } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import { navigations } from '@/navigation' - - -export default memo(() => { - const theme = useGetter('common', 'theme') - const componentIds = useGetter('common', 'componentIds') - - const handleShowCommentScreen = () => { - navigations.pushCommentScreen(componentIds.home) - } - - return ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={handleShowCommentScreen}> - <Icon name="comment" style={{ color: theme.normal30 }} size={24} /> - </TouchableOpacity> - ) -}) - -const styles = StyleSheet.create({ - cotrolBtn: { - marginLeft: 5, - width: 32, - height: 32, - justifyContent: 'center', - alignItems: 'center', - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 1, - }, -}) diff --git a/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/MusicAddBtn.js b/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/MusicAddBtn.js deleted file mode 100644 index e8d62fd11..000000000 --- a/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/MusicAddBtn.js +++ /dev/null @@ -1,47 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect, useState, useRef } from 'react' -import { Text, StyleSheet, TouchableOpacity } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import MusicAddModal from '@/components/MusicAddModal' - - -export default memo(() => { - const theme = useGetter('common', 'theme') - const [visibleMusicAddModal, setVisibleMusicAddModal] = useState(false) - const playMusicInfo = useGetter('player', 'playMusicInfo') - const selectedDataRef = useRef() - const hideMusicAddModal = () => { - setVisibleMusicAddModal(false) - } - - const handleShowMusicAddModal = () => { - selectedDataRef.current = playMusicInfo.musicInfo - setVisibleMusicAddModal(true) - } - - return ( - <> - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={handleShowMusicAddModal}> - <Icon name="add-music" style={{ color: theme.normal30 }} size={24} /> - </TouchableOpacity> - <MusicAddModal - visible={visibleMusicAddModal} - hideModal={hideMusicAddModal} - musicInfo={selectedDataRef.current} /> - </> - ) -}) - -const styles = StyleSheet.create({ - cotrolBtn: { - marginLeft: 5, - width: 32, - height: 32, - justifyContent: 'center', - alignItems: 'center', - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 1, - }, -}) diff --git a/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/TimeoutExit.js b/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/TimeoutExit.js deleted file mode 100644 index 758ed13ec..000000000 --- a/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/TimeoutExit.js +++ /dev/null @@ -1,184 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect, useState, useRef } from 'react' -import { Text, StyleSheet, TouchableOpacity, View } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import ConfirmAlert from '@/components/common/ConfirmAlert' -import { useTranslation } from '@/plugins/i18n' -import Input from '@/components/common/Input' -import { startTimeoutExit, stopTimeoutExit, useTimeoutExitTimeInfo, getTimeoutExitTime, cancelTimeoutExit } from '@/utils/timeoutExit' -import { toast } from '@/utils/tools' -import CheckBox from '@/components/common/CheckBox' - -const MAX_MIN = 1440 -const formatTime = time => { - // let d = parseInt(time / 86400) - // d = d ? d.toString() + ':' : '' - // time = time % 86400 - let h = parseInt(time / 3600) - h = h ? h.toString() + ':' : '' - time = time % 3600 - const m = parseInt(time / 60).toString().padStart(2, '0') - const s = parseInt(time % 60).toString().padStart(2, '0') - return `${h}${m}:${s}` -} -const rxp = /([1-9]\d*)/ -const Status = ({ exitTimeInfo }) => { - const theme = useGetter('common', 'theme') - const { t } = useTranslation() - return ( - <View style={styles.tip}> - { - exitTimeInfo.time < 0 - ? ( - <Text style={{ color: theme.normal }}>{t('timeout_exit_tip_off')}</Text> - ) - : ( - <Text style={{ color: theme.normal }}>{t('timeout_exit_tip_on', { time: formatTime(exitTimeInfo.time) })}</Text> - ) - } - {exitTimeInfo.isPlayedExit ? <Text style={{ fontSize: 12, color: theme.normal40 }}>{t('timeout_exit_btn_wait_tip')}</Text> : null} - </View> - ) -} - -export default memo(() => { - const theme = useGetter('common', 'theme') - const [visibleAlert, setVisibleAlert] = useState(false) - const { t } = useTranslation() - const [text, setText] = useState('') - const exitTimeInfo = useTimeoutExitTimeInfo() - const inputRef = useRef() - const timeoutExit = useGetter('common', 'timeoutExit') - const timeoutExitPlayed = useGetter('common', 'timeoutExitPlayed') - const setTimeoutExit = useDispatch('common', 'setTimeoutExit') - const timeInfo = useMemo(() => { - return exitTimeInfo.time < 0 - ? { cancelText: exitTimeInfo.isPlayedExit ? t('timeout_exit_btn_wait_cancel') : '', confirmText: '', active: false } - : { - cancelText: t('timeout_exit_btn_cancel'), - confirmText: t('timeout_exit_btn_update'), - active: true, - } - }, [exitTimeInfo, t]) - - const handleShowTimeoutAlert = () => { - setText(timeoutExit) - setVisibleAlert(true) - // global.requestAnimationFrame(() => { - // inputRef.current.focus() - // }) - } - const handleAlertHide = () => { - setVisibleAlert(false) - } - const handleAlertCancel = () => { - setVisibleAlert(false) - if (exitTimeInfo.isPlayedExit) { - cancelTimeoutExit() - return - } - if (!timeInfo.active) return - stopTimeoutExit() - toast(t('timeout_exit_tip_cancel')) - } - const handleAlertConfirm = () => { - // if (filterFileName.test(text)) { - // toast(t('create_new_folder_error_tip'), 'long') - // return - // } - const time = parseInt(text) - if (!time) return - cancelTimeoutExit() - startTimeoutExit(time * 60) - setVisibleAlert(false) - toast(t('timeout_exit_tip_on', { time: formatTime(getTimeoutExitTime()) })) - setTimeoutExit({ time: String(time) }) - } - const onChangeText = useCallback(text => { - if (rxp.test(text)) { - if (text != RegExp.$1) toast(t('input_error')) - text = RegExp.$1 - if (parseInt(text) > MAX_MIN) { - toast(t('timeout_exit_tip_max', { num: MAX_MIN })) - text = text.substring(0, text.length - 1) - } - } else { - if (text.length) toast(t('input_error')) - text = '' - } - setText(text) - }, [t]) - - const onCheckChange = check => { - setTimeoutExit({ isPlayed: check }) - } - - - return ( - <> - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={handleShowTimeoutAlert}> - <Icon name="alarm-snooze" style={{ color: timeInfo.active ? theme.secondary20 : theme.normal30 }} size={24} /> - </TouchableOpacity> - <ConfirmAlert - visible={visibleAlert} - onHide={handleAlertHide} - onCancel={handleAlertCancel} - onConfirm={handleAlertConfirm} - cancelText={timeInfo.cancelText} - confirmText={timeInfo.confirmText} - > - <View style={styles.alertContent}> - <Status exitTimeInfo={exitTimeInfo} /> - <View style={styles.inputContent}> - <Input - ref={inputRef} - value={text} - onChangeText={onChangeText} - style={{ ...styles.input, backgroundColor: theme.secondary40 }} /> - <Text style={{ marginLeft: 5, color: theme.normal }}>{t('timeout_exit_min')}</Text> - </View> - <View style={styles.checkbox}> - <CheckBox check={timeoutExitPlayed} label={t('timeout_exit_label_isPlayed')} onChange={onCheckChange} /> - </View> - </View> - </ConfirmAlert> - </> - ) -}) - -const styles = StyleSheet.create({ - cotrolBtn: { - marginLeft: 5, - width: 32, - height: 32, - justifyContent: 'center', - alignItems: 'center', - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 1, - }, - alertContent: { - flexShrink: 1, - flexDirection: 'column', - }, - tip: { - marginBottom: 8, - }, - checkbox: { - marginTop: 5, - }, - inputContent: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - }, - input: { - flexGrow: 1, - flexShrink: 1, - borderRadius: 4, - paddingTop: 2, - paddingBottom: 2, - fontSize: 12, - }, -}) diff --git a/src/screens/PlayDetail/Portrait/Player/components/PlayInfo.js b/src/screens/PlayDetail/Portrait/Player/components/PlayInfo.js deleted file mode 100644 index 8ae7a4ef4..000000000 --- a/src/screens/PlayDetail/Portrait/Player/components/PlayInfo.js +++ /dev/null @@ -1,53 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, StyleSheet, View } from 'react-native' -import { usePlayTime } from '@/utils/hooks' -import { useGetter } from '@/store' - -import Progress from './Progress' -import Status from './Status' - -const PlayTimeCurrent = ({ timeStr }) => { - const theme = useGetter('common', 'theme') - // console.log(timeStr) - return <Text style={{ fontSize: 14, color: theme.normal10 }}>{timeStr}</Text> -} - -const PlayTimeMax = memo(({ timeStr }) => { - const theme = useGetter('common', 'theme') - return <Text style={{ fontSize: 14, color: theme.normal10 }}>{timeStr}</Text> -}) - -export default () => { - const { curTimeStr, maxTimeStr, progress, bufferedProgress, duration } = usePlayTime() - const theme = useGetter('common', 'theme') - - return ( - <> - <View style={styles.progress}><Progress progress={progress} bufferedProgress={bufferedProgress} duration={duration} /></View> - <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}> - <View style={{ flexGrow: 1, flexShrink: 1, paddingRight: 5 }} > - <Status /> - </View> - <View style={{ flexGrow: 0, flexShrink: 0, flexDirection: 'row' }} > - <PlayTimeCurrent timeStr={curTimeStr} /> - <Text style={{ fontSize: 14, color: theme.normal }}> / </Text> - <PlayTimeMax timeStr={maxTimeStr} /> - </View> - </View> - </> - ) -} - - -const styles = StyleSheet.create({ - progress: { - flexGrow: 1, - flexShrink: 0, - flexDirection: 'column', - justifyContent: 'center', - // height: - // position: 'absolute', - // width: '100%', - // top: 0, - }, -}) diff --git a/src/screens/PlayDetail/Portrait/Player/components/Progress.js b/src/screens/PlayDetail/Portrait/Player/components/Progress.js deleted file mode 100644 index 9591402fc..000000000 --- a/src/screens/PlayDetail/Portrait/Player/components/Progress.js +++ /dev/null @@ -1,87 +0,0 @@ -import React, { memo } from 'react' -import { View, StyleSheet, TouchableOpacity, Pressable } from 'react-native' -import { useLayout } from '@/utils/hooks' -import { useGetter, useDispatch } from '@/store' -// import { AppColors } from '@/theme' - - -const DefaultBar = memo(() => { - const theme = useGetter('common', 'theme') - - return <View style={{ ...styles.progressBar, backgroundColor: theme.normal75, position: 'absolute', width: '100%', left: 0, top: 0 }}></View> -}) - -const BufferedBar = memo(({ bufferedProgress }) => { - const theme = useGetter('common', 'theme') - return <View style={{ ...styles.progressBar, backgroundColor: theme.secondary45, position: 'absolute', width: bufferedProgress + '%', left: 0, top: 0 }}></View> -}) - -const PreassBar = memo(({ duration }) => { - const { onLayout, ...layout } = useLayout() - const setProgress = useDispatch('player', 'setProgress') - const handlePress = event => { - setProgress(event.nativeEvent.locationX / layout.width * duration) - } - - return <Pressable onPress={handlePress} onLayout={onLayout} style={styles.pressBar} /> -}) - - -const Progress = ({ progress, bufferedProgress, duration }) => { - // const { progress } = usePlayTimeBuffer() - const theme = useGetter('common', 'theme') - // console.log(progress) - const progressStr = progress + '%' - - return ( - <View style={styles.progress}> - <View> - <DefaultBar /> - <BufferedBar bufferedProgress={bufferedProgress} /> - <View style={{ ...styles.progressBar, backgroundColor: theme.secondary30, width: progressStr, position: 'absolute', left: 0, top: 0 }}> - <Pressable style={{ ...styles.progressDot, backgroundColor: theme.secondary10 }}></Pressable> - </View> - </View> - <PreassBar duration={duration} /> - {/* <View style={{ ...styles.progressBar, height: '100%', width: progressStr }}><Pressable style={styles.progressDot}></Pressable></View> */} - </View> - ) -} - - -const progressContentPadding = 10 -const progressHeight = 3.6 -const progressDotSize = 12 -const styles = StyleSheet.create({ - progress: { - width: '100%', - height: progressContentPadding * 2 + progressHeight, - // backgroundColor: 'rgba(0,0,0,0.5)', - paddingTop: progressContentPadding, - paddingBottom: progressContentPadding, - zIndex: 1, - }, - progressBar: { - height: progressHeight, - borderRadius: 4, - }, - progressDot: { - width: progressDotSize, - height: progressDotSize, - borderRadius: progressDotSize, - position: 'absolute', - right: -progressDotSize / 2, - top: -(progressDotSize - progressHeight) / 2, - zIndex: 9, - }, - pressBar: { - position: 'absolute', - // backgroundColor: 'rgba(0,0,0,0.5)', - left: 0, - top: 0, - height: progressContentPadding * 2 + progressHeight, - width: '100%', - }, -}) - -export default Progress diff --git a/src/screens/PlayDetail/Portrait/Player/components/Status.js b/src/screens/PlayDetail/Portrait/Player/components/Status.js deleted file mode 100644 index 43f2a45fb..000000000 --- a/src/screens/PlayDetail/Portrait/Player/components/Status.js +++ /dev/null @@ -1,25 +0,0 @@ -import React, { memo, useMemo } from 'react' -import { Text } from 'react-native' -import { useGetter } from '@/store' -import { STATUS } from '@/store/modules/player' - - -export default memo(() => { - const theme = useGetter('common', 'theme') - const playStatus = useGetter('player', 'status') - const statusText = useGetter('player', 'statusText') - const status = useMemo(() => { - switch (playStatus) { - case STATUS.playing: - case STATUS.pause: - case STATUS.stop: - return '' - default: return statusText - } - }, [playStatus, statusText]) - return <Text numberOfLines={1} style={{ fontSize: 13, color: theme.normal10 }}>{status}</Text> -}) - -// const styles = StyleSheet.create({ - -// }) diff --git a/src/screens/PlayDetail/Portrait/Player/components/Title.js b/src/screens/PlayDetail/Portrait/Player/components/Title.js deleted file mode 100644 index 689447e14..000000000 --- a/src/screens/PlayDetail/Portrait/Player/components/Title.js +++ /dev/null @@ -1,35 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, View, StyleSheet } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' - -export default () => { - const theme = useGetter('common', 'theme') - const playMusicInfo = useGetter('player', 'playMusicInfo') - const { t } = useTranslation() - const titleInfo = useMemo(() => { - const info = { - name: '', - singer: '', - } - if (playMusicInfo) { - info.name = t('name', { name: playMusicInfo.musicInfo.name }) - info.singer = t('singer', { name: playMusicInfo.musicInfo.singer }) - } - return info - }, [playMusicInfo, t]) - // console.log(playMusicInfo) - return ( - <View style={styles.container}> - <Text style={{ width: '100%', fontSize: 14, color: theme.normal20 }} numberOfLines={2}>{titleInfo.name}</Text> - <Text style={{ width: '100%', fontSize: 14, color: theme.normal20 }} numberOfLines={2}>{titleInfo.singer}</Text> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - flexShrink: 1, - flexGrow: 1, - }, -}) diff --git a/src/screens/PlayDetail/Portrait/components/Header.js b/src/screens/PlayDetail/Portrait/components/Header.js deleted file mode 100644 index fd90c0b45..000000000 --- a/src/screens/PlayDetail/Portrait/components/Header.js +++ /dev/null @@ -1,136 +0,0 @@ -import React, { memo, useState, useCallback } from 'react' - -import { View, StyleSheet, TouchableOpacity, Text } from 'react-native' - -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import { pop } from '@/navigation' -import Popup from '@/components/common/Popup' -import Slider from '@/components/common/Slider' -import { useTranslation } from '@/plugins/i18n' -// import { AppColors } from '@/theme' -import StatusBar from '@/components/common/StatusBar' - -const LrcFontSizeStyles = StyleSheet.create({ - content: { - flexGrow: 0, - flexShrink: 1, - flexDirection: 'row', - flexWrap: 'nowrap', - alignItems: 'center', - paddingLeft: 15, - paddingRight: 15, - }, -}) -const LrcFontSize = () => { - const theme = useGetter('common', 'theme') - const playerPortraitStyle = useGetter('common', 'playerPortraitStyle') - const setPlayerPortraitStyle = useDispatch('common', 'setPlayerPortraitStyle') - const [sliderSize, setSliderSize] = useState(playerPortraitStyle.lrcFontSize) - const [isSliding, setSliding] = useState(false) - - const handleSlidingStart = useCallback(value => { - setSliding(true) - }, []) - const handleValueChange = useCallback(value => { - setSliderSize(value) - }, []) - const handleSlidingComplete = useCallback(value => { - if (playerPortraitStyle.lrcFontSize == value) return - setPlayerPortraitStyle({ ...playerPortraitStyle, lrcFontSize: value }) - setSliding(false) - }, [playerPortraitStyle, setPlayerPortraitStyle]) - - return ( - <View style={LrcFontSizeStyles.content}> - <Text style={{ color: theme.secondary10 }}>{isSliding ? sliderSize : playerPortraitStyle.lrcFontSize}</Text> - <Slider - minimumValue={100} - maximumValue={300} - onSlidingComplete={handleSlidingComplete} - onValueChange={handleValueChange} - onSlidingStart={handleSlidingStart} - step={2} - value={playerPortraitStyle.lrcFontSize} - /> - </View> - ) -} - -const Setting = ({ visible, hide }) => { - const { t } = useTranslation() - return ( - <Popup - visible={visible} - hide={hide} - title={t('player_setting_lrc_font_size')} - > - <LrcFontSize /> - </Popup> - ) -} - -export default memo(() => { - const theme = useGetter('common', 'theme') - const playMusicInfo = useGetter('player', 'playMusicInfo') - const componentIds = useGetter('common', 'componentIds') - - const [settingVisible, setSettingVisible] = useState(false) - - const back = () => { - pop(componentIds.playDetail) - } - const showSetting = () => { - setSettingVisible(true) - } - - return ( - <View style={{ ...styles.header, backgroundColor: theme.primary }} nativeID="header"> - <StatusBar /> - <View style={{ ...styles.container }}> - <TouchableOpacity onPress={back} style={styles.button}> - <Icon name="chevron-left" style={{ color: theme.normal }} size={24} /> - </TouchableOpacity> - <View style={styles.titleContent}> - <Text numberOfLines={1} style={{ ...styles.title, color: theme.normal10 }}>{playMusicInfo.musicInfo?.name}</Text> - <Text numberOfLines={1} style={{ ...styles.title, color: theme.normal20, fontSize: 12 }}>{playMusicInfo.musicInfo?.singer}</Text> - </View> - <TouchableOpacity onPress={showSetting} style={styles.button}> - <Icon name="font-size" style={{ color: theme.normal30 }} size={24} /> - </TouchableOpacity> - </View> - <Setting visible={settingVisible} hide={() => setSettingVisible(false)} /> - </View> - ) -}) - - -const styles = StyleSheet.create({ - header: { - height: 40 + StatusBar.currentHeight, - paddingTop: StatusBar.currentHeight, - }, - container: { - flexDirection: 'row', - // justifyContent: 'center', - height: 40, - }, - button: { - width: 40, - justifyContent: 'center', - alignItems: 'center', - flex: 0, - }, - titleContent: { - flex: 1, - }, - title: { - flex: 1, - textAlign: 'center', - fontSize: 15, - }, - icon: { - paddingLeft: 4, - paddingRight: 4, - }, -}) diff --git a/src/screens/PlayDetail/Vertical/Lyric.tsx b/src/screens/PlayDetail/Vertical/Lyric.tsx new file mode 100644 index 000000000..3df30e74a --- /dev/null +++ b/src/screens/PlayDetail/Vertical/Lyric.tsx @@ -0,0 +1,232 @@ +import React, { memo, useMemo, useEffect, useRef } from 'react' +import { View, FlatList, type FlatListProps } from 'react-native' +// import { useLayout } from '@/utils/hooks' +import { type Line, useLrcPlay, useLrcSet } from '@/plugins/lyric' +import { createStyle } from '@/utils/tools' +// import { useComponentIds } from '@/store/common/hook' +import { useTheme } from '@/store/theme/hook' +import { useSettingValue } from '@/store/setting/hook' +import Text from '@/components/common/Text' +import { scaleSizeH, setSpText } from '@/utils/pixelRatio' +// import { screenkeepAwake } from '@/utils/nativeModules/utils' +// import { log } from '@/utils/log' +// import { toast } from '@/utils/tools' + +type FlatListType = FlatListProps<Line> + +// const useLock = () => { +// const showCommentRef = useRef(false) + + +// useEffect(() => { +// let appstateListener = AppState.addEventListener('change', (state) => { +// switch (state) { +// case 'active': +// if (showLyricRef.current && !showCommentRef.current) screenkeepAwake() +// break +// case 'background': +// screenUnkeepAwake() +// break +// } +// }) +// return () => { +// appstateListener.remove() +// } +// }, []) +// useEffect(() => { +// let listener: ReturnType<typeof onNavigationComponentDidDisappearEvent> +// showCommentRef.current = !!componentIds.comment +// if (showCommentRef.current) { +// if (showLyricRef.current) screenUnkeepAwake() +// listener = onNavigationComponentDidDisappearEvent(componentIds.comment as string, () => { +// if (showLyricRef.current && AppState.currentState == 'active') screenkeepAwake() +// }) +// } + +// const rm = global.state_event.on('componentIdsUpdated', (ids) => { + +// }) + +// return () => { +// if (listener) listener.remove() +// } +// }, []) +// } + +const LrcLine = memo(({ line, lineNum, activeLine }: { + line: Line + lineNum: number + activeLine: number +}) => { + const theme = useTheme() + const playerPortraitStyle = useSettingValue('player.vertical.style.lrcFontSize') + const lineHeight = scaleSizeH(setSpText(playerPortraitStyle) / 10 * 1.25) + + return ( + <View style={styles.line}> + <Text style={{ + ...styles.lineText, + lineHeight, + }} color={activeLine == lineNum ? theme['c-primary'] : theme['c-300']} size={playerPortraitStyle / 10}>{line.text}</Text> + { + line.extendedLyrics.map((lrc, index) => { + return (<Text style={{ + ...styles.lineTranslationText, + lineHeight: lineHeight * 0.8, + }} key={index} color={activeLine == lineNum ? theme['c-primary-alpha-200'] : theme['c-300']} size={playerPortraitStyle / 10 * 0.8}>{lrc}</Text>) + }) + } + </View> + ) +}, (prevProps, nextProps) => { + return prevProps.line === nextProps.line && + prevProps.activeLine != nextProps.lineNum && + nextProps.activeLine != nextProps.lineNum +}) +const wait = async() => new Promise(resolve => setTimeout(resolve, 100)) + +export default () => { + const lyricLines = useLrcSet() + const { line } = useLrcPlay() + const flatListRef = useRef<FlatList>(null) + const isPauseScrollRef = useRef(true) + const scrollTimoutRef = useRef<NodeJS.Timeout | null>(null) + const lineRef = useRef(0) + const isFirstSetLrc = useRef(true) + // useLock() + // const [imgUrl, setImgUrl] = useState(null) + // const theme = useGetter('common', 'theme') + // const { onLayout, ...layout } = useLayout() + + // useEffect(() => { + // const url = playMusicInfo ? playMusicInfo.musicInfo.img : null + // if (imgUrl == url) return + // setImgUrl(url) + // // eslint-disable-next-line react-hooks/exhaustive-deps + // }, [playMusicInfo]) + + // const imgWidth = useMemo(() => layout.width * 0.75, [layout.width]) + const handleScrollToActive = (index = lineRef.current) => { + if (index < 0) return + if (flatListRef.current) { + try { + flatListRef.current.scrollToIndex({ + index, + animated: true, + viewPosition: 0.4, + }) + } catch {} + } + } + + const handleScrollBeginDrag = () => { + isPauseScrollRef.current = true + if (scrollTimoutRef.current) clearTimeout(scrollTimoutRef.current) + scrollTimoutRef.current = setTimeout(() => { + scrollTimoutRef.current = null + isPauseScrollRef.current = false + handleScrollToActive() + }, 3000) + } + + + useEffect(() => { + return () => { + if (scrollTimoutRef.current) { + clearTimeout(scrollTimoutRef.current) + scrollTimoutRef.current = null + } + } + }, []) + + useEffect(() => { + // linesRef.current = lyricLines + if (!flatListRef.current) return + flatListRef.current.scrollToOffset({ + offset: 0, + animated: false, + }) + if (isFirstSetLrc.current) { + isFirstSetLrc.current = false + setTimeout(() => { + isPauseScrollRef.current = false + handleScrollToActive() + }, 100) + } else { + handleScrollToActive(0) + } + }, [lyricLines]) + + useEffect(() => { + lineRef.current = line + if (!flatListRef.current || isPauseScrollRef.current) return + handleScrollToActive() + }, [line]) + + const handleScrollToIndexFailed: FlatListType['onScrollToIndexFailed'] = (info) => { + // console.log(info) + void wait().then(() => { + handleScrollToActive(info.index) + }) + } + + const renderItem: FlatListType['renderItem'] = ({ item, index }) => { + return ( + <LrcLine line={item} lineNum={index} activeLine={line} /> + ) + } + const getkey: FlatListType['keyExtractor'] = (item, index) => `${index}${item.text}` + + const spaceComponent = useMemo(() => ( + <View style={styles.space}></View> + ), []) + + return ( + <FlatList + data={lyricLines} + renderItem={renderItem} + keyExtractor={getkey} + style={styles.container} + ref={flatListRef} + showsVerticalScrollIndicator={false} + ListHeaderComponent={spaceComponent} + ListFooterComponent={spaceComponent} + onScrollBeginDrag={handleScrollBeginDrag} + fadingEdgeLength={200} + initialNumToRender={Math.max(line + 10, 10)} + onScrollToIndexFailed={handleScrollToIndexFailed} + /> + ) +} + +const styles = createStyle({ + container: { + flex: 1, + paddingLeft: 10, + paddingRight: 10, + // backgroundColor: 'rgba(0,0,0,0.1)', + }, + space: { + paddingTop: '80%', + }, + line: { + paddingTop: 8, + paddingBottom: 8, + // opacity: 0, + }, + lineText: { + textAlign: 'center', + // fontSize: 16, + // lineHeight: 20, + // paddingTop: 5, + // paddingBottom: 5, + // opacity: 0, + }, + lineTranslationText: { + textAlign: 'center', + // fontSize: 13, + // lineHeight: 17, + paddingTop: 5, + // paddingBottom: 5, + }, +}) diff --git a/src/screens/PlayDetail/Vertical/Pic.tsx b/src/screens/PlayDetail/Vertical/Pic.tsx new file mode 100644 index 000000000..eca4c34f0 --- /dev/null +++ b/src/screens/PlayDetail/Vertical/Pic.tsx @@ -0,0 +1,81 @@ +import React, { memo, useState } from 'react' +import { View, Image } from 'react-native' +// import { useLayout } from '@/utils/hooks' +import { createStyle } from '@/utils/tools' +import { usePlayerMusicInfo } from '@/store/player/hook' +import { useTheme } from '@/store/theme/hook' +import { BorderRadius } from '@/theme' +import { useDimensions } from '@/utils/hooks' +import Text from '@/components/common/Text' +import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant' +import { useNavigationComponentDidAppear } from '@/navigation' + +const EmptyPic = memo(({ width }: { width: number }) => { + const theme = useTheme() + const size = width * 0.2 + return ( + <View style={{ ...styles.emptyPic, width, height: width, backgroundColor: theme['c-primary-light-900-alpha-200'] }}> + <Text size={size} color={theme['c-primary-light-400-alpha-200']}>L</Text> + <Text size={size} color={theme['c-primary-light-400-alpha-200']} style={styles.text}>X</Text> + </View> + ) +}) + +export default ({ componentId }: { componentId: string }) => { + const musicInfo = usePlayerMusicInfo() + const { window } = useDimensions() + + const [animated, setAnimated] = useState(false) + + useNavigationComponentDidAppear(componentId, () => { + setAnimated(true) + }) + // console.log('render pic') + + const imgWidth = window.width * 0.8 + + return ( + <View style={styles.container}> + <View style={{ ...styles.content, elevation: animated ? 3 : 0 }}> + { + musicInfo.pic + ? ( + <Image source={{ uri: musicInfo.pic }} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} progressiveRenderingEnabled={true} borderRadius={2} style={{ + ...styles.img, + width: imgWidth, + height: imgWidth, + }} /> + ) + : <EmptyPic width={imgWidth} /> + } + </View> + </View> + ) +} + +const styles = createStyle({ + container: { + flexGrow: 1, + flexShrink: 1, + justifyContent: 'center', + alignItems: 'center', + }, + content: { + // elevation: 3, + backgroundColor: 'rgba(0,0,0,0)', + borderRadius: 4, + }, + img: { + borderRadius: 4, + // opacity: 0, + }, + emptyPic: { + borderRadius: BorderRadius.normal, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + }, + text: { + paddingLeft: 2, + }, +}) diff --git a/src/screens/PlayDetail/Vertical/Player/components/ControlBtn.tsx b/src/screens/PlayDetail/Vertical/Player/components/ControlBtn.tsx new file mode 100644 index 000000000..12b7e8355 --- /dev/null +++ b/src/screens/PlayDetail/Vertical/Player/components/ControlBtn.tsx @@ -0,0 +1,65 @@ +import React from 'react' +import { StyleSheet, TouchableOpacity } from 'react-native' +import { Icon } from '@/components/common/Icon' +import { useTheme } from '@/store/theme/hook' +// import { useIsPlay } from '@/store/player/hook' +import { playNext, playPrev, togglePlay } from '@/core/player/player' +import { scaleSizeW } from '@/utils/pixelRatio' +import { useIsPlay } from '@/store/player/hook' + +const WIDTH = scaleSizeW(50) + +const PrevBtn = () => { + const theme = useTheme() + const handlePlayPrev = () => { + void playPrev() + } + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn, width: WIDTH, height: WIDTH }} activeOpacity={0.5} onPress={handlePlayPrev}> + <Icon name='prevMusic' color={theme['c-button-font']} size={38} /> + </TouchableOpacity> + ) +} +const NextBtn = () => { + const theme = useTheme() + const handlePlayNext = () => { + void playNext() + } + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn, width: WIDTH, height: WIDTH }} activeOpacity={0.5} onPress={handlePlayNext}> + <Icon name='nextMusic' color={theme['c-button-font']} size={38} /> + </TouchableOpacity> + ) +} + +const TogglePlayBtn = () => { + const theme = useTheme() + const isPlay = useIsPlay() + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn, width: WIDTH, height: WIDTH }} activeOpacity={0.5} onPress={togglePlay}> + <Icon name={isPlay ? 'pause' : 'play'} color={theme['c-button-font']} size={38} /> + </TouchableOpacity> + ) +} + +export default () => { + return ( + <> + <PrevBtn /> + <TogglePlayBtn /> + <NextBtn /> + </> + ) +} + + +const styles = StyleSheet.create({ + cotrolBtn: { + justifyContent: 'center', + alignItems: 'center', + + // backgroundColor: '#ccc', + shadowOpacity: 1, + textShadowRadius: 1, + }, +}) diff --git a/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/Btn.tsx b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/Btn.tsx new file mode 100644 index 000000000..9f7e2fbc1 --- /dev/null +++ b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/Btn.tsx @@ -0,0 +1,34 @@ +import React from 'react' +import { TouchableOpacity } from 'react-native' +import { Icon } from '@/components/common/Icon' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { scaleSizeW } from '@/utils/pixelRatio' + +export const BTN_WIDTH = scaleSizeW(32) +export const BTN_ICON_SIZE = 22 + +export default ({ icon, color, onPress }: { + icon: string + color?: string + onPress: () => void +}) => { + const theme = useTheme() + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn, width: BTN_WIDTH, height: BTN_WIDTH }} activeOpacity={0.5} onPress={onPress}> + <Icon name={icon} color={color ?? theme['c-font-label']} size={BTN_ICON_SIZE} /> + </TouchableOpacity> + ) +} + +const styles = createStyle({ + cotrolBtn: { + marginLeft: 5, + justifyContent: 'center', + alignItems: 'center', + + // backgroundColor: '#ccc', + shadowOpacity: 1, + textShadowRadius: 1, + }, +}) diff --git a/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/CommentBtn.tsx b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/CommentBtn.tsx new file mode 100644 index 000000000..4cb35e320 --- /dev/null +++ b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/CommentBtn.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import Btn from './Btn' +import { useComponentIds } from '@/store/common/hook' +import { navigations } from '@/navigation' + + +export default () => { + const componentIds = useComponentIds() + + const handleShowCommentScreen = () => { + navigations.pushCommentScreen(componentIds.playDetail as string) + } + + return <Btn icon="comment" onPress={handleShowCommentScreen} /> +} diff --git a/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/MusicAddBtn.tsx b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/MusicAddBtn.tsx new file mode 100644 index 000000000..ed2e3c3bb --- /dev/null +++ b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/MusicAddBtn.tsx @@ -0,0 +1,26 @@ +import React, { useRef } from 'react' +import MusicAddModal, { MusicAddModalType } from '@/components/MusicAddModal' +import playerState from '@/store/player/state' +import Btn from './Btn' + + +export default () => { + const musicAddModalRef = useRef<MusicAddModalType>(null) + + const handleShowMusicAddModal = () => { + const musicInfo = playerState.playMusicInfo.musicInfo + if (!musicInfo) return + musicAddModalRef.current?.show({ + musicInfo: 'progress' in musicInfo ? musicInfo.metadata.musicInfo : musicInfo, + isMove: false, + listId: playerState.playMusicInfo.listId as string, + }) + } + + return ( + <> + <Btn icon="add-music" onPress={handleShowMusicAddModal} /> + <MusicAddModal ref={musicAddModalRef} /> + </> + ) +} diff --git a/src/screens/PlayDetail/Landscape/MoreBtn/PlayModeBtn.js b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/PlayModeBtn.tsx similarity index 56% rename from src/screens/PlayDetail/Landscape/MoreBtn/PlayModeBtn.js rename to src/screens/PlayDetail/Vertical/Player/components/MoreBtn/PlayModeBtn.tsx index 1746a2d78..35227f819 100644 --- a/src/screens/PlayDetail/Landscape/MoreBtn/PlayModeBtn.js +++ b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/PlayModeBtn.tsx @@ -1,23 +1,22 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, StyleSheet, TouchableOpacity } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' +import React, { memo, useMemo } from 'react' import { toast } from '@/utils/tools' -import { useTranslation } from '@/plugins/i18n' import { MUSIC_TOGGLE_MODE_LIST, MUSIC_TOGGLE_MODE } from '@/config/constant' +import { useSettingValue } from '@/store/setting/hook' +import { useI18n } from '@/lang' +import { updateSetting } from '@/core/common' +import Btn from './Btn' -export default memo(({ width }) => { - const togglePlayMethod = useGetter('common', 'togglePlayMethod') - const theme = useGetter('common', 'theme') - const setPlayNextMode = useDispatch('common', 'setPlayNextMode') - const { t } = useTranslation() + +export default memo(() => { + const togglePlayMethod = useSettingValue('player.togglePlayMethod') + const t = useI18n() const toggleNextPlayMode = () => { let index = MUSIC_TOGGLE_MODE_LIST.indexOf(togglePlayMethod) if (++index >= MUSIC_TOGGLE_MODE_LIST.length) index = 0 const mode = MUSIC_TOGGLE_MODE_LIST[index] - setPlayNextMode(mode || '') - let modeName + updateSetting({ 'player.togglePlayMethod': mode }) + let modeName: 'play_list_loop' | 'play_list_random' | 'play_list_order' | 'play_single_loop' | 'play_single' switch (mode) { case MUSIC_TOGGLE_MODE.listLoop: modeName = 'play_list_loop' @@ -60,23 +59,5 @@ export default memo(({ width }) => { return playModeIcon }, [togglePlayMethod]) - return ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={toggleNextPlayMode}> - <Icon name={playModeIcon} style={{ color: theme.normal30 }} size={width} /> - </TouchableOpacity> - ) -}) - -const styles = StyleSheet.create({ - cotrolBtn: { - marginRight: '1%', - width: '25%', - aspectRatio: 1, - justifyContent: 'center', - alignItems: 'center', - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 1, - }, + return <Btn icon={playModeIcon} onPress={toggleNextPlayMode} /> }) diff --git a/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/TimeoutExitBtn.tsx b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/TimeoutExitBtn.tsx new file mode 100644 index 000000000..4af732043 --- /dev/null +++ b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/TimeoutExitBtn.tsx @@ -0,0 +1,23 @@ +import React, { memo, useRef } from 'react' +import TimeoutExitEditModal, { TimeoutExitEditModalType, useTimeInfo } from '@/components/TimeoutExitEditModal' +import { useTheme } from '@/store/theme/hook' +import Btn from './Btn' + + +export default memo(() => { + const theme = useTheme() + const modalRef = useRef<TimeoutExitEditModalType>(null) + + const timeInfo = useTimeInfo() + + const handleShow = () => { + modalRef.current?.show() + } + + return ( + <> + <Btn icon="music_time" color={timeInfo.active ? theme['c-primary-font-active'] : theme['c-font-label']} onPress={handleShow} /> + <TimeoutExitEditModal ref={modalRef} timeInfo={timeInfo} /> + </> + ) +}) diff --git a/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/index.js b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/index.tsx similarity index 66% rename from src/screens/PlayDetail/Portrait/Player/components/MoreBtn/index.js rename to src/screens/PlayDetail/Vertical/Player/components/MoreBtn/index.tsx index 81967e61a..edb0bae2d 100644 --- a/src/screens/PlayDetail/Portrait/Player/components/MoreBtn/index.js +++ b/src/screens/PlayDetail/Vertical/Player/components/MoreBtn/index.tsx @@ -1,23 +1,24 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { View, StyleSheet } from 'react-native' +import { createStyle } from '@/utils/tools' +import React from 'react' +import { View } from 'react-native' import PlayModeBtn from './PlayModeBtn' import MusicAddBtn from './MusicAddBtn' -import TimeoutExit from './TimeoutExit' +import TimeoutExitBtn from './TimeoutExitBtn' import CommentBtn from './CommentBtn' export default () => { return ( <View style={styles.container}> - <TimeoutExit /> - <PlayModeBtn /> + <TimeoutExitBtn /> <MusicAddBtn /> + <PlayModeBtn /> <CommentBtn /> </View> ) } -const styles = StyleSheet.create({ +const styles = createStyle({ container: { flexShrink: 0, flexGrow: 0, diff --git a/src/screens/PlayDetail/Vertical/Player/components/PlayInfo.tsx b/src/screens/PlayDetail/Vertical/Player/components/PlayInfo.tsx new file mode 100644 index 000000000..85aaa35f5 --- /dev/null +++ b/src/screens/PlayDetail/Vertical/Player/components/PlayInfo.tsx @@ -0,0 +1,66 @@ +import React, { memo } from 'react' +import { View } from 'react-native' + +import Progress from './Progress' +import Status from './Status' +import { useProgress } from '@/store/player/hook' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' + +// const FONT_SIZE = 13 + +const PlayTimeCurrent = ({ timeStr }: { timeStr: string }) => { + const theme = useTheme() + // console.log(timeStr) + return <Text color={theme['c-500']}>{timeStr}</Text> +} + +const PlayTimeMax = memo(({ timeStr }: { timeStr: string }) => { + const theme = useTheme() + return <Text color={theme['c-500']}>{timeStr}</Text> +}) + +export default () => { + const theme = useTheme() + const { maxPlayTimeStr, nowPlayTimeStr, progress, maxPlayTime } = useProgress() + // console.log('render playInfo') + + return ( + <> + <View style={styles.progress}><Progress progress={progress} duration={maxPlayTime} /></View> + <View style={styles.info}> + {/* <MusicName /> */} + <View style={styles.status} > + <Status /> + </View> + <View style={{ flexGrow: 0, flexShrink: 0, flexDirection: 'row' }} > + <PlayTimeCurrent timeStr={nowPlayTimeStr} /> + <Text color={theme['c-500']}> / </Text> + <PlayTimeMax timeStr={maxPlayTimeStr} /> + </View> + </View> + </> + ) +} + + +const styles = createStyle({ + progress: { + flexGrow: 1, + flexShrink: 0, + flexDirection: 'column', + justifyContent: 'center', + }, + info: { + flexDirection: 'row', + justifyContent: 'space-between', + // alignItems: 'center', + // backgroundColor: '#ccc', + }, + status: { + flexGrow: 1, + flexShrink: 1, + paddingRight: 5, + }, +}) diff --git a/src/screens/PlayDetail/Vertical/Player/components/Progress.tsx b/src/screens/PlayDetail/Vertical/Player/components/Progress.tsx new file mode 100644 index 000000000..2940104f9 --- /dev/null +++ b/src/screens/PlayDetail/Vertical/Player/components/Progress.tsx @@ -0,0 +1,104 @@ +import React, { memo, useMemo } from 'react' +import { View, Pressable, GestureResponderEvent } from 'react-native' +import { useLayout } from '@/utils/hooks' +import { createStyle } from '@/utils/tools' +import { useTheme } from '@/store/theme/hook' +import { scaleSizeW } from '@/utils/pixelRatio' +// import { AppColors } from '@/theme' + + +const DefaultBar = memo(() => { + const theme = useTheme() + + return <View style={{ ...styles.progressBar, backgroundColor: theme['c-primary-light-100-alpha-800'], position: 'absolute', width: '100%', left: 0, top: 0 }}></View> +}) + +// const BufferedBar = memo(({ bufferedProgress }) => { +// // console.log(bufferedProgress) +// const theme = useTheme() +// return <View style={{ ...styles.progressBar, backgroundColor: theme.secondary45, position: 'absolute', width: bufferedProgress + '%', left: 0, top: 0 }}></View> +// }) + +const PreassBar = memo(({ duration }: { duration: number }) => { + const { onLayout, ...layout } = useLayout() + const handlePress = (event: GestureResponderEvent) => { + global.app_event.setProgress(event.nativeEvent.locationX / layout.width * duration) + } + + return <Pressable onPress={handlePress} onLayout={onLayout} style={styles.pressBar} /> +}) + + +const Progress = ({ progress, duration }: { + progress: number + duration: number +}) => { + // const { progress } = usePlayTimeBuffer() + const theme = useTheme() + // console.log(progress) + const progressStr = `${progress * 100}%` + + const progressDotStyle = useMemo(() => { + return { + width: progressDotSize, + height: progressDotSize, + borderRadius: progressDotSize, + position: 'absolute', + right: -progressDotSize / 2, + top: -(progressDotSize - progressHeight) / 2, + backgroundColor: theme['c-primary-light-100'], + zIndex: 9, + } as const + }, [theme]) + + return ( + <View style={styles.progress}> + <View> + <DefaultBar /> + {/* <BufferedBar bufferedProgress={bufferedProgress} /> */} + <View style={{ ...styles.progressBar, backgroundColor: theme['c-primary-light-100-alpha-400'], width: progressStr, position: 'absolute', left: 0, top: 0 }}> + <Pressable style={{ ...styles.progressDot, ...progressDotStyle }}></Pressable> + </View> + </View> + <PreassBar duration={duration} /> + {/* <View style={{ ...styles.progressBar, height: '100%', width: progressStr }}><Pressable style={styles.progressDot}></Pressable></View> */} + </View> + ) +} + +const progressContentPadding = 10 +const progressHeight = 3.6 +const progressDotSize = scaleSizeW(12) +const styles = createStyle({ + progress: { + width: '100%', + height: progressContentPadding * 2 + progressHeight, + // backgroundColor: 'rgba(0,0,0,0.5)', + paddingTop: progressContentPadding, + paddingBottom: progressContentPadding, + zIndex: 1, + }, + progressBar: { + height: progressHeight, + borderRadius: 4, + }, + progressDot: { + width: progressDotSize, + height: progressDotSize, + borderRadius: progressDotSize, + position: 'absolute', + right: -progressDotSize / 2, + top: -(progressDotSize - progressHeight) / 2, + zIndex: 9, + }, + pressBar: { + position: 'absolute', + // backgroundColor: 'rgba(0,0,0,0.5)', + left: 0, + top: 0, + height: progressContentPadding * 2 + progressHeight, + width: '100%', + }, +}) + +export default Progress diff --git a/src/screens/PlayDetail/Vertical/Player/components/Status.tsx b/src/screens/PlayDetail/Vertical/Player/components/Status.tsx new file mode 100644 index 000000000..2c473f93e --- /dev/null +++ b/src/screens/PlayDetail/Vertical/Player/components/Status.tsx @@ -0,0 +1,22 @@ +import React from 'react' +// import { useLrcPlay } from '@/plugins/lyric' +import { useStatusText } from '@/store/player/hook' +// import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' + + +export default () => { + // const { text } = useLrcPlay() + const statusText = useStatusText() + // console.log('render status') + + // const status = playerStatus.isPlay ? text : playerStatus.statusText + + return <Text numberOfLines={1} size={13}>{statusText}</Text> +} + +// const styles = createStyle({ +// text: { +// fontSize: 10, +// }, +// }) diff --git a/src/screens/PlayDetail/Portrait/Player/index.js b/src/screens/PlayDetail/Vertical/Player/index.tsx similarity index 64% rename from src/screens/PlayDetail/Portrait/Player/index.js rename to src/screens/PlayDetail/Vertical/Player/index.tsx index 577af2fe8..0734c24b8 100644 --- a/src/screens/PlayDetail/Portrait/Player/index.js +++ b/src/screens/PlayDetail/Vertical/Player/index.tsx @@ -1,21 +1,17 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { View, Text, StyleSheet } from 'react-native' -import { useLayout, useKeyboard } from '@/utils/hooks' -import { useGetter, useDispatch } from '@/store' -import { BorderWidths } from '@/theme' +import React, { memo } from 'react' +import { View } from 'react-native' // import Title from './components/Title' import MoreBtn from './components/MoreBtn' import PlayInfo from './components/PlayInfo' import ControlBtn from './components/ControlBtn' +import { createStyle } from '@/utils/tools' +import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant' -export default memo(({ playNextModes }) => { - // const { onLayout, ...layout } = useLayout() - const theme = useGetter('common', 'theme') - +export default memo(() => { return ( - <View style={{ ...styles.container, backgroundColor: theme.primary }}> + <View style={styles.container} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_player}> <View style={{ ...styles.info }} > {/* <Title /> */} <MoreBtn /> @@ -24,13 +20,13 @@ export default memo(({ playNextModes }) => { <PlayInfo /> </View> <View style={styles.control}> - <ControlBtn playNextModes={playNextModes} /> + <ControlBtn /> </View> </View> ) }) -const styles = StyleSheet.create({ +const styles = createStyle({ container: { width: '100%', // paddingTop: progressContentPadding, @@ -57,10 +53,10 @@ const styles = StyleSheet.create({ justifyContent: 'space-evenly', flexGrow: 0, flexShrink: 0, - paddingLeft: '15%', - paddingRight: '15%', + paddingLeft: '10%', + paddingRight: '10%', paddingTop: '9.5%', - paddingBottom: '8.5%', + paddingBottom: '8%', }, row: { flexDirection: 'row', diff --git a/src/screens/PlayDetail/Vertical/components/Header.tsx b/src/screens/PlayDetail/Vertical/components/Header.tsx new file mode 100644 index 000000000..9e820be9c --- /dev/null +++ b/src/screens/PlayDetail/Vertical/components/Header.tsx @@ -0,0 +1,143 @@ +import React, { memo, useRef, useState } from 'react' + +import { View, StyleSheet, TouchableOpacity } from 'react-native' + +import { Icon } from '@/components/common/Icon' +import { pop } from '@/navigation' +// import { AppColors } from '@/theme' +import StatusBar from '@/components/common/StatusBar' +// import commonState from '@/store/common/state' +import { useTheme } from '@/store/theme/hook' +import { usePlayerMusicInfo } from '@/store/player/hook' +import Text from '@/components/common/Text' +import { scaleSizeH } from '@/utils/pixelRatio' +import { HEADER_HEIGHT as _HEADER_HEIGHT, NAV_SHEAR_NATIVE_IDS } from '@/config/constant' +import commonState from '@/store/common/state' +import { createStyle } from '@/utils/tools' +import { useSettingValue } from '@/store/setting/hook' +import Slider, { type SliderProps } from '@/components/common/Slider' +import { updateSetting } from '@/core/common' +import Popup, { type PopupType } from '@/components/common/Popup' +import { useI18n } from '@/lang' + +const HEADER_HEIGHT = scaleSizeH(_HEADER_HEIGHT) + +const LrcFontSizeStyles = createStyle({ + content: { + flexGrow: 0, + flexShrink: 1, + flexDirection: 'row', + flexWrap: 'nowrap', + alignItems: 'center', + paddingLeft: 15, + paddingRight: 15, + }, +}) +const LrcFontSize = () => { + const theme = useTheme() + const lrcFontSize = useSettingValue('player.vertical.style.lrcFontSize') + const [sliderSize, setSliderSize] = useState(lrcFontSize) + const [isSliding, setSliding] = useState(false) + + const handleSlidingStart: SliderProps['onSlidingStart'] = value => { + setSliding(true) + } + const handleValueChange: SliderProps['onValueChange'] = value => { + setSliderSize(value) + } + const handleSlidingComplete: SliderProps['onSlidingComplete'] = value => { + if (lrcFontSize == value) return + updateSetting({ 'player.vertical.style.lrcFontSize': value }) + setSliding(false) + } + + return ( + <View style={LrcFontSizeStyles.content}> + <Text color={theme['c-font-label']}>{isSliding ? sliderSize : lrcFontSize}</Text> + <Slider + minimumValue={100} + maximumValue={300} + onSlidingComplete={handleSlidingComplete} + onValueChange={handleValueChange} + onSlidingStart={handleSlidingStart} + step={2} + value={lrcFontSize} + /> + </View> + ) +} + +const Title = () => { + const theme = useTheme() + const musicInfo = usePlayerMusicInfo() + + + return ( + <View style={styles.titleContent}> + <Text numberOfLines={1} style={styles.title}>{musicInfo.name}</Text> + <Text numberOfLines={1} style={styles.title} size={12} color={theme['c-font-label']}>{musicInfo.singer}</Text> + </View> + ) +} + +export default memo(() => { + const t = useI18n() + // const theme = useTheme() + + // const [settingVisible, setSettingVisible] = useState(false) + const popupRef = useRef<PopupType>(null) + + const back = () => { + // navigation.goBack() + void pop(commonState.componentIds.playDetail as string) + } + const showSetting = () => { + popupRef.current?.setVisible(true) + } + + return ( + <View style={{ height: HEADER_HEIGHT + StatusBar.currentHeight, paddingTop: StatusBar.currentHeight }} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_header}> + <StatusBar /> + <View style={styles.container}> + <TouchableOpacity onPress={back} style={{ ...styles.button, width: HEADER_HEIGHT }}> + <Icon name="chevron-left" size={18} /> + </TouchableOpacity> + <Title /> + <TouchableOpacity onPress={showSetting} style={{ ...styles.button, width: HEADER_HEIGHT }}> + <Icon name="font-size" size={18} /> + </TouchableOpacity> + </View> + <Popup ref={popupRef} title={t('player_setting_lrc_font_size')}> + <LrcFontSize /> + </Popup> + </View> + ) +}) + + +const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + // justifyContent: 'center', + height: '100%', + }, + button: { + justifyContent: 'center', + alignItems: 'center', + height: '100%', + flex: 0, + }, + titleContent: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + }, + title: { + // flex: 1, + // textAlign: 'center', + }, + icon: { + paddingLeft: 4, + paddingRight: 4, + }, +}) diff --git a/src/screens/PlayDetail/Portrait/index.js b/src/screens/PlayDetail/Vertical/index.tsx similarity index 59% rename from src/screens/PlayDetail/Portrait/index.js rename to src/screens/PlayDetail/Vertical/index.tsx index f97c090d0..080185d14 100644 --- a/src/screens/PlayDetail/Portrait/index.js +++ b/src/screens/PlayDetail/Vertical/index.tsx @@ -1,18 +1,18 @@ -import React, { useEffect, useCallback, memo, useState, useMemo, useRef } from 'react' +import React, { memo, useState, useRef, useMemo, useEffect } from 'react' import { View, StyleSheet, AppState } from 'react-native' import Header from './components/Header' // import Aside from './components/Aside' // import Main from './components/Main' import Player from './Player' -import { useGetter, useDispatch } from '@/store' -import PagerView from 'react-native-pager-view' +import PagerView, { type PagerViewOnPageSelectedEvent } from 'react-native-pager-view' import Pic from './Pic' import Lyric from './Lyric' -import { screenkeepAwake, screenUnkeepAwake } from '@/utils/utils' -import { onNavigationComponentDidDisappearEvent } from '@/navigation' +import { screenkeepAwake, screenUnkeepAwake } from '@/utils/nativeModules/utils' +import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant' +import commonState, { type InitState as CommonState } from '@/store/common/state' -const LyricPage = ({ activeIndex }) => { +const LyricPage = ({ activeIndex }: { activeIndex: number }) => { const initedRef = useRef(false) const lyric = useMemo(() => <Lyric />, []) switch (activeIndex) { @@ -27,74 +27,69 @@ const LyricPage = ({ activeIndex }) => { } // global.iskeep = false -export default memo(({ componentId, animated }) => { - const theme = useGetter('common', 'theme') +export default memo(({ componentId }: { componentId: string }) => { + // const theme = useTheme() const [pageIndex, setPageIndex] = useState(0) - const componentIds = useGetter('common', 'componentIds') const showLyricRef = useRef(false) - const showCommentRef = useRef(false) - useEffect(() => { - let listener - showCommentRef.current = !!componentIds.comment - if (showCommentRef.current) { - if (showLyricRef.current) screenUnkeepAwake() - listener = onNavigationComponentDidDisappearEvent(componentIds.comment, () => { - if (showLyricRef.current && AppState.currentState == 'active') screenkeepAwake() - }) - } - return () => { - if (listener) listener.remove() + const onPageSelected = ({ nativeEvent }: PagerViewOnPageSelectedEvent) => { + setPageIndex(nativeEvent.position) + showLyricRef.current = nativeEvent.position == 1 + if (showLyricRef.current) { + screenkeepAwake() + } else { + screenUnkeepAwake() } - }, [componentIds]) + } useEffect(() => { let appstateListener = AppState.addEventListener('change', (state) => { switch (state) { case 'active': - if (showLyricRef.current && !showCommentRef.current) screenkeepAwake() + if (showLyricRef.current && !commonState.componentIds.comment) screenkeepAwake() break case 'background': screenUnkeepAwake() break } }) - return () => { - appstateListener.remove() + + const handleComponentIdsChange = (ids: CommonState['componentIds']) => { + if (ids.comment) screenUnkeepAwake() + else if (AppState.currentState == 'active') screenkeepAwake() } - }, []) - const onPageSelected = useCallback(({ nativeEvent }) => { - setPageIndex(nativeEvent.position) - showLyricRef.current = nativeEvent.position == 1 - if (showLyricRef.current) { - screenkeepAwake() - } else { + global.state_event.on('componentIdsUpdated', handleComponentIdsChange) + + return () => { + global.state_event.off('componentIdsUpdated', handleComponentIdsChange) + appstateListener.remove() screenUnkeepAwake() } + // eslint-disable-next-line react-hooks/exhaustive-deps }, []) return ( <> <Header /> - <View style={{ flex: 1, flexDirection: 'column', height: '100%', backgroundColor: theme.primary }}> + <View style={{ flex: 1, flexDirection: 'column' }}> <PagerView onPageSelected={onPageSelected} // onPageScrollStateChanged={onPageScrollStateChanged} style={styles.pagerView} > - <View collapsable={false} style={styles.pageStyle}> - <Pic componentId={componentId} animated={animated} /> + <View collapsable={false}> + <Pic componentId={componentId} /> </View> - <View collapsable={false} style={styles.pageStyle}> + <View collapsable={false}> <LyricPage activeIndex={pageIndex} /> </View> </PagerView> - <View style={styles.pageIndicator} nativeID="pageIndicator"> + {/* <View style={styles.pageIndicator} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pageIndicator}> <View style={{ ...styles.pageIndicatorItem, backgroundColor: pageIndex == 0 ? theme.secondary20 : theme.normal60 }}></View> <View style={{ ...styles.pageIndicatorItem, backgroundColor: pageIndex == 1 ? theme.secondary20 : theme.normal60 }}></View> - </View> - <View style={styles.player} nativeID="player"> + </View> */} + <View style={styles.player} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_player}> <Player /> </View> </View> diff --git a/src/screens/PlayDetail/index.js b/src/screens/PlayDetail/index.js deleted file mode 100644 index 60d1c12ca..000000000 --- a/src/screens/PlayDetail/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import React, { useEffect, useState } from 'react' -// import { View, StyleSheet } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import { useDimensions } from '@/utils/hooks' -import { useNavigationComponentDidDisappear, useNavigationComponentDidAppear } from '@/navigation' -import { screenUnkeepAwake } from '@/utils/utils' - -import Portrait from './Portrait' -import Landscape from './Landscape' - -export default (props) => { - // const theme = useGetter('common', 'theme') - const setComponentId = useDispatch('common', 'setComponentId') - const [animated, setAnimated] = useState(false) - const { window } = useDimensions() - useEffect(() => { - setComponentId({ name: 'playDetail', id: props.componentId }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - useNavigationComponentDidDisappear(props.componentId, () => { - screenUnkeepAwake() - }) - useNavigationComponentDidAppear(props.componentId, () => { - setAnimated(true) - }) - - return ( - window.height > window.width - ? <Portrait componentId={props.componentId} animated={animated} /> - : <Landscape componentId={props.componentId} animated={animated} /> - ) -} diff --git a/src/screens/PlayDetail/index.tsx b/src/screens/PlayDetail/index.tsx new file mode 100644 index 000000000..232f78325 --- /dev/null +++ b/src/screens/PlayDetail/index.tsx @@ -0,0 +1,30 @@ +import React, { useEffect } from 'react' +// import { View, StyleSheet } from 'react-native' +import { useDimensions } from '@/utils/hooks' + +import Vertical from './Vertical' +import Horizontal from './Horizontal' +import PageContent from '@/components/PageContent' +import StatusBar from '@/components/common/StatusBar' +import { setComponentId } from '@/core/common' +import { COMPONENT_IDS } from '@/config/constant' + +export default ({ componentId }: { componentId: string }) => { + const { window } = useDimensions() + + useEffect(() => { + setComponentId(COMPONENT_IDS.playDetail, componentId) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + return ( + <PageContent> + <StatusBar /> + { + window.height > window.width + ? <Vertical componentId={componentId} /> + : <Horizontal componentId={componentId} /> + } + </PageContent> + ) +} diff --git a/src/screens/SonglistDetail/ActionBar.js b/src/screens/SonglistDetail/ActionBar.js deleted file mode 100644 index 3d5eaae5b..000000000 --- a/src/screens/SonglistDetail/ActionBar.js +++ /dev/null @@ -1,90 +0,0 @@ -import React, { useCallback, memo } from 'react' -import { View, Text, StyleSheet } from 'react-native' -import Button from '@/components/common/Button' - -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' -import { toast } from '@/utils/tools' -import { LIST_ID_PLAY_TEMP } from '@/config/constant' -import { pop } from '@/navigation' - -export default memo(() => { - const selectListInfo = useGetter('songList', 'selectListInfo') - const listDetailData = useGetter('songList', 'listDetailData') - const setPlayList = useDispatch('player', 'setList') - // const setVisibleListDetail = useDispatch('songList', 'setVisibleListDetail') - const getListDetailAll = useDispatch('songList', 'getListDetailAll') - const createUserList = useDispatch('list', 'createUserList') - const { t } = useTranslation() - const theme = useGetter('common', 'theme') - const songListSource = useGetter('songList', 'songListSource') - const componentIds = useGetter('common', 'componentIds') - - const back = () => { - pop(componentIds.songlistDetail) - } - - const handlePlayAll = useCallback(async() => { - if (!listDetailData.info.name) return - const list = await getListDetailAll({ id: selectListInfo.id, source: songListSource }) - // if (!list.length) return - setPlayList({ - list: { - list, - id: LIST_ID_PLAY_TEMP, - }, - index: 0, - }) - }, [getListDetailAll, listDetailData, selectListInfo, setPlayList, songListSource]) - - const handleCollection = useCallback(async() => { - if (!listDetailData.info.name) return - const list = await getListDetailAll({ id: selectListInfo.id, source: songListSource }) - createUserList({ - name: listDetailData.info.name || `${listDetailData.source}-list`, - id: `${listDetailData.source}__${listDetailData.id}`, - list, - source: listDetailData.source, - sourceListId: listDetailData.id, - isShowToast: true, - }) - toast(t('collect_success')) - }, [listDetailData, getListDetailAll, selectListInfo, songListSource, createUserList, t]) - - return ( - <View style={styles.container}> - <Button onPress={handleCollection} style={styles.controlBtn}> - <Text style={{ ...styles.controlBtnText, color: theme.secondary }}>{t('collect_songlist')}</Text> - </Button> - <Button onPress={handlePlayAll} style={styles.controlBtn}> - <Text style={{ ...styles.controlBtnText, color: theme.secondary }}>{t('play_all')}</Text> - </Button> - <Button onPress={back} style={styles.controlBtn}> - <Text style={{ ...styles.controlBtnText, color: theme.secondary }}>{t('back')}</Text> - </Button> - </View> - ) -}) - -const styles = StyleSheet.create({ - container: { - flexDirection: 'row', - width: '100%', - flexGrow: 0, - flexShrink: 0, - }, - controlBtn: { - flexGrow: 1, - flexShrink: 1, - width: '33%', - paddingTop: 12, - paddingBottom: 12, - paddingLeft: 10, - paddingRight: 10, - }, - controlBtnText: { - fontSize: 13, - textAlign: 'center', - }, -}) - diff --git a/src/screens/SonglistDetail/ActionBar.tsx b/src/screens/SonglistDetail/ActionBar.tsx new file mode 100644 index 000000000..5c7909b26 --- /dev/null +++ b/src/screens/SonglistDetail/ActionBar.tsx @@ -0,0 +1,69 @@ +import React, { memo } from 'react' +import { View } from 'react-native' +import Button from '@/components/common/Button' + +import { createStyle } from '@/utils/tools' +import { pop } from '@/navigation' +import { useTheme } from '@/store/theme/hook' +import commonState from '@/store/common/state' +import Text from '@/components/common/Text' +import { handleCollect, handlePlay } from './listAction' +import songlistState from '@/store/songlist/state' +import { useI18n } from '@/lang' +// import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant' + +export default memo(() => { + const theme = useTheme() + const t = useI18n() + + const back = () => { + void pop(commonState.componentIds.songlistDetail as string) + } + + const handlePlayAll = () => { + if (!songlistState.listDetailInfo.info.name) return + void handlePlay(songlistState.selectListInfo.id, songlistState.selectListInfo.source, songlistState.listDetailInfo.list) + } + + const handleCollection = () => { + if (!songlistState.listDetailInfo.info.name) return + void handleCollect(songlistState.selectListInfo.id, songlistState.selectListInfo.source, songlistState.listDetailInfo.info.name || songlistState.selectListInfo.name) + } + + return ( + <View style={styles.container}> + <Button onPress={handleCollection} style={styles.controlBtn}> + <Text style={{ ...styles.controlBtnText, color: theme['c-button-font'] }}>{t('collect_songlist')}</Text> + </Button> + <Button onPress={handlePlayAll} style={styles.controlBtn}> + <Text style={{ ...styles.controlBtnText, color: theme['c-button-font'] }}>{t('play_all')}</Text> + </Button> + <Button onPress={back} style={styles.controlBtn}> + <Text style={{ ...styles.controlBtnText, color: theme['c-button-font'] }}>{t('back')}</Text> + </Button> + </View> + ) +}) + +const styles = createStyle({ + container: { + flexDirection: 'row', + width: '100%', + flexGrow: 0, + flexShrink: 0, + }, + controlBtn: { + flexGrow: 1, + flexShrink: 1, + width: '33%', + paddingTop: 12, + paddingBottom: 12, + paddingLeft: 10, + paddingRight: 10, + }, + controlBtnText: { + fontSize: 13, + textAlign: 'center', + }, +}) + diff --git a/src/screens/SonglistDetail/Failed.js b/src/screens/SonglistDetail/Failed.js deleted file mode 100644 index 38fd6e029..000000000 --- a/src/screens/SonglistDetail/Failed.js +++ /dev/null @@ -1,53 +0,0 @@ -import React, { memo } from 'react' -import { View, Text, StyleSheet, ImageBackground } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import { useTranslation } from '@/plugins/i18n' -import Button from '@/components/common/Button' -import { pop } from '@/navigation' - -const Header = memo(() => { - const { t } = useTranslation() - const theme = useGetter('common', 'theme') - const componentIds = useGetter('common', 'componentIds') - const back = () => { - pop(componentIds.songlistDetail) - } - - return ( - <View style={{ ...styles.container, backgroundColor: theme.primary }}> - <Text style={{ ...styles.text, color: theme.normal20 }}>{t('load_failed')}</Text> - <Button onPress={back} style={{ ...styles.controlBtn, backgroundColor: theme.secondary40 }}> - <Text style={{ ...styles.controlBtnText, color: theme.secondary }}>{t('back')}</Text> - </Button> - </View> - ) -}) - -const styles = StyleSheet.create({ - container: { - position: 'absolute', - left: 0, - top: 0, - height: '100%', - width: '100%', - alignItems: 'center', - justifyContent: 'center', - }, - text: { - fontSize: 18, - marginBottom: '20%', - }, - controlBtn: { - paddingTop: 12, - paddingBottom: 12, - paddingLeft: 25, - paddingRight: 25, - borderRadius: 4, - }, - controlBtnText: { - fontSize: 14, - textAlign: 'center', - }, -}) - -export default Header diff --git a/src/screens/SonglistDetail/Header.js b/src/screens/SonglistDetail/Header.js deleted file mode 100644 index 8d40df0b9..000000000 --- a/src/screens/SonglistDetail/Header.js +++ /dev/null @@ -1,84 +0,0 @@ -import React, { memo } from 'react' -import { View, Text, StyleSheet, Image } from 'react-native' -import { BorderWidths } from '@/theme' -import { useGetter } from '@/store' -import ButtonBar from './ActionBar' - -const Header = memo(({ animatePlayed }) => { - const theme = useGetter('common', 'theme') - const selectListInfo = useGetter('songList', 'selectListInfo') - const { info: listDetailDataInfo = {} } = useGetter('songList', 'listDetailData') - const playCount = selectListInfo.play_count || listDetailDataInfo.play_count - - return ( - <View style={{ ...styles.container, borderBottomColor: theme.borderColor }}> - <View style={{ flexDirection: 'row', flexGrow: 0, flexShrink: 0, padding: 10 }}> - <View style={{ ...styles.listItemImg, backgroundColor: theme.primary }}> - <Image nativeID={`pic${selectListInfo.id}Dest`} source={{ uri: selectListInfo.img || listDetailDataInfo.img || null }} borderRadius={4} style={{ flex: 1, resizeMode: 'cover', justifyContent: 'flex-end' }} /> - { - playCount && animatePlayed - ? <Text style={styles.playCount} numberOfLines={ 1 }>{playCount}</Text> - : null - } - </View> - <View style={{ flexDirection: 'column', flexGrow: 1, flexShrink: 1, paddingLeft: 5 }} nativeID="title"> - <Text style={{ fontSize: 13, color: theme.normal }} numberOfLines={ 1 }>{selectListInfo.name || listDetailDataInfo.name}</Text> - <View style={{ flexGrow: 0, flexShrink: 1 }}> - <Text style={{ fontSize: 10, color: theme.normal40 }} numberOfLines={ 4 }>{selectListInfo.desc || listDetailDataInfo.desc}</Text> - </View> - </View> - </View> - <ButtonBar /> - {/* <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}> - <View style={{ flexGrow: 0, flexShrink: 1, paddingTop: 5, paddingRight: 5 }}> - <Text style={{ fontSize: 12, color: AppColors.normal20 }} numberOfLines={ 1 }>{playCount || '-'}</Text> - <Text style={{ fontSize: 12, color: AppColors.normal30 }} numberOfLines={ 1 }>{this.props.selectListInfo.author || this.props.listDetailData.info.author}</Text> - </View> - </View> */} - </View> - ) -}) - -const styles = StyleSheet.create({ - container: { - flexDirection: 'column', - flexWrap: 'nowrap', - borderBottomWidth: BorderWidths.normal, - }, - listItemImg: { - backgroundColor: '#eee', - flexGrow: 0, - flexShrink: 0, - width: 70, - height: 70, - // ...Platform.select({ - // ios: { - // shadowColor: '#000', - // shadowOffset: { - // width: 0, - // height: 1, - // }, - // shadowOpacity: 0.20, - // shadowRadius: 1.41, - // }, - // android: { - // elevation: 2, - // }, - // }), - }, - playCount: { - position: 'absolute', - bottom: 0, - left: 0, - width: '100%', - fontSize: 12, - paddingLeft: 3, - paddingRight: 3, - backgroundColor: 'rgba(0, 0, 0, 0.5)', - color: '#fff', - borderBottomLeftRadius: 4, - borderBottomRightRadius: 4, - }, -}) - -export default Header diff --git a/src/screens/SonglistDetail/Header.tsx b/src/screens/SonglistDetail/Header.tsx new file mode 100644 index 000000000..3d4dd4694 --- /dev/null +++ b/src/screens/SonglistDetail/Header.tsx @@ -0,0 +1,125 @@ +import React, { forwardRef, useImperativeHandle, useState } from 'react' +import { View, Image } from 'react-native' +import { BorderWidths } from '@/theme' +import ButtonBar from './ActionBar' +import { useNavigationComponentDidAppear } from '@/navigation' +import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant' +import { scaleSizeW } from '@/utils/pixelRatio' +import { useTheme } from '@/store/theme/hook' +import Text from '@/components/common/Text' +import { createStyle } from '@/utils/tools' +import StatusBar from '@/components/common/StatusBar' +import songlistState from '@/store/songlist/state' + +const IMAGE_WIDTH = scaleSizeW(70) + +const Pic = ({ componentId, playCount, imgUrl }: { + componentId: string + playCount: string + imgUrl?: string +}) => { + const [animated, setAnimated] = useState(false) + + useNavigationComponentDidAppear(componentId, () => { + setAnimated(true) + }) + + return ( + <View style={{ ...styles.listItemImg, width: IMAGE_WIDTH, height: IMAGE_WIDTH }}> + <Image nativeID={`${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_to_${songlistState.selectListInfo.id}`} source={{ uri: imgUrl }} borderRadius={4} style={{ flex: 1, resizeMode: 'cover', justifyContent: 'flex-end' }} /> + { + playCount && animated + ? <Text style={styles.playCount} numberOfLines={ 1 }>{playCount}</Text> + : null + } + </View> + ) +} + +export interface HeaderProps { + componentId: string +} + +export interface HeaderType { + setInfo: (info: DetailInfo) => void +} +export interface DetailInfo { + name: string + desc: string + playCount: string + imgUrl?: string +} + +export default forwardRef<HeaderType, HeaderProps>(({ componentId }: { componentId: string }, ref) => { + const theme = useTheme() + const [detailInfo, setDetailInfo] = useState<DetailInfo>({ name: '', desc: '', playCount: '' }) + + useImperativeHandle(ref, () => ({ + setInfo(info) { + setDetailInfo(info) + }, + }), []) + + return ( + <View style={{ ...styles.container, paddingTop: StatusBar.currentHeight, borderBottomColor: theme['c-border-background'] }}> + <View style={{ flexDirection: 'row', flexGrow: 0, flexShrink: 0, padding: 10 }}> + <Pic componentId={componentId} playCount={detailInfo.playCount} imgUrl={detailInfo.imgUrl} /> + <View style={{ flexDirection: 'column', flexGrow: 1, flexShrink: 1, paddingLeft: 5 }} nativeID={NAV_SHEAR_NATIVE_IDS.songlistDetail_title}> + <Text size={14} numberOfLines={ 1 }>{detailInfo.name}</Text> + <View style={{ flexGrow: 0, flexShrink: 1 }}> + <Text size={13} color={theme['c-font-label']} numberOfLines={ 4 }>{detailInfo.desc}</Text> + </View> + </View> + </View> + <ButtonBar /> + {/* <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}> + <View style={{ flexGrow: 0, flexShrink: 1, paddingTop: 5, paddingRight: 5 }}> + <Text style={{ fontSize: 12, color: AppColors.normal20 }} numberOfLines={ 1 }>{playCount || '-'}</Text> + <Text style={{ fontSize: 12, color: AppColors.normal30 }} numberOfLines={ 1 }>{this.props.selectListInfo.author || this.props.listDetailData.info.author}</Text> + </View> + </View> */} + </View> + ) +}) + +const styles = createStyle({ + container: { + flexDirection: 'column', + flexWrap: 'nowrap', + borderBottomWidth: BorderWidths.normal, + }, + listItemImg: { + // backgroundColor: '#eee', + flexGrow: 0, + flexShrink: 0, + // width: 70, + // height: 70, + // ...Platform.select({ + // ios: { + // shadowColor: '#000', + // shadowOffset: { + // width: 0, + // height: 1, + // }, + // shadowOpacity: 0.20, + // shadowRadius: 1.41, + // }, + // android: { + // elevation: 2, + // }, + // }), + }, + playCount: { + position: 'absolute', + bottom: 0, + left: 0, + width: '100%', + fontSize: 12, + paddingLeft: 3, + paddingRight: 3, + backgroundColor: 'rgba(0, 0, 0, 0.5)', + color: '#fff', + borderBottomLeftRadius: 4, + borderBottomRightRadius: 4, + }, +}) diff --git a/src/screens/SonglistDetail/List.js b/src/screens/SonglistDetail/List.js deleted file mode 100644 index 7dbcb8b18..000000000 --- a/src/screens/SonglistDetail/List.js +++ /dev/null @@ -1,64 +0,0 @@ -import React, { useState, useCallback, useRef } from 'react' -// import { View, Text, StyleSheet, Animated, FlatList, ImageBackground } from 'react-native' -import ListDetailHeader from './Header' -import Failed from './Failed' -import { useGetter, useDispatch } from '@/store' -import OnlineList from '@/components/OnlineList' -import { LIST_ID_PLAY_TEMP } from '@/config/constant' - - -export default ({ animatePlayed }) => { - const [isListRefreshing, setIsListRefreshing] = useState(false) - const isGetListDetailFailed = useGetter('songList', 'isGetListDetailFailed') - - const selectListInfo = useGetter('songList', 'selectListInfo') - const selectListInfoRef = useRef(selectListInfo) - const listDetailData = useGetter('songList', 'listDetailData') - const getListDetail = useDispatch('songList', 'getListDetail') - const getListDetailAll = useDispatch('songList', 'getListDetailAll') - const songListSource = useGetter('songList', 'songListSource') - const setPlayList = useDispatch('player', 'setList') - - const handleListLoadMore = useCallback(() => { - if (listDetailData.isLoading || listDetailData.isEnd) return - getListDetail({ id: selectListInfoRef.current.id, page: listDetailData.page + 1 }) - }, [getListDetail, listDetailData]) - - const handleListRefresh = useCallback(() => { - setIsListRefreshing(true) - getListDetail({ id: selectListInfoRef.current.id, page: 1, isRefresh: true }).finally(() => { - setIsListRefreshing(false) - }) - }, [getListDetail]) - - const handlePlayList = useCallback(async index => { - if (!listDetailData.info.name) return - const list = await getListDetailAll({ id: selectListInfo.id, source: songListSource }) - // if (!list.length) return - setPlayList({ - list: { - list, - id: LIST_ID_PLAY_TEMP, - }, - index, - }) - }, [getListDetailAll, listDetailData.info.name, selectListInfo.id, setPlayList, songListSource]) - - return ( - <> - <OnlineList - list={animatePlayed ? listDetailData.list : []} - page={-1} - // isEnd={listDetailData.isEnd} - isListRefreshing={isListRefreshing} - onRefresh={handleListRefresh} - onLoadMore={handleListLoadMore} - onPlayList={handlePlayList} - isLoading={listDetailData.isLoading} - ListHeaderComponent={<ListDetailHeader animatePlayed={animatePlayed} />} - /> - - { isGetListDetailFailed ? <Failed /> : null } - </> - ) -} diff --git a/src/screens/SonglistDetail/MusicList.tsx b/src/screens/SonglistDetail/MusicList.tsx new file mode 100644 index 000000000..52a3b8f53 --- /dev/null +++ b/src/screens/SonglistDetail/MusicList.tsx @@ -0,0 +1,113 @@ +import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react' +import OnlineList, { type OnlineListType, type OnlineListProps } from '@/components/OnlineList' +import { getListDetail, setListDetail, setListDetailInfo } from '@/core/songlist' +import songlistState from '@/store/songlist/state' +import { handlePlay } from './listAction' +import Header, { type HeaderType } from './Header' + +export interface MusicListProps { + componentId: string +} + +export interface MusicListType { + loadList: (source: LX.OnlineSource, listId: string) => void +} + +export default forwardRef<MusicListType, MusicListProps>(({ componentId }, ref) => { + const listRef = useRef<OnlineListType>(null) + const headerRef = useRef<HeaderType>(null) + const isUnmountedRef = useRef(false) + useImperativeHandle(ref, () => ({ + loadList(source, id) { + const listDetailInfo = songlistState.listDetailInfo + listRef.current?.setList([]) + if (listDetailInfo.id == id && listDetailInfo.source == source && listDetailInfo.list.length) { + requestAnimationFrame(() => { + listRef.current?.setList(listDetailInfo.list) + headerRef.current?.setInfo({ + name: (songlistState.selectListInfo.name || listDetailInfo.info.name) ?? '', + desc: songlistState.selectListInfo.desc ?? listDetailInfo.desc ?? '', + playCount: (songlistState.selectListInfo.play_count ?? listDetailInfo.info.play_count) ?? '', + imgUrl: songlistState.selectListInfo.img ?? listDetailInfo.info.img, + }) + }) + } else { + listRef.current?.setStatus('loading') + const page = 1 + setListDetailInfo(songlistState.selectListInfo.source, songlistState.selectListInfo.id) + headerRef.current?.setInfo({ + name: (songlistState.selectListInfo.name || listDetailInfo.info.name) ?? '', + desc: songlistState.selectListInfo.desc ?? listDetailInfo.desc ?? '', + playCount: (songlistState.selectListInfo.play_count ?? listDetailInfo.info.play_count) ?? '', + imgUrl: songlistState.selectListInfo.img ?? listDetailInfo.info.img, + }) + return getListDetail(id, source, page).then((listDetail) => { + const result = setListDetail(listDetail, id, page) + if (isUnmountedRef.current) return + requestAnimationFrame(() => { + headerRef.current?.setInfo({ + name: (songlistState.selectListInfo.name || listDetailInfo.info.name) ?? '', + desc: songlistState.selectListInfo.desc ?? listDetailInfo.desc ?? '', + playCount: (songlistState.selectListInfo.play_count ?? listDetailInfo.info.play_count) ?? '', + imgUrl: songlistState.selectListInfo.img ?? listDetailInfo.info.img, + }) + listRef.current?.setList(result.list) + listRef.current?.setStatus(songlistState.listDetailInfo.maxPage == page ? 'end' : 'idle') + }) + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + }, + }), []) + + useEffect(() => { + isUnmountedRef.current = false + return () => { + isUnmountedRef.current = true + } + }, []) + + + const handlePlayList: OnlineListProps['onPlayList'] = (index) => { + const listDetailInfo = songlistState.listDetailInfo + // console.log(songlistState.listDetailInfo) + void handlePlay(listDetailInfo.id, listDetailInfo.source, listDetailInfo.list, index) + } + const handleRefresh: OnlineListProps['onRefresh'] = () => { + const page = 1 + listRef.current?.setStatus('refreshing') + getListDetail(songlistState.listDetailInfo.id, songlistState.listDetailInfo.source, page, true).then((listDetail) => { + const result = setListDetail(listDetail, songlistState.listDetailInfo.id, page) + if (isUnmountedRef.current) return + listRef.current?.setList(result.list) + listRef.current?.setStatus(songlistState.listDetailInfo.maxPage == page ? 'end' : 'idle') + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + const handleLoadMore: OnlineListProps['onLoadMore'] = () => { + listRef.current?.setStatus('loading') + const page = songlistState.listDetailInfo.list.length ? songlistState.listDetailInfo.page + 1 : 1 + getListDetail(songlistState.listDetailInfo.id, songlistState.listDetailInfo.source, page).then((listDetail) => { + const result = setListDetail(listDetail, songlistState.listDetailInfo.id, page) + if (isUnmountedRef.current) return + listRef.current?.setList(result.list) + listRef.current?.setStatus(songlistState.listDetailInfo.maxPage == page ? 'end' : 'idle') + }).catch(() => { + listRef.current?.setStatus('error') + }) + } + + const header = useMemo(() => <Header ref={headerRef} componentId={componentId} />, []) + + return <OnlineList + ref={listRef} + onPlayList={handlePlayList} + onRefresh={handleRefresh} + onLoadMore={handleLoadMore} + ListHeaderComponent={header} + // progressViewOffset={} + /> +}) + diff --git a/src/screens/SonglistDetail/PlayerBar/ControlBtn.tsx b/src/screens/SonglistDetail/PlayerBar/ControlBtn.tsx new file mode 100644 index 000000000..d1b1ce3cc --- /dev/null +++ b/src/screens/SonglistDetail/PlayerBar/ControlBtn.tsx @@ -0,0 +1,63 @@ +import React from 'react' +import { TouchableOpacity } from 'react-native' +import { Icon } from '@/components/common/Icon' +import { useIsPlay } from '@/store/player/hook' +import { useTheme } from '@/store/theme/hook' +import { playNext, togglePlay } from '@/core/player/player' +import { createStyle } from '@/utils/tools' + +const BTN_SIZE = 24 +const handlePlayNext = () => { + void playNext() +} + +const PlayNextBtn = () => { + const theme = useTheme() + + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={handlePlayNext}> + <Icon name='nextMusic' color={theme['c-button-font']} size={BTN_SIZE} /> + </TouchableOpacity> + ) +} + +const TogglePlayBtn = () => { + const isPlay = useIsPlay() + const theme = useTheme() + + return ( + <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={togglePlay}> + <Icon name={isPlay ? 'pause' : 'play'} color={theme['c-button-font']} size={BTN_SIZE} /> + </TouchableOpacity> + ) +} + +export default () => { + return ( + <> + {/* <TouchableOpacity activeOpacity={0.5} onPress={toggleNextPlayMode}> + <Text style={{ ...styles.cotrolBtn }}> + <Icon name={playModeIcon} style={{ color: theme.secondary10 }} size={18} /> + </Text> + </TouchableOpacity> + */} + {/* {btnPrev} */} + <TogglePlayBtn /> + <PlayNextBtn /> + </> + ) +} + + +const styles = createStyle({ + cotrolBtn: { + width: 46, + height: 46, + justifyContent: 'center', + alignItems: 'center', + + // backgroundColor: '#ccc', + shadowOpacity: 1, + textShadowRadius: 1, + }, +}) diff --git a/src/screens/SonglistDetail/PlayerBar/Pic.tsx b/src/screens/SonglistDetail/PlayerBar/Pic.tsx new file mode 100644 index 000000000..221d20619 --- /dev/null +++ b/src/screens/SonglistDetail/PlayerBar/Pic.tsx @@ -0,0 +1,83 @@ +import React, { memo } from 'react' +import { View, Image, TouchableOpacity } from 'react-native' +import { navigations } from '@/navigation' +import { usePlayerMusicInfo } from '@/store/player/hook' +import { useTheme } from '@/store/theme/hook' +import { scaleSizeH } from '@/utils/pixelRatio' +import { createStyle } from '@/utils/tools' +import { BorderRadius } from '@/theme' +import commonState from '@/store/common/state' +// import playerState from '@/store/player/state' +import Text from '@/components/common/Text' +import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant' + +const PIC_HEIGHT = scaleSizeH(46) + +const styles = createStyle({ + // content: { + // marginBottom: 3, + // },/ + emptyPic: { + borderRadius: BorderRadius.normal, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + }, + text: { + paddingLeft: 2, + }, +}) + +const EmptyPic = memo(() => { + const theme = useTheme() + return ( + <View nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={{ ...styles.emptyPic, width: PIC_HEIGHT, height: PIC_HEIGHT, backgroundColor: theme['c-primary-light-900-alpha-200'] }}> + <Text size={20} color={theme['c-primary-light-400-alpha-200']}>L</Text> + <Text size={20} color={theme['c-primary-light-400-alpha-200']} style={styles.text}>X</Text> + </View> + ) +}) + +export default () => { + const musicInfo = usePlayerMusicInfo() + const handlePress = () => { + // console.log('') + // console.log(playMusicInfo) + if (!musicInfo.id) return + navigations.pushPlayDetailScreen(commonState.componentIds.home as string) + + // toast(global.i18n.t('play_detail_todo_tip'), 'long') + } + + // const handleLongPress = () => { + // const listId = playerState.playMusicInfo.listId + // if (!listId || listId == LIST_IDS.DOWNLOAD) return + // global.app_event.jumpListPosition() + // } + + // console.log('render pic') + + return ( + <TouchableOpacity onPress={handlePress} activeOpacity={0.7} > + { + musicInfo.pic + ? ( + <Image source={{ uri: musicInfo.pic }} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} progressiveRenderingEnabled={true} borderRadius={2} style={{ + // ...styles.playInfoImg, + // backgroundColor: theme.primary, + width: PIC_HEIGHT, + height: PIC_HEIGHT, + }} /> + ) + : <EmptyPic /> + } + </TouchableOpacity> + ) +} + + +// const styles = StyleSheet.create({ +// playInfoImg: { + +// }, +// }) diff --git a/src/screens/SonglistDetail/PlayerBar/PlayInfo.tsx b/src/screens/SonglistDetail/PlayerBar/PlayInfo.tsx new file mode 100644 index 000000000..4ce154901 --- /dev/null +++ b/src/screens/SonglistDetail/PlayerBar/PlayInfo.tsx @@ -0,0 +1,75 @@ +import React, { memo } from 'react' +import { View } from 'react-native' + +import Progress from '@/components/player/Progress' +import Status from './Status' +import { useProgress } from '@/store/player/hook' +import { useTheme } from '@/store/theme/hook' +import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' + +const FONT_SIZE = 13 + +const PlayTimeCurrent = ({ timeStr }: { timeStr: string }) => { + const theme = useTheme() + // console.log(timeStr) + return <Text size={FONT_SIZE} color={theme['c-500']}>{timeStr}</Text> +} + +const PlayTimeMax = memo(({ timeStr }: { timeStr: string }) => { + const theme = useTheme() + return <Text size={FONT_SIZE} color={theme['c-500']}>{timeStr}</Text> +}) + +export default () => { + const theme = useTheme() + const { maxPlayTimeStr, nowPlayTimeStr, progress, maxPlayTime } = useProgress() + + return ( + <> + <View style={styles.progress}><Progress progress={progress} duration={maxPlayTime} /></View> + <View style={styles.info}> + {/* <MusicName /> */} + <View style={styles.status}> + <Status /> + </View> + <View style={{ flexGrow: 0, flexShrink: 0, flexDirection: 'row' }} > + <PlayTimeCurrent timeStr={nowPlayTimeStr} /> + <Text size={FONT_SIZE} color={theme['c-500']}> / </Text> + <PlayTimeMax timeStr={maxPlayTimeStr} /> + </View> + </View> + </> + ) +} + + +const styles = createStyle({ + progress: { + height: 16, + // flexGrow: 0, + flexShrink: 0, + // flexDirection: 'column', + justifyContent: 'center', + // alignItems: 'center', + // marginBottom: -1, + // backgroundColor: '#ccc', + // overflow: 'hidden', + // height: + // position: 'absolute', + // width: '100%', + // top: 0, + }, + info: { + // flex: 1, + flexDirection: 'row', + justifyContent: 'space-between', + // alignItems: 'center', + // backgroundColor: '#ccc', + }, + status: { + flexGrow: 1, + flexShrink: 1, + paddingRight: 5, + }, +}) diff --git a/src/screens/SonglistDetail/PlayerBar/Status.tsx b/src/screens/SonglistDetail/PlayerBar/Status.tsx new file mode 100644 index 000000000..12684d69b --- /dev/null +++ b/src/screens/SonglistDetail/PlayerBar/Status.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import { useLrcPlay } from '@/plugins/lyric' +import { useIsPlay, useStatusText } from '@/store/player/hook' +// import { createStyle } from '@/utils/tools' +import Text from '@/components/common/Text' + + +export default () => { + const { text } = useLrcPlay() + const statusText = useStatusText() + const isPlay = useIsPlay() + // console.log('render status') + + const status = isPlay ? text : statusText + + return <Text numberOfLines={1} size={12}>{status}</Text> +} + +// const styles = createStyle({ +// text: { +// fontSize: 10, +// }, +// }) diff --git a/src/screens/SonglistDetail/PlayerBar/Title.tsx b/src/screens/SonglistDetail/PlayerBar/Title.tsx new file mode 100644 index 000000000..ab0107354 --- /dev/null +++ b/src/screens/SonglistDetail/PlayerBar/Title.tsx @@ -0,0 +1,66 @@ +import React from 'react' +import { TouchableOpacity } from 'react-native' +import { navigations } from '@/navigation' +import { usePlayerMusicInfo } from '@/store/player/hook' +// import { toast } from '@/utils/tools' +import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' +import commonState from '@/store/common/state' +// import playerState from '@/store/player/state' +import Text from '@/components/common/Text' +// import { LIST_IDS } from '@/config/constant' + + +export default () => { + // const { t } = useTranslation() + const musicInfo = usePlayerMusicInfo() + const downloadFileName = useSettingValue('download.fileName') + const theme = useTheme() + + const handlePress = () => { + // console.log('') + // console.log(playMusicInfo) + if (!musicInfo.id) return + navigations.pushPlayDetailScreen(commonState.componentIds.home as string) + // toast(global.i18n.t('play_detail_todo_tip'), 'long') + } + + // const handleLongPress = () => { + // const listId = playerState.playMusicInfo.listId + // if (!listId || listId == LIST_IDS.DOWNLOAD) return + // global.app_event.jumpListPosition() + // } + // console.log('render title') + + const title = musicInfo.id ? downloadFileName.replace('歌手', musicInfo.singer).replace('歌名', musicInfo.name) : '' + // console.log(playMusicInfo) + return ( + <TouchableOpacity style={{ width: '100%' }} onPress={handlePress} activeOpacity={0.7} > + <Text color={theme['c-font-label']} numberOfLines={1}>{title}</Text> + </TouchableOpacity> + ) +} +// const Singer = () => { +// const playMusicInfo = useGetter('player', 'playMusicInfo') +// return ( +// <View style={{ flexGrow: 0, flexShrink: 0 }}> +// <Text style={{ width: '100%', color: AppColors.normal }} numberOfLines={1}> +// {playMusicInfo ? playMusicInfo.musicInfo.singer : ''} +// </Text> +// </View> +// ) +// } +// const MusicName = () => { +// const playMusicInfo = useGetter('player', 'playMusicInfo') +// return ( +// <View style={{ flexGrow: 0, flexShrink: 1 }}> +// <Text style={{ width: '100%', color: AppColors.normal }} numberOfLines={1}> +// {playMusicInfo ? playMusicInfo.musicInfo.name : '^-^'} +// </Text> +// </View> +// ) +// } + +// const styles = StyleSheet.create({ + +// }) diff --git a/src/screens/SonglistDetail/PlayerBar/index.tsx b/src/screens/SonglistDetail/PlayerBar/index.tsx new file mode 100644 index 000000000..fec054cb0 --- /dev/null +++ b/src/screens/SonglistDetail/PlayerBar/index.tsx @@ -0,0 +1,86 @@ +import React, { memo } from 'react' +import { View } from 'react-native' +// import { useKeyboard } from '@/utils/hooks' + +import Pic from './Pic' +import Title from './Title' +import PlayInfo from './PlayInfo' +import ControlBtn from './ControlBtn' +import { createStyle } from '@/utils/tools' +// import { useSettingValue } from '@/store/setting/hook' +import { useTheme } from '@/store/theme/hook' + + +export default memo(() => { + // const { onLayout, ...layout } = useLayout() + // const { keyboardShown } = useKeyboard() + const theme = useTheme() + // const autoHidePlayBar = useSettingValue('common.autoHidePlayBar') + + // console.log('render pb') + + return ( + <View style={{ ...styles.container, backgroundColor: theme['c-content-background'] }}> + <Pic /> + <View style={styles.center}> + <Title /> + {/* <View style={{ ...styles.row, justifyContent: 'space-between' }}> + <PlayTime /> + </View> */} + <PlayInfo /> + </View> + <View style={styles.right}> + <ControlBtn /> + </View> + </View> + ) +}) + + +const styles = createStyle({ + container: { + width: '100%', + // height: 100, + // paddingTop: progressContentPadding, + // marginTop: -progressContentPadding, + // backgroundColor: 'rgba(0, 0, 0, .1)', + // borderTopWidth: BorderWidths.normal2, + paddingTop: 5, + paddingBottom: 5, + paddingLeft: 5, + // backgroundColor: AppColors.primary, + // backgroundColor: 'red', + borderTopLeftRadius: 6, + borderTopRightRadius: 6, + flexDirection: 'row', + alignItems: 'center', + elevation: 10, + }, + left: { + // borderRadius: 3, + flexGrow: 0, + flexShrink: 0, + }, + center: { + flexDirection: 'column', + flexGrow: 1, + flexShrink: 1, + paddingLeft: 5, + // height: '100%', + // justifyContent: 'space-evenly', + // height: 48, + }, + right: { + flexDirection: 'row', + alignItems: 'center', + flexGrow: 0, + flexShrink: 0, + paddingLeft: 5, + paddingRight: 5, + }, + // row: { + // flexDirection: 'row', + // flexGrow: 0, + // flexShrink: 0, + // }, +}) diff --git a/src/screens/SonglistDetail/PlayerPortrait/components/ControlBtn.js b/src/screens/SonglistDetail/PlayerPortrait/components/ControlBtn.js deleted file mode 100644 index df8238133..000000000 --- a/src/screens/SonglistDetail/PlayerPortrait/components/ControlBtn.js +++ /dev/null @@ -1,84 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, StyleSheet, TouchableOpacity } from 'react-native' -import { Icon } from '@/components/common/Icon' -import { useGetter, useDispatch } from '@/store' -import { STATUS } from '@/store/modules/player' - - -export default () => { - const playStatus = useGetter('player', 'status') - const playNext = useDispatch('player', 'playNext') - // const playPrev = useDispatch('player', 'playPrev') - // const playMusicInfo = useGetter('player', 'playMusicInfo') - const pauseMusic = useDispatch('player', 'pauseMusic') - const playMusic = useDispatch('player', 'playMusic') - const theme = useGetter('common', 'theme') - - // const togglePlayMethod = useGetter('common', 'togglePlayMethod') - // const setPlayNextMode = useDispatch('common', 'setPlayNextMode') - // const toggleNextPlayMode = useCallback(() => { - // let index = playNextModes.indexOf(togglePlayMethod) - // if (++index >= playNextModes.length) index = -1 - // setPlayNextMode(playNextModes[index] || '') - // }, [setPlayNextMode, togglePlayMethod, playNextModes]) - - // const btnPrev = useMemo(() => ( - // <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playPrev}> - // <Icon name='prevMusic' style={{ color: theme.secondary10 }} size={20} /> - // </TouchableOpacity> - // ), [playPrev, theme]) - - const togglePlay = useCallback(playStatus => { - switch (playStatus) { - case STATUS.playing: - pauseMusic() - break - case STATUS.pause: - case STATUS.stop: - case STATUS.none: - playMusic() - break - // default: - // playMusic(playMusicInfo) - // break - } - }, []) - const btnPlay = useMemo(() => ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={() => togglePlay(playStatus)}> - <Icon name={playStatus == STATUS.playing ? 'pause' : 'play'} style={{ color: theme.secondary10 }} size={24} /> - </TouchableOpacity> - ), [playStatus, theme, togglePlay]) - const btnNext = useMemo(() => ( - <TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playNext}> - <Icon name='nextMusic' style={{ color: theme.secondary10 }} size={24} /> - </TouchableOpacity> - ), [playNext, theme]) - - return ( - <> - {/* <TouchableOpacity activeOpacity={0.5} onPress={toggleNextPlayMode}> - <Text style={{ ...styles.cotrolBtn }}> - <Icon name={playModeIcon} style={{ color: theme.secondary10 }} size={18} /> - </Text> - </TouchableOpacity> - */} - {/* {btnPrev} */} - {btnPlay} - {btnNext} - </> - ) -} - - -const styles = StyleSheet.create({ - cotrolBtn: { - width: 50, - height: 50, - justifyContent: 'center', - alignItems: 'center', - - // backgroundColor: '#ccc', - shadowOpacity: 1, - textShadowRadius: 1, - }, -}) diff --git a/src/screens/SonglistDetail/PlayerPortrait/components/Pic.js b/src/screens/SonglistDetail/PlayerPortrait/components/Pic.js deleted file mode 100644 index 8d763f8c5..000000000 --- a/src/screens/SonglistDetail/PlayerPortrait/components/Pic.js +++ /dev/null @@ -1,49 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect, useState } from 'react' -import { Image, TouchableOpacity } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import { navigations } from '@/navigation' - -export default () => { - const playMusicInfo = useGetter('player', 'playMusicInfo') - const theme = useGetter('common', 'theme') - // const { t } = useTranslation() - const componentIds = useGetter('common', 'componentIds') - const musicInfo = useMemo(() => { - return (playMusicInfo && playMusicInfo.musicInfo) || {} - }, [playMusicInfo]) - const handlePress = useCallback(() => { - // console.log('') - // console.log(playMusicInfo) - if (!playMusicInfo) return - navigations.pushPlayDetailScreen(componentIds.home, musicInfo.songmid) - // toast(t('play_detail_todo_tip'), 'long') - }, [componentIds.home, musicInfo, playMusicInfo]) - - // const handleLongPress = useCallback(() => { - // if (!playMusicInfo || playMusicInfo.listId == LIST_ID_PLAY_TEMP || playMusicInfo.listId == LIST_ID_PLAY_LATER) return - // setNavActiveIndex(NAV_VIEW_NAMES.list) - // setPrevSelectListId(playMusicInfo.listId) - // global.requestAnimationFrame(() => { - // setJumpPosition(true) - // }) - // }, [playMusicInfo, setJumpPosition, setNavActiveIndex, setPrevSelectListId]) - - const component = useMemo(() => ( - <TouchableOpacity onPress={handlePress} activeOpacity={0.7} > - <Image source={{ uri: musicInfo.img }} nativeID={`pic${musicInfo.songmid}`} progressiveRenderingEnabled={true} borderRadius={2} style={{ - // ...styles.playInfoImg, - backgroundColor: theme.primary, - width: 50, - height: 50, - }} /> - </TouchableOpacity> - ), [handlePress, musicInfo, theme]) - return component -} - - -// const styles = StyleSheet.create({ -// playInfoImg: { - -// }, -// }) diff --git a/src/screens/SonglistDetail/PlayerPortrait/components/PlayInfo.js b/src/screens/SonglistDetail/PlayerPortrait/components/PlayInfo.js deleted file mode 100644 index 3de417ad7..000000000 --- a/src/screens/SonglistDetail/PlayerPortrait/components/PlayInfo.js +++ /dev/null @@ -1,56 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, StyleSheet, View } from 'react-native' -import { usePlayTime } from '@/utils/hooks' -import { useGetter } from '@/store' - -import Progress from '@/components/player/Progress' -import Status from './Status' - -const PlayTimeCurrent = ({ timeStr }) => { - const theme = useGetter('common', 'theme') - // console.log(timeStr) - return <Text style={{ fontSize: 12, color: theme.normal10 }}>{timeStr}</Text> -} - -const PlayTimeMax = memo(({ timeStr }) => { - const theme = useGetter('common', 'theme') - return <Text style={{ fontSize: 12, color: theme.normal10 }}>{timeStr}</Text> -}) - -export default () => { - const { curTimeStr, maxTimeStr, progress, bufferedProgress, duration } = usePlayTime() - const theme = useGetter('common', 'theme') - - return ( - <> - <View style={styles.progress}><Progress progress={progress} bufferedProgress={bufferedProgress} duration={duration} /></View> - <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-end' }}> - {/* <MusicName /> */} - <View style={{ flexGrow: 1, flexShrink: 1, paddingRight: 5 }} > - <Status /> - </View> - <View style={{ flexGrow: 0, flexShrink: 0, flexDirection: 'row' }} > - <PlayTimeCurrent timeStr={curTimeStr} /> - <Text style={{ fontSize: 12, color: theme.normal }}> / </Text> - <PlayTimeMax timeStr={maxTimeStr} /> - </View> - </View> - </> - ) -} - - -const styles = StyleSheet.create({ - progress: { - height: 14, - flexGrow: 1, - flexShrink: 0, - flexDirection: 'column', - justifyContent: 'center', - marginBottom: -2, - // height: - // position: 'absolute', - // width: '100%', - // top: 0, - }, -}) diff --git a/src/screens/SonglistDetail/PlayerPortrait/components/Status.js b/src/screens/SonglistDetail/PlayerPortrait/components/Status.js deleted file mode 100644 index 9ea771a4f..000000000 --- a/src/screens/SonglistDetail/PlayerPortrait/components/Status.js +++ /dev/null @@ -1,25 +0,0 @@ -import React, { memo, useMemo } from 'react' -import { Text } from 'react-native' -import { useGetter } from '@/store' -import { STATUS } from '@/store/modules/player' -import { useLrcPlay } from '@/plugins/lyric' - - -export default memo(() => { - const theme = useGetter('common', 'theme') - const playStatus = useGetter('player', 'status') - const statusText = useGetter('player', 'statusText') - const { text } = useLrcPlay() - const status = useMemo(() => playStatus == STATUS.playing - ? text - : ( - (playStatus == STATUS.pause || playStatus == STATUS.stop) && text - ? text - : statusText - ), [playStatus, statusText, text]) - return <Text numberOfLines={1} style={{ fontSize: 10, color: theme.normal10 }}>{status}</Text> -}) - -// const styles = StyleSheet.create({ - -// }) diff --git a/src/screens/SonglistDetail/PlayerPortrait/components/Title.js b/src/screens/SonglistDetail/PlayerPortrait/components/Title.js deleted file mode 100644 index 442b84b65..000000000 --- a/src/screens/SonglistDetail/PlayerPortrait/components/Title.js +++ /dev/null @@ -1,61 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { Text, StyleSheet, TouchableOpacity } from 'react-native' -import { useGetter, useDispatch } from '@/store' -import { navigations } from '@/navigation' - - -export default () => { - const playMusicInfo = useGetter('player', 'playMusicInfo') - const theme = useGetter('common', 'theme') - // const { t } = useTranslation() - const componentIds = useGetter('common', 'componentIds') - const musicInfo = useMemo(() => { - return (playMusicInfo && playMusicInfo.musicInfo) || {} - }, [playMusicInfo]) - const handlePress = useCallback(() => { - // console.log('') - // console.log(playMusicInfo) - if (!playMusicInfo) return - navigations.pushPlayDetailScreen(componentIds.home, musicInfo.songmid) - // toast(t('play_detail_todo_tip'), 'long') - }, [componentIds.home, musicInfo, playMusicInfo]) - - const downloadFileName = useGetter('common', 'downloadFileName') - const title = useMemo(() => { - let title = '^-^' - if (playMusicInfo && playMusicInfo.musicInfo) { - title = downloadFileName.replace('歌手', playMusicInfo.musicInfo.singer).replace('歌名', playMusicInfo.musicInfo.name) - } - return title - }, [downloadFileName, playMusicInfo]) - // console.log(playMusicInfo) - return ( - <TouchableOpacity style={{ width: '100%' }} onPress={handlePress} activeOpacity={0.7} > - <Text style={{ fontSize: 14, color: theme.normal }} numberOfLines={1}>{title}</Text> - </TouchableOpacity> - ) -} -// const Singer = () => { -// const playMusicInfo = useGetter('player', 'playMusicInfo') -// return ( -// <View style={{ flexGrow: 0, flexShrink: 0 }}> -// <Text style={{ width: '100%', color: AppColors.normal }} numberOfLines={1}> -// {playMusicInfo ? playMusicInfo.musicInfo.singer : ''} -// </Text> -// </View> -// ) -// } -// const MusicName = () => { -// const playMusicInfo = useGetter('player', 'playMusicInfo') -// return ( -// <View style={{ flexGrow: 0, flexShrink: 1 }}> -// <Text style={{ width: '100%', color: AppColors.normal }} numberOfLines={1}> -// {playMusicInfo ? playMusicInfo.musicInfo.name : '^-^'} -// </Text> -// </View> -// ) -// } - -// const styles = StyleSheet.create({ - -// }) diff --git a/src/screens/SonglistDetail/PlayerPortrait/index.js b/src/screens/SonglistDetail/PlayerPortrait/index.js deleted file mode 100644 index 5640c0a8a..000000000 --- a/src/screens/SonglistDetail/PlayerPortrait/index.js +++ /dev/null @@ -1,88 +0,0 @@ -import React, { useCallback, memo, useMemo, useEffect } from 'react' -import { View, Text, StyleSheet } from 'react-native' -import { useLayout, useKeyboard } from '@/utils/hooks' -import { useGetter, useDispatch } from '@/store' -// import { BorderWidths } from '@/theme' - -import Pic from './components/Pic' -import Title from './components/Title' -import PlayInfo from './components/PlayInfo' -import ControlBtn from './components/ControlBtn' - - -export default memo(() => { - // const { onLayout, ...layout } = useLayout() - const { keyboardShown } = useKeyboard() - const theme = useGetter('common', 'theme') - const autoHidePlayBar = useGetter('common', 'autoHidePlayBar') - const componentIds = useGetter('common', 'componentIds') - - - const playerComponent = useMemo(() => ( - <View style={{ ...styles.container, backgroundColor: theme.primary }}> - <View style={styles.left} elevation={1}><Pic /></View> - <View style={styles.center}> - <View style={{ ...styles.row, justifyContent: 'space-between', fontSize: 12 }}> - <Title /> - {/* <PlayTime /> */} - </View> - {componentIds.playDetail ? null : <PlayInfo />} - </View> - <View style={styles.right}> - <ControlBtn /> - </View> - </View> - ), [theme, componentIds]) - - // console.log(layout) - - return autoHidePlayBar && keyboardShown ? null : playerComponent -}) - -const styles = StyleSheet.create({ - container: { - width: '100%', - // height: 59, - // paddingTop: progressContentPadding, - // marginTop: -progressContentPadding, - // backgroundColor: 'rgba(0, 0, 0, .1)', - // borderTopWidth: BorderWidths.normal2, - paddingTop: 5, - paddingBottom: 5, - paddingLeft: 5, - // backgroundColor: AppColors.primary, - // backgroundColor: 'red', - borderTopLeftRadius: 6, - borderTopRightRadius: 6, - flexDirection: 'row', - alignItems: 'center', - elevation: 10, - }, - left: { - borderRadius: 3, - flexGrow: 0, - flexShrink: 0, - }, - center: { - flexDirection: 'column', - flexGrow: 1, - flexShrink: 1, - paddingLeft: 5, - height: '100%', - // justifyContent: 'space-evenly', - // height: 48, - }, - right: { - flexDirection: 'row', - alignItems: 'center', - flexGrow: 0, - flexShrink: 0, - paddingLeft: 5, - paddingRight: 5, - }, - row: { - flexDirection: 'row', - flexGrow: 0, - flexShrink: 0, - }, -}) diff --git a/src/screens/SonglistDetail/index.js b/src/screens/SonglistDetail/index.js deleted file mode 100644 index b4883850f..000000000 --- a/src/screens/SonglistDetail/index.js +++ /dev/null @@ -1,38 +0,0 @@ -import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react' -import { View } from 'react-native' -import List from './List' -import { useGetter, useDispatch } from '@/store' -import PlayerPortrait from './PlayerPortrait' -import { useNavigationComponentDidAppear } from '@/navigation' -import StatusBar from '@/components/common/StatusBar' - - -export default ({ componentId }) => { - const selectListInfo = useGetter('songList', 'selectListInfo') - const getListDetail = useDispatch('songList', 'getListDetail') - const theme = useGetter('common', 'theme') - const [animatePlayed, setAnimatPlayed] = useState(false) - - const setComponentId = useDispatch('common', 'setComponentId') - - useEffect(() => { - setAnimatPlayed(false) - setComponentId({ name: 'songlistDetail', id: componentId }) - getListDetail({ id: selectListInfo.id, page: 1 }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - useNavigationComponentDidAppear(componentId, () => { - setAnimatPlayed(true) - }) - - return ( - <View style={{ flex: 1, backgroundColor: theme.primary, paddingTop: StatusBar.currentHeight }}> - <StatusBar /> - <View style={{ flex: 1 }}> - <List animatePlayed={animatePlayed} /> - </View> - <PlayerPortrait /> - </View> - ) -} diff --git a/src/screens/SonglistDetail/index.tsx b/src/screens/SonglistDetail/index.tsx new file mode 100644 index 000000000..7bd1aab72 --- /dev/null +++ b/src/screens/SonglistDetail/index.tsx @@ -0,0 +1,49 @@ +import React, { useEffect, useRef } from 'react' + +import MusicList, { type MusicListType } from './MusicList' +import PageContent from '@/components/PageContent' +import StatusBar from '@/components/common/StatusBar' +import { setComponentId } from '@/core/common' +import { COMPONENT_IDS } from '@/config/constant' +import songlistState from '@/store/songlist/state' +import PlayerBar from './PlayerBar' + + +export default ({ componentId }: { componentId: string }) => { + const musicListRef = useRef<MusicListType>(null) + const isUnmountedRef = useRef(false) + + useEffect(() => { + setComponentId(COMPONENT_IDS.songlistDetail, componentId) + + isUnmountedRef.current = false + + musicListRef.current?.loadList(songlistState.selectListInfo.source, songlistState.selectListInfo.id) + + + return () => { + isUnmountedRef.current = true + } + }, []) + + + return ( + <PageContent> + <StatusBar /> + <MusicList ref={musicListRef} componentId={componentId} /> + <PlayerBar /> + </PageContent> + ) +} + +// const styles = createStyle({ +// container: { +// width: '100%', +// flex: 1, +// flexDirection: 'row', +// borderTopWidth: BorderWidths.normal, +// }, +// content: { +// flex: 1, +// }, +// }) diff --git a/src/screens/SonglistDetail/listAction.ts b/src/screens/SonglistDetail/listAction.ts new file mode 100644 index 000000000..6b1c57e6b --- /dev/null +++ b/src/screens/SonglistDetail/listAction.ts @@ -0,0 +1,54 @@ +import { createList, setTempList } from '@/core/list' +import { playList } from '@/core/player/player' +import { getListDetail, getListDetailAll } from '@/core/songlist' +import { LIST_IDS } from '@/config/constant' +import listState from '@/store/list/state' +import syncSourceList from '@/core/syncSourceList' +import { confirmDialog, toast } from '@/utils/tools' +import { type Source } from '@/store/songlist/state' + + +export const handlePlay = async(listId: string, source: Source, list?: LX.Music.MusicInfoOnline[], index = 0) => { + let isPlayingList = false + // console.log(list) + if (!list?.length) list = (await getListDetail(listId, source, 1)).list + if (list?.length) { + await setTempList(listId, [...list]) + void playList(LIST_IDS.TEMP, index) + isPlayingList = true + } + const fullList = await getListDetailAll(source, listId) + if (!fullList.length) return + if (isPlayingList) { + if (listState.tempListMeta.id == listId) { + await setTempList(listId, [...fullList]) + } + } else { + await setTempList(listId, [...fullList]) + void playList(LIST_IDS.TEMP, index) + } +} + +export const handleCollect = async(listId: string, source: Source, name: string) => { + const targetList = listState.userList.find(l => l.id == listId) + if (targetList) { + const confirm = await confirmDialog({ + message: global.i18n.t('duplicate_list_tip', { name: targetList.name }), + cancelButtonText: global.i18n.t('list_import_part_button_cancel'), + confirmButtonText: global.i18n.t('confirm_button_text'), + }) + if (!confirm) return + void syncSourceList(targetList) + return + } + + const list = await getListDetailAll(source, listId) + await createList({ + name, + id: listId, + list, + source, + sourceListId: listId, + }) + toast(global.i18n.t('collect_success')) +} diff --git a/src/screens/index.js b/src/screens/index.ts similarity index 100% rename from src/screens/index.js rename to src/screens/index.ts diff --git a/src/store/.bak/actions/common.js b/src/store/.bak/actions/common.js deleted file mode 100644 index 09b20e762..000000000 --- a/src/store/.bak/actions/common.js +++ /dev/null @@ -1,23 +0,0 @@ -export const TYPES = { - updateSetting: 'updateSetting', - updateNavHomeViewPageIndex: 'updateNavHomeViewPageIndex', -} - -export const updateSetting = setting => { - return { - type: TYPES.updateSetting, - payload: setting, - } -} - -export const updateNavHomeViewPageIndex = index => ({ - type: TYPES.updateNavHomeViewPageIndex, - payload: index, -}) - -// export const changeCountAsync = count => (dispatch, getState) => { -// console.log(getState()) -// setTimeout(() => { -// dispatch(changeCount(count)) -// }, 1000) -// } diff --git a/src/store/.bak/actions/counts.js b/src/store/.bak/actions/counts.js deleted file mode 100644 index d266a37ad..000000000 --- a/src/store/.bak/actions/counts.js +++ /dev/null @@ -1,23 +0,0 @@ -// import { httpFetch } from '../../utils/request' - -export const TYPES = { - COUNTER_CHANGE: 'COUNTER_CHANGE', -} - -export const changeCount = count => { - return { - type: TYPES.COUNTER_CHANGE, - payload: count, - } -} - -export const changeCountAsync = count => (dispatch, getState) => { - // console.log(getState()) - // const { promise } = httpFetch('https://cdn.stsky.cn/lx-music/desktop/version.json') - // promise.then(resp => { - // console.log(resp) - // }) - setTimeout(() => { - dispatch(changeCount(count)) - }, 1000) -} diff --git a/src/store/.bak/actions/search.js b/src/store/.bak/actions/search.js deleted file mode 100644 index 561029f40..000000000 --- a/src/store/.bak/actions/search.js +++ /dev/null @@ -1,76 +0,0 @@ -import music from '../../../utils/music' - -export const TYPES = { - loading: 'loading', - setText: 'setText', - addHistory: 'addHistory', - setList: 'setList', - setLists: 'setLists', - clearList: 'clearList', - removeHistory: 'removeHistory', - clearHistory: 'clearHistory', -} - -const sources = [] -for (const source of music.sources) { - const musicSearch = music[source.id].musicSearch - if (!musicSearch) continue - sources.push(source) -} - -export const search = ({ text, page, limit }) => (dispatch, getState) => { - dispatch({ type: TYPES.setText, payload: text }) - dispatch({ type: TYPES.addHistory, payload: text }) - - const state = getState() - - if (state.common.setting.search.searchSource == 'all') { - const task = [] - for (const source of sources) { - if (source.id == 'all') continue - dispatch({ type: TYPES.loading, payload: true }) - task.push(music[source.id].musicSearch.search(text, page).catch(error => { - console.log(error) - return { - allPage: 1, - limit: 30, - list: [], - source: source.id, - total: 0, - } - })) - } - return Promise.all(task).then(results => dispatch({ type: TYPES.setLists, payload: { results, page } })) - .finally(() => dispatch({ type: TYPES.loading, payload: false })) - } else { - dispatch({ type: TYPES.loading, payload: true }) - return (music[state.common.setting.search.searchSource]?.musicSearch.search(text, page, limit) ?? Promise.reject(new Error('source not found'))).catch(error => { - console.log(error) - return { - allPage: 1, - limit: 30, - list: [], - source: state.common.setting.search.searchSource, - total: 0, - } - }).then(data => dispatch({ type: TYPES.setList, payload: { page, ...data } })) - .finally(() => dispatch({ type: TYPES.loading, payload: false })) - } -} - -export const setText = text => ({ type: TYPES.setText, payload: text }) - -export const clearList = () => ({ - type: TYPES.clearList, -}) -export const addHistory = text => ({ - type: TYPES.addHistory, - payload: text, -}) -export const removeHistory = index => ({ - type: TYPES.addHistory, - payload: index, -}) -export const clearHistory = () => ({ - type: TYPES.addHistory, -}) diff --git a/src/store/.bak/reducers/common.js b/src/store/.bak/reducers/common.js deleted file mode 100644 index 66feceea0..000000000 --- a/src/store/.bak/reducers/common.js +++ /dev/null @@ -1,34 +0,0 @@ -import { initSetting } from '../../../config' -import { TYPES } from '../actions/common' - -const initialState = { - ...initSetting(), - nav: { - homeViewPageIndex: 0, - }, -} - -const mutations = { - [TYPES.updateSetting](state, setting) { - return { - ...state, - setting: { - ...setting, - }, - } - }, - [TYPES.updateNavHomeViewPageIndex](state, index) { - return { - ...state, - nav: { - ...state.nav, - homeViewPageIndex: index, - }, - } - }, -} - -export default (state = initialState, action) => - mutations[action.type] - ? mutations[action.type](state, action.payload) - : state diff --git a/src/store/.bak/reducers/count.js b/src/store/.bak/reducers/count.js deleted file mode 100644 index 75f812513..000000000 --- a/src/store/.bak/reducers/count.js +++ /dev/null @@ -1,19 +0,0 @@ -import { TYPES } from '../actions/counts' - -const initialState = { - count: 0, -} - -const countReducer = (state = initialState, action) => { - switch (action.type) { - case TYPES.COUNTER_CHANGE: - return { - ...state, - count: action.payload, - } - default: - return state - } -} - -export default countReducer diff --git a/src/store/.bak/reducers/index.js b/src/store/.bak/reducers/index.js deleted file mode 100644 index 785722c2a..000000000 --- a/src/store/.bak/reducers/index.js +++ /dev/null @@ -1,19 +0,0 @@ -import { persistCombineReducers } from 'redux-persist' -import AsyncStorage from '@react-native-async-storage/async-storage' - -import common from './common' -import search from './search' -import count from './count' - -const config = { - key: 'LIFTED_REDUX_STORE', - storage: AsyncStorage, -} - -const appReducer = persistCombineReducers(config, { - common, - search, - count, -}) - -export default (state, action) => appReducer(state, action) diff --git a/src/store/.bak/reducers/search.js b/src/store/.bak/reducers/search.js deleted file mode 100644 index 40197ad19..000000000 --- a/src/store/.bak/reducers/search.js +++ /dev/null @@ -1,220 +0,0 @@ -import { TYPES } from '../actions/search' - -import music from '../../../utils/music' - -let historyList -if (historyList == null) { - historyList = [] - // electronStore_data.set('searchHistoryList', historyList) -} - -const sources = [] -const sourceList = {} -const sourceMaxPage = {} -for (const source of music.sources) { - const musicSearch = music[source.id].musicSearch - if (!musicSearch) continue - sources.push(source) - sourceList[source.id] = { - page: 1, - allPage: 0, - limit: 30, - total: 0, - list: [], - } - sourceMaxPage[source.id] = 0 -} - -const initialState = { - isLoading: false, - sourceList, - list: [], - text: '', - page: 1, - limit: 30, - allPage: 1, - total: 0, - sourceMaxPage, - historyList, -} - -sources.push({ - id: 'all', - name: '聚合搜索', -}) - -// https://blog.csdn.net/xcxy2015/article/details/77164126#comments -const similar = (a, b) => { - if (!a || !b) return 0 - if (a.length > b.length) { // 保证 a <= b - const t = b - b = a - a = t - } - const al = a.length - const bl = b.length - const mp = [] // 一个表 - let i, j, ai, lt, tmp // ai:字符串a的第i个字符。 lt:左上角的值。 tmp:暂存新的值。 - for (i = 0; i <= bl; i++) mp[i] = i - for (i = 1; i <= al; i++) { - ai = a.charAt(i - 1) - lt = mp[0] - mp[0] = mp[0] + 1 - for (j = 1; j <= bl; j++) { - tmp = Math.min(mp[j] + 1, mp[j - 1] + 1, lt + (ai == b.charAt(j - 1) ? 0 : 1)) - lt = mp[j] - mp[j] = tmp - } - } - return 1 - (mp[bl] / bl) -} - -const sortInsert = (arr, data) => { - const key = data.num - let left = 0 - let right = arr.length - 1 - - while (left <= right) { - const middle = parseInt((left + right) / 2) - if (key == arr[middle]) { - left = middle - break - } else if (key < arr[middle].num) { - right = middle - 1 - } else { - left = middle + 1 - } - } - while (left > 0) { - if (arr[left - 1].num != key) break - left-- - } - - arr.splice(left, 0, data) -} - -const handleSortList = (list, keyword) => { - const arr = [] - for (const item of list) { - sortInsert(arr, { - num: similar(keyword, `${item.name} ${item.singer}`), - data: item, - }) - } - return arr.map(item => item.data).reverse() -} - -const filterList = list => { - const set = new Set() - for (let i = list.length - 1; i > -1; i--) { - const item = list[i] - if (set.has(item.songmid)) { - list.splice(i, 1) - } else { - set.add(item.songmid) - } - } - return list -} - -const mutations = { - [TYPES.loading](state, isLoading) { - return { - ...state, - isLoading, - } - }, - [TYPES.setText](state, text) { - return { - ...state, - text, - } - }, - [TYPES.addHistory](state, text) { - let historyList = [...state.historyList] - const index = historyList.indexOf(text) - if (index > -1) historyList.splice(index, 1) - if (historyList.length >= 15) historyList = historyList.slice(0, 14) - historyList.unshift(text) - return { - ...state, - historyList, - } - }, - [TYPES.setList](state, datas) { - const source = { ...state.sourceList[datas.source] } - source.list = datas.page > 1 ? filterList([...source.list, ...datas.list]) : datas.list - source.total = datas.total - source.allPage = datas.allPage - source.page = datas.page - source.limit = datas.limit - - return { - ...state, - sourceList: { - ...state.sourceList, - [datas.source]: source, - }, - } - }, - [TYPES.setLists](state, { results, page }) { - const pages = [] - let total = 0 - let limit = 0 - const list = [] - state = { ...state } - state.sourceMaxPage = { ...state.sourceMaxPage } - for (const source of results) { - sourceMaxPage[source.source] = source.allPage - if (source.allPage < page) continue - list.push(...source.list) - pages.push(source.allPage) - total += source.total - limit += source.limit - } - state.allPage = Math.max(...pages) - state.total = total - state.limit = limit - state.page = page - state.list = page > 1 ? filterList([...state.list, ...handleSortList(list, state.text)]) : handleSortList(list, state.text) - return state - }, - [TYPES.clearList](state) { - state = { ...state } - state.sourceMaxPage = { ...state.sourceMaxPage } - state.sourceList = { ...state.sourceList } - for (const source of Object.keys(state.sourceList)) { - state.sourceList[source] = { ...state.sourceList[source] } - state.sourceList[source].list = [] - state.sourceList[source].page = 0 - state.sourceList[source].allPage = 0 - state.sourceList[source].total = 0 - state.sourceMaxPage[source] = 0 - } - state.list = [] - state.page = 0 - state.allPage = 0 - state.total = 0 - state.text = '' - return state - }, - [TYPES.removeHistory](state, index) { - const historyList = [...state.historyList] - historyList.splice(index, 1) - return { - ...state, - historyList, - } - }, - [TYPES.clearHistory](state) { - return { - ...state, - historyList: [], - } - }, -} - -export default (state = initialState, action) => - mutations[action.type] - ? mutations[action.type](state, action.payload) - : state diff --git a/src/store/Provider/Provider.js b/src/store/Provider/Provider.js deleted file mode 100644 index dab0294af..000000000 --- a/src/store/Provider/Provider.js +++ /dev/null @@ -1,32 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import { Provider } from 'react-redux' -import createStore from '../store' - -let store - -class AppStoreProvider extends PureComponent { - getChildContext() { - return { - store, - } - } - - static childContextTypes = { - store: PropTypes.shape({}), - }; - - render() { - const { children } = this.props - - store = store || createStore() - - return ( - <Provider store={store}> - {children} - </Provider> - ) - } -} - -export default AppStoreProvider diff --git a/src/store/Provider/Provider.tsx b/src/store/Provider/Provider.tsx new file mode 100644 index 000000000..5da51e9fd --- /dev/null +++ b/src/store/Provider/Provider.tsx @@ -0,0 +1,27 @@ +// import React, { PureComponent } from 'react' +// import PropTypes from 'prop-types' +// import { Provider } from 'react-redux' +// import { store } from '../store' + + +// class AppStoreProvider extends PureComponent<{ children: any }> { +// getChildContext() { +// return { +// store, +// } +// } + +// static childContextTypes = { +// store: PropTypes.shape({}), +// } + +// render() { +// return ( +// <Provider store={store}> +// {this.props.children} +// </Provider> +// ) +// } +// } + +// export default AppStoreProvider diff --git a/src/store/Provider/ThemeProvider.tsx b/src/store/Provider/ThemeProvider.tsx new file mode 100644 index 000000000..bb1e5939e --- /dev/null +++ b/src/store/Provider/ThemeProvider.tsx @@ -0,0 +1,23 @@ +import React, { memo, useEffect, useState } from 'react' + +import themeState, { ThemeContext } from '../theme/state' + + +export default memo(({ children }: { + children: React.ReactNode +}) => { + const [theme, setTheme] = useState(themeState.theme) + + useEffect(() => { + global.state_event.on('themeUpdated', setTheme) + return () => { + global.state_event.off('themeUpdated', setTheme) + } + }, []) + + return ( + <ThemeContext.Provider value={theme}> + {children} + </ThemeContext.Provider> + ) +}) diff --git a/src/store/Provider/index.js b/src/store/Provider/index.js deleted file mode 100644 index 4c1b7465a..000000000 --- a/src/store/Provider/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default as Provider } from './Provider' diff --git a/src/store/Provider/index.ts b/src/store/Provider/index.ts new file mode 100644 index 000000000..6a21de29e --- /dev/null +++ b/src/store/Provider/index.ts @@ -0,0 +1 @@ +export { default as Provider } from './ThemeProvider' diff --git a/src/store/common/action.ts b/src/store/common/action.ts new file mode 100644 index 000000000..ed9153d90 --- /dev/null +++ b/src/store/common/action.ts @@ -0,0 +1,29 @@ +import state, { type InitState } from './state' +import { type COMPONENT_IDS } from '@/config/constant' + + +export default { + setFontSize(size: number) { + state.fontSize = size + global.state_event.fontSizeUpdated(size) + }, + setComponentId(name: COMPONENT_IDS, id: string) { + state.componentIds[name] = id + global.state_event.componentIdsUpdated({ ...state.componentIds }) + }, + removeComponentId(id: string) { + const name = (Object.entries(state.componentIds) as Array<[COMPONENT_IDS, string]>).find(kv => kv[1] == id)?.[0] + if (!name) return + delete state.componentIds[name] + global.state_event.componentIdsUpdated({ ...state.componentIds }) + }, + setNavActiveId(id: InitState['navActiveId']) { + state.navActiveId = id + global.state_event.navActiveIdUpdated(id) + }, + setSourceNames(names: InitState['sourceNames']) { + state.sourceNames = names + global.state_event.sourceNamesUpdated(names) + }, +} + diff --git a/src/store/common/hook.ts b/src/store/common/hook.ts new file mode 100644 index 000000000..06c4c6720 --- /dev/null +++ b/src/store/common/hook.ts @@ -0,0 +1,97 @@ +import { type COMPONENT_IDS } from '@/config/constant' +import { useEffect, useState } from 'react' +import state, { type InitState } from './state' + +export const useFontSize = () => { + const [value, update] = useState(state.fontSize) + + useEffect(() => { + global.state_event.on('fontSizeUpdated', update) + return () => { + global.state_event.off('fontSizeUpdated', update) + } + }, []) + + return value +} + +export const useComponentIds = () => { + const [value, update] = useState(state.componentIds) + + useEffect(() => { + global.state_event.on('componentIdsUpdated', update) + return () => { + global.state_event.off('componentIdsUpdated', update) + } + }, []) + + return value +} + +const hasVisible = (visibleNames: COMPONENT_IDS[], ids: InitState['componentIds']) => { + const names = Object.keys(ids) + return names.length == visibleNames.length ? visibleNames.every(n => names.includes(n)) : false +} +export const usePageVisible = (visibleNames: COMPONENT_IDS[], onChange: (visible: boolean) => void) => { + useEffect(() => { + let visible = hasVisible(visibleNames, state.componentIds) + const handlecheck = (ids: InitState['componentIds']) => { + const res = hasVisible(visibleNames, ids) + // console.log(visible, res, res == visible) + if (res == visible) return + visible = res + onChange(visible) + } + global.state_event.on('componentIdsUpdated', handlecheck) + return () => { + global.state_event.off('componentIdsUpdated', handlecheck) + } + }, []) +} + + +export const useAssertApiSupport = (source: LX.Source) => { + const [value, update] = useState(global.lx.qualityList[source] != null || source == 'local') + + useEffect(() => { + const handleUpdate = () => { + update(global.lx.qualityList[source] != null || source == 'local') + } + + global.state_event.on('apiSourceUpdated', handleUpdate) + return () => { + global.state_event.off('apiSourceUpdated', handleUpdate) + } + }, []) + + return value +} + + +export const useNavActiveId = () => { + const [value, update] = useState(state.navActiveId) + + useEffect(() => { + global.state_event.on('navActiveIdUpdated', update) + return () => { + global.state_event.off('navActiveIdUpdated', update) + } + }, []) + + return value +} + + +export const useSourceNames = () => { + const [value, update] = useState(state.sourceNames) + + useEffect(() => { + global.state_event.on('sourceNamesUpdated', update) + return () => { + global.state_event.off('sourceNamesUpdated', update) + } + }, []) + + return value +} + diff --git a/src/store/common/state.ts b/src/store/common/state.ts new file mode 100644 index 000000000..63659e4e6 --- /dev/null +++ b/src/store/common/state.ts @@ -0,0 +1,21 @@ +import { type NAV_ID_Type, type COMPONENT_IDS } from '@/config/constant' + + +export interface InitState { + fontSize: number + componentIds: Partial<Record<COMPONENT_IDS, string>> + navActiveId: NAV_ID_Type + sourceNames: Record<LX.OnlineSource | 'all', string> +} + +const initData = {} + +const state: InitState = { + fontSize: global.lx.fontSize, + componentIds: {}, + navActiveId: 'nav_search', + sourceNames: initData as InitState['sourceNames'], +} + + +export default state diff --git a/src/store/connect.js b/src/store/connect.js deleted file mode 100644 index 65be30fd1..000000000 --- a/src/store/connect.js +++ /dev/null @@ -1,23 +0,0 @@ -import { bindActionCreators } from 'redux' -import { connect } from 'react-redux' -import * as modules from './modules' - - -const mapDispatchToProps = actionCreators => dispatch => ({ - actions: bindActionCreators(actionCreators, dispatch), -}) - -export default (mapStateToProps, mapActions) => { - const mapActionToProps = {} - for (const [moduleName, actions] of mapActions) { - const moduleActions = modules[moduleName].action - if (Array.isArray(actions)) { - for (const action of actions) mapActionToProps[action] = moduleActions[action] - } else { - for (const [key, value] of Object.entries(actions)) { - mapActionToProps[key] = moduleActions[value] - } - } - } - return connect(mapStateToProps, mapDispatchToProps(mapActionToProps)) -} diff --git a/src/store/getter.js b/src/store/getter.js deleted file mode 100644 index d0887afaa..000000000 --- a/src/store/getter.js +++ /dev/null @@ -1,30 +0,0 @@ -import { useMemo, useCallback } from 'react' -import { useSelector } from 'react-redux' -import * as modules from './modules' - -// console.log(modules) -const defaultGetter = state => state - -const getter = (moduleName, key) => { - const getters = modules[moduleName].getter - if (getters && getters[key]) return getters[key] - console.warn('getter not found:', moduleName, key) - return defaultGetter -} - -const useGetter = (moduleName, key, props) => { - const memoGetter = useMemo(() => { - return getter(moduleName, key) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - const selecteor = useCallback(state => memoGetter(state, props), [props]) - - // console.log(selector) - // console.log(moduleName, key) - return useSelector(selecteor) -} - -export { - getter, - useGetter, -} diff --git a/src/store/hotSearch/action.ts b/src/store/hotSearch/action.ts new file mode 100644 index 000000000..17cfb4cdc --- /dev/null +++ b/src/store/hotSearch/action.ts @@ -0,0 +1,37 @@ +import state, { type Source } from './state' + +export type Lists = Array<{ source: LX.OnlineSource, list: string[] }> + +const setList = (source: LX.OnlineSource, list: string[]): string[] => { + const l = state.sourceList[source] = list.slice(0, 20) + return l +} + +const setLists = (lists: Lists): string[] => { + let wordsMap = new Map<string, number>() + for (const { source, list } of lists) { + if (!state.sourceList[source]?.length) state.sourceList[source] = list.slice(0, 20) + for (let item of list) { + item = item.trim() + wordsMap.set(item, (wordsMap.get(item) ?? 0) + 1) + } + } + const wordsMapArr = Array.from(wordsMap) + wordsMapArr.sort((a, b) => a[0].localeCompare(b[0])) + wordsMapArr.sort((a, b) => b[1] - a[1]) + const words = wordsMapArr.map(item => item[0]) + return state.sourceList.all = words.slice(0, state.sources.length * 10) +} + + +export default { + setList(source: Source, list: string[] | Lists) { + if (source == 'all') { + return setLists(list as Lists) + } + return setList(source, list as string[]) + }, + clearList(source: Source) { + state.sourceList[source] = [] + }, +} diff --git a/src/store/hotSearch/state.ts b/src/store/hotSearch/state.ts new file mode 100644 index 000000000..1008b1b21 --- /dev/null +++ b/src/store/hotSearch/state.ts @@ -0,0 +1,29 @@ +import musicSdk from '@/utils/musicSdk' + +// import { deduplicationList } from '@common/utils/renderer' + +export declare type Source = LX.OnlineSource | 'all' + +type SourceLists = Partial<Record<Source, string[]>> + + +export interface InitState { + sources: Source[] + sourceList: SourceLists +} + +const state: InitState = { + sources: [], + sourceList: { + all: [], + }, +} + +for (const source of musicSdk.sources) { + if (!musicSdk[source.id as LX.OnlineSource]?.hotSearch) continue + state.sources.push(source.id as LX.OnlineSource) + state.sourceList[source.id as LX.OnlineSource] = [] +} +state.sources.push('all') + +export default state diff --git a/src/store/index.js b/src/store/index.js deleted file mode 100644 index 09cc2cd71..000000000 --- a/src/store/index.js +++ /dev/null @@ -1,7 +0,0 @@ -export { Provider } from './Provider' -export { reducers } from './reducer' -export * from './getter' -export { default as useDispatch } from './useDispatch' -export { default as connect } from './connect' -export { default as getStore } from './store' -export { subscribe } from './subscriber' diff --git a/src/store/index.ts b/src/store/index.ts new file mode 100644 index 000000000..560d2350d --- /dev/null +++ b/src/store/index.ts @@ -0,0 +1,5 @@ + + +export const useGetter = () => { + +} diff --git a/src/store/leaderboard/action.ts b/src/store/leaderboard/action.ts new file mode 100644 index 000000000..e20821441 --- /dev/null +++ b/src/store/leaderboard/action.ts @@ -0,0 +1,33 @@ +import state, { type Source, type Board, type ListDetailInfo } from './state' + +export default { + setBoard(board: Board, source: LX.OnlineSource) { + state.boards[source] = board + }, + setListDetailInfo(source: Source, id: string) { + state.listDetailInfo.source = source + state.listDetailInfo.id = id + }, + setListDetail(result: ListDetailInfo, id: string, page: number) { + state.listDetailInfo.list = page == 1 ? [...result.list] : [...state.listDetailInfo.list, ...result.list] + state.listDetailInfo.id = id + state.listDetailInfo.source = result.source + state.listDetailInfo.total = result.total + state.listDetailInfo.limit = result.limit + state.listDetailInfo.page = page + state.listDetailInfo.maxPage = Math.ceil(result.total / result.limit) + + return state.listDetailInfo + }, + clearListDetail() { + state.listDetailInfo.list = [] + state.listDetailInfo.id = '' + state.listDetailInfo.source = null + state.listDetailInfo.total = 0 + state.listDetailInfo.limit = 30 + state.listDetailInfo.page = 1 + state.listDetailInfo.maxPage = 1 + state.listDetailInfo.key = null + }, +} + diff --git a/src/store/leaderboard/state.ts b/src/store/leaderboard/state.ts new file mode 100644 index 000000000..24f62cce4 --- /dev/null +++ b/src/store/leaderboard/state.ts @@ -0,0 +1,54 @@ +import music from '@/utils/musicSdk' + +export declare type Source = LX.OnlineSource + +export declare interface BoardItem { + id: string + name: string + bangid: string +} +export declare interface Board { + list: BoardItem[] + source: LX.OnlineSource +} +type Boards = Partial<Record<LX.OnlineSource, Board>> + +export declare interface ListDetailInfo { + list: LX.Music.MusicInfoOnline[] + total: number + maxPage: number + page: number + source: LX.OnlineSource | null + limit: number + key: string | null + id: string +} + +export interface InitState { + sources: LX.OnlineSource[] + boards: Boards + listDetailInfo: ListDetailInfo +} + +const state: InitState = { + sources: [], + boards: {}, + listDetailInfo: { + list: [], + total: 0, + page: 1, + maxPage: 1, + limit: 30, + key: null, + source: null, + id: '', + }, +} + +for (const source of music.sources) { + if (!music[source.id as LX.OnlineSource]?.leaderboard?.getBoards) continue + state.sources.push(source.id as LX.OnlineSource) +} + + +export default state diff --git a/src/store/list/action.ts b/src/store/list/action.ts new file mode 100644 index 000000000..4392d5329 --- /dev/null +++ b/src/store/list/action.ts @@ -0,0 +1,37 @@ +import state, { type InitState } from './state' + + +export default { + setUserLists(userList: LX.List.UserListInfo[]) { + state.userList = userList + state.allList = [state.defaultList, state.loveList, ...state.userList] + + global.state_event.mylistUpdated(state.allList) + }, + setActiveList(activeListId: string) { + state.activeListId = activeListId + + global.state_event.mylistToggled(activeListId) + }, + setTempListMeta(meta: InitState['tempListMeta']) { + state.tempListMeta = meta + }, + setFetchingListStatus(id: string, status: boolean) { + state.fetchingListStatus[id] = status + + global.state_event.fetchingListStatusUpdated({ ...state.fetchingListStatus }) + }, +} + + +// Other code such as selectors can use the imported `RootState` type +// export const defaultList = (state: LX.State) => state.userList.defaultList +// export const loveList = (state: LX.State) => state.userList.loveList +// export const userList = (state: LX.State) => state.userList.userList +// export const selectAllList = createSelector(defaultList, loveList, userList, (defaultList, loveList, userList) => { +// return [defaultList, loveList, ...userList] +// }) + +// export const selectActiveListId = (state: LX.State) => state.userList.activeListId + +// export default slice.reducer diff --git a/src/store/list/hook.ts b/src/store/list/hook.ts new file mode 100644 index 000000000..c409ac291 --- /dev/null +++ b/src/store/list/hook.ts @@ -0,0 +1,88 @@ +import { useEffect, useState } from 'react' +import state, { type InitState } from './state' +import { getListMusics } from '@/core/list' + +export const useMyList = () => { + const [lists, setList] = useState(state.allList) + + useEffect(() => { + global.state_event.on('mylistUpdated', setList) + return () => { + global.state_event.off('mylistUpdated', setList) + } + }, []) + + return lists +} + +export const useActiveListId = () => { + const [id, setId] = useState(state.activeListId) + + useEffect(() => { + global.state_event.on('mylistToggled', setId) + return () => { + global.state_event.off('mylistToggled', setId) + } + }, []) + + return id +} + + +export const useMusicList = () => { + const [list, setList] = useState<LX.List.ListMusics>([]) + + useEffect(() => { + const handleToggle = (activeListId: string) => { + void getListMusics(activeListId).then((list) => { + setList([...list]) + }) + } + const handleChange = (ids: string[]) => { + if (!ids.includes(state.activeListId)) return + void getListMusics(state.activeListId).then((list) => { + setList([...list]) + }) + } + global.state_event.on('mylistToggled', handleToggle) + global.app_event.on('myListMusicUpdate', handleChange) + + handleToggle(state.activeListId) + + return () => { + global.state_event.off('mylistToggled', handleToggle) + global.app_event.off('myListMusicUpdate', handleChange) + } + }, []) + + return list +} + +export const useMusicExistsList = (list: LX.List.MyListInfo, musicInfo: LX.Music.MusicInfo) => { + const [isExists, setExists] = useState(false) + + useEffect(() => { + void getListMusics(list.id).then((musics) => { + setExists(musics.some(s => s.id == musicInfo.id)) + }) + }, [list.id, musicInfo.id]) + + return isExists +} + +export const useListFetching = (listId: string) => { + const [fetching, setFetching] = useState(!!state.fetchingListStatus[listId]) + + useEffect(() => { + const handleUpdate = (status: InitState['fetchingListStatus']) => { + setFetching(!!status[listId]) + } + global.state_event.on('fetchingListStatusUpdated', handleUpdate) + return () => { + global.state_event.off('fetchingListStatusUpdated', handleUpdate) + } + }, []) + + return fetching +} + diff --git a/src/store/list/state.ts b/src/store/list/state.ts new file mode 100644 index 000000000..bf8085fa6 --- /dev/null +++ b/src/store/list/state.ts @@ -0,0 +1,48 @@ +import { LIST_IDS } from '@/config/constant' + + +export interface InitState { + allMusicList: Map<string, LX.Music.MusicInfo[]> + defaultList: LX.List.MyDefaultListInfo + loveList: LX.List.MyLoveListInfo + tempList: LX.List.MyTempListInfo + userList: LX.List.UserListInfo[] + activeListId: string + + allList: Array<LX.List.MyDefaultListInfo | LX.List.MyLoveListInfo | LX.List.UserListInfo> + + tempListMeta: { + id: string + } + + fetchingListStatus: Record<string, boolean> +} + +const state: InitState = { + allMusicList: new Map(), + defaultList: { + id: LIST_IDS.DEFAULT, + name: '试听列表', + }, + loveList: { + id: LIST_IDS.LOVE, + name: '我的收藏', + }, + tempList: { + id: LIST_IDS.TEMP, + name: '临时列表', + meta: {}, + }, + userList: [], + activeListId: '', + allList: [], + tempListMeta: { + id: '', + }, + fetchingListStatus: {}, +} + +state.allList = [state.defaultList, state.loveList] + + +export default state diff --git a/src/store/modules/common/action.js b/src/store/modules/common/action.js deleted file mode 100644 index 6fe246f73..000000000 --- a/src/store/modules/common/action.js +++ /dev/null @@ -1,517 +0,0 @@ -import { getData, setData } from '@/plugins/storage' -import { storageDataPrefix } from '@/config' -import { action as playerAction, getter as playerGetter } from '@/store/modules/player' -import { mergeSetting } from '@/config/setting' -import { changeLanguage } from '@/plugins/i18n' -import music from '@/utils/music' -import { getVersionInfo } from '@/utils/version' -import { compareVer } from '@/utils' -// import { setMaxCache } from '@/plugins/player/utils' -import { showVersionModal } from '@/navigation' -import { VERSION_STATUS } from '@/config/constant' -// import { screenUnkeepAwake } from '@/utils/utils' - -export const TYPES = { - updateSetting: null, - setComponentId: null, - removeComponentId: null, - setNavActiveIndex: null, - setNavScreenName: null, - setPlayNextMode: null, - setPrevSelectListId: null, - setStartupAutoPlay: null, - setAutoHidePlayBar: null, - setApiSource: null, - setTheme: null, - setIsAutoTheme: null, - setSystemColor: null, - setSearchSource: null, - setAgreePact: null, - setSongList: null, - setLang: null, - setPlayerCacheSize: null, - setIsPlayHighQuality: null, - setSourceNameType: null, - setTop: null, - setIgnoreVersion: null, - setVersionInfo: null, - setShareType: null, - setTimeoutExit: null, - setIsHandleAudioFocus: null, - setAddMusicLocationType: null, - setIsShowLyricTranslation: null, - setIsShowLyricRoma: null, - setIsS2T: null, - setIsEnableSync: null, - setSyncStatus: null, - setIsClickPlayList: null, - setIsShowDesktopLyric: null, - setIsLockDesktopLyric: null, - setThemeDesktopLyric: null, - setDesktopLyricPosition: null, - setDesktopLyricWidth: null, - setDesktopLyricSingleLine: null, - setDesktopLyricShowToggleAnima: null, - setDesktopLyricMaxLineNum: null, - setDesktopLyricTextPosition: null, - setDesktopLyricStyle: null, - setPlayerPortraitStyle: null, - setPlayerLandscapeStyle: null, - setIsShowNotificationImage: null, -} -for (const key of Object.keys(TYPES)) { - TYPES[key] = `common__${key}` -} - -const settingKey = storageDataPrefix.setting - -export const checkVersion = () => async(dispatch, getState) => { - let versionInfo - try { - const { version, desc, history } = await getVersionInfo() - versionInfo = { - version, - desc, - history, - } - } catch (err) { - versionInfo = { - version: '0.0.0', - desc: null, - history: [], - } - } - // const versionInfo = { - // version: '1.9.0', - // desc: '- 更新xxx\n- 修复xxx123的萨达修复xxx123的萨达修复xxx123的萨达修复xxx123的萨达修复xxx123的萨达', - // history: [{ version: '1.8.0', desc: '- 更新xxx22\n- 修复xxx22' }, { version: '1.7.0', desc: '- 更新xxx22\n- 修复xxx22' }], - // } - versionInfo.status = - versionInfo.version == '0.0.0' - ? VERSION_STATUS.unknown - : compareVer(process.versions.app, versionInfo.version) < 0 - ? VERSION_STATUS.available - : VERSION_STATUS.latest - - const { common } = getState() - - if (common.setting.ignoreVersion != versionInfo.version && versionInfo.status == VERSION_STATUS.available) { - versionInfo.showModal = true - dispatch(setVersionInfo(versionInfo)) - showVersionModal() - } else { - versionInfo.showModal = false - dispatch(setVersionInfo(versionInfo)) - } - // console.log(compareVer(process.versions.app, versionInfo.version)) - // console.log(process.versions.app, versionInfo.version) -} - -export const setVersionInfo = versionInfo => { - return { - type: TYPES.setVersionInfo, - payload: versionInfo, - } -} - -export const initSetting = () => async(dispatch, getState) => { - const setting = await getData(settingKey) - if (!setting) return - global.globalObj.qualityList = music.supportQuality[setting.apiSource] - global.globalObj.apiSource = setting.apiSource - await dispatch(updateSetting(mergeSetting(setting))) -} - -export const updateSetting = setting => async(dispatch, getState) => { - dispatch({ - type: TYPES.updateSetting, - payload: setting, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setComponentId = data => ({ - type: TYPES.setComponentId, - payload: data, -}) -export const removeComponentId = id => { - return { - type: TYPES.removeComponentId, - payload: id, - } -} - -export const setNavActiveIndex = index => ({ - type: TYPES.setNavActiveIndex, - payload: index, -}) - -export const setTimeoutExit = ({ time, isPlayed }) => async(dispatch, getState) => { - dispatch({ - type: TYPES.setTimeoutExit, - payload: { time, isPlayed }, - }) - const state = getState() - await setData(settingKey, state.common.setting) -} - -export const setPrevSelectListId = id => async(dispatch, getState) => { - dispatch({ - type: TYPES.setPrevSelectListId, - payload: id, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setPlayNextMode = mode => async(dispatch, getState) => { - dispatch({ - type: TYPES.setPlayNextMode, - payload: mode, - }) - dispatch(playerAction.clearPlayedList()) - const state = getState() - if (mode == 'random') dispatch(playerAction.addMusicToPlayedList(playerGetter.playMusicInfo(state))) - await setData(settingKey, state.common.setting) -} - -export const setStartupAutoPlay = enable => async(dispatch, getState) => { - dispatch({ - type: TYPES.setStartupAutoPlay, - payload: enable, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setAutoHidePlayBar = enable => async(dispatch, getState) => { - dispatch({ - type: TYPES.setAutoHidePlayBar, - payload: enable, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setApiSource = id => async(dispatch, getState) => { - dispatch({ - type: TYPES.setApiSource, - payload: id, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setIgnoreVersion = version => async(dispatch, getState) => { - dispatch({ - type: TYPES.setIgnoreVersion, - payload: version, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setTheme = id => async(dispatch, getState) => { - dispatch({ - type: TYPES.setTheme, - payload: id, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setIsAutoTheme = enabled => async(dispatch, getState) => { - dispatch({ - type: TYPES.setIsAutoTheme, - payload: enabled, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setSystemColor = color => ({ - type: TYPES.setSystemColor, - payload: color, -}) - -export const setLang = id => async(dispatch, getState) => { - dispatch({ - type: TYPES.setLang, - payload: id, - }) - changeLanguage(id) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setSourceNameType = id => async(dispatch, getState) => { - dispatch({ - type: TYPES.setSourceNameType, - payload: id, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setSearchSource = ({ searchSource, tempSearchSource }) => async(dispatch, getState) => { - dispatch({ - type: TYPES.setSearchSource, - payload: { searchSource, tempSearchSource }, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setAgreePact = isAgreePact => async(dispatch, getState) => { - dispatch({ - type: TYPES.setAgreePact, - payload: isAgreePact, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setLeaderboard = ({ tabId, source }) => async(dispatch, getState) => { - dispatch({ - type: TYPES.setLeaderboard, - payload: { tabId, source }, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setSongList = ({ sortId, tagInfo, source }) => async(dispatch, getState) => { - dispatch({ - type: TYPES.setSongList, - payload: { sortId, tagInfo, source }, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setTop = ({ tabId, source }) => async(dispatch, getState) => { - dispatch({ - type: TYPES.setTop, - payload: { tabId, source }, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setPlayerCacheSize = size => async(dispatch, getState) => { - dispatch({ - type: TYPES.setPlayerCacheSize, - payload: size, - }) - const { common } = getState() - await setData(settingKey, common.setting) - // setMaxCache(size) -} - -export const setIsPlayHighQuality = highQuality => async(dispatch, getState) => { - dispatch({ - type: TYPES.setIsPlayHighQuality, - payload: highQuality, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setIsHandleAudioFocus = flag => async(dispatch, getState) => { - dispatch({ - type: TYPES.setIsHandleAudioFocus, - payload: flag, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setAddMusicLocationType = type => async(dispatch, getState) => { - dispatch({ - type: TYPES.setAddMusicLocationType, - payload: type, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setIsShowLyricTranslation = flag => async(dispatch, getState) => { - dispatch(playerAction.toggleTranslation(flag)) - dispatch({ - type: TYPES.setIsShowLyricTranslation, - payload: flag, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setIsShowLyricRoma = flag => async(dispatch, getState) => { - dispatch(playerAction.toggleRoma(flag)) - dispatch({ - type: TYPES.setIsShowLyricRoma, - payload: flag, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} -export const setIsS2T = flag => async(dispatch, getState) => { - dispatch({ - type: TYPES.setIsS2T, - payload: flag, - }) - dispatch(playerAction.toggleS2T()) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setIsShowDesktopLyric = flag => async(dispatch, getState) => { - await dispatch(playerAction.toggleDesktopLyric(flag)) - dispatch({ - type: TYPES.setIsShowDesktopLyric, - payload: flag, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} -export const setIsLockDesktopLyric = flag => async(dispatch, getState) => { - dispatch(playerAction.toggleDesktopLyricLock(flag)) - dispatch({ - type: TYPES.setIsLockDesktopLyric, - payload: flag, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} -export const setThemeDesktopLyric = theme => async(dispatch, getState) => { - dispatch(playerAction.setDesktopLyricTheme(theme)) - dispatch({ - type: TYPES.setThemeDesktopLyric, - payload: theme, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} -export const setIsClickPlayList = flag => async(dispatch, getState) => { - dispatch({ - type: TYPES.setIsClickPlayList, - payload: flag, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} -export const setDesktopLyricStyle = style => async(dispatch, getState) => { - dispatch(playerAction.setDesktopLyricStyle(style)) - dispatch({ - type: TYPES.setDesktopLyricStyle, - payload: style, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} -export const setDesktopLyricPosition = position => async(dispatch, getState) => { - dispatch({ - type: TYPES.setDesktopLyricPosition, - payload: position, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} -export const setDesktopLyricSingleLine = isSingleLine => async(dispatch, getState) => { - dispatch(playerAction.setDesktopLyricSingleLine(isSingleLine)) - dispatch({ - type: TYPES.setDesktopLyricSingleLine, - payload: isSingleLine, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} -export const setDesktopLyricShowToggleAnima = showToggleAnima => async(dispatch, getState) => { - dispatch(playerAction.setDesktopLyricShowToggleAnima(showToggleAnima)) - dispatch({ - type: TYPES.setDesktopLyricShowToggleAnima, - payload: showToggleAnima, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} -export const setDesktopLyricWidth = width => async(dispatch, getState) => { - dispatch(playerAction.setDesktopLyricWidth(width)) - dispatch({ - type: TYPES.setDesktopLyricWidth, - payload: width, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} -export const setDesktopLyricMaxLineNum = maxLineNum => async(dispatch, getState) => { - dispatch(playerAction.setDesktopLyricMaxLineNum(maxLineNum)) - dispatch({ - type: TYPES.setDesktopLyricMaxLineNum, - payload: maxLineNum, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} -export const setDesktopLyricTextPosition = position => async(dispatch, getState) => { - const textPosition = { ...getState().common.setting.desktopLyric.textPosition, ...position } - dispatch(playerAction.setDesktopLyricTextPosition(textPosition)) - dispatch({ - type: TYPES.setDesktopLyricTextPosition, - payload: textPosition, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setIsEnableSync = flag => async(dispatch, getState) => { - dispatch({ - type: TYPES.setIsEnableSync, - payload: flag, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setSyncStatus = statusInfo => async(dispatch, getState) => { - dispatch({ - type: TYPES.setSyncStatus, - payload: statusInfo, - }) -} - -export const setPlayerPortraitStyle = style => async(dispatch, getState) => { - dispatch({ - type: TYPES.setPlayerPortraitStyle, - payload: style, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setPlayerLandscapeStyle = style => async(dispatch, getState) => { - dispatch({ - type: TYPES.setPlayerLandscapeStyle, - payload: style, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setShareType = type => async(dispatch, getState) => { - dispatch({ - type: TYPES.setShareType, - payload: type, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} - -export const setIsShowNotificationImage = flag => async(dispatch, getState) => { - dispatch({ - type: TYPES.setIsShowNotificationImage, - payload: flag, - }) - const { common } = getState() - await setData(settingKey, common.setting) -} diff --git a/src/store/modules/common/common.ts b/src/store/modules/common/common.ts new file mode 100644 index 000000000..549c8f2e7 --- /dev/null +++ b/src/store/modules/common/common.ts @@ -0,0 +1,35 @@ +// import { createSlice } from '@reduxjs/toolkit' +import { NAV_MENUS } from '@/config/constant' +// import type { PayloadAction } from '@reduxjs/toolkit' +// import type { RootState } from '@/store' + +// type MenuIds = (typeof NAV_MENUS)[number]['id'] + +// // Define a type for the slice state +// interface InitState { +// activeId: MenuIds +// } + +// // Define the initial state using that type +// const initialState: InitState = { +// activeId: 'search', +// } + +// // export const slice = createSlice({ +// // name: 'common', +// // // `createSlice` will infer the state type from the `initialState` argument +// // initialState, +// // reducers: { +// // setNavActive(state, action: PayloadAction<MenuIds>) { +// // if (action.payload === state.activeId) return +// // state.activeId = action.payload +// // }, +// // }, +// // }) + +// export const { setNavActive } = slice.actions + +// // Other code such as selectors can use the imported `RootState` type +// // export const selectCount = (state: RootState) => state.counter.value + +// export default slice.reducer diff --git a/src/store/modules/common/getter.js b/src/store/modules/common/getter.js deleted file mode 100644 index 4bbcdd66c..000000000 --- a/src/store/modules/common/getter.js +++ /dev/null @@ -1,93 +0,0 @@ -import { createSelector } from 'reselect' -import apiSourceInfo from '@/utils/music/api-source-info' - -// sourceInfo(state, getters, rootState, { sourceNames }) { -// return { sources: sources.map(item => ({ id: item.id, name: sourceNames[item.id] })), sortList } -// }, -// tags: state => state.tags, -// isVisibleListDetail: state => state.isVisibleListDetail, -// selectListInfo: state => state.selectListInfo, -export const common = state => state.common -export const navMenus = state => state.common.nav.menus -export const navActiveIndex = state => state.common.nav.activeIndex - -export const startupAutoPlay = state => state.common.setting.startupAutoPlay -export const autoHidePlayBar = state => state.common.setting.autoHidePlayBar - -export const setting = state => state.common.setting - -export const componentIds = state => state.common.componentIds - -export const activeLangId = state => state.common.setting.langId - -export const isAgreePact = state => state.common.setting.isAgreePact - -export const isPlayHighQuality = state => state.common.setting.player.highQuality -export const isHandleAudioFocus = state => state.common.setting.player.isHandleAudioFocus -export const playerCacheSize = state => state.common.setting.player.cacheSize - -export const systemColor = state => state.common.systemColor -export const isAutoTheme = state => state.common.setting.isAutoTheme -export const themeList = state => state.common.themes -export const activeThemeId = state => state.common.setting.themeId -export const activeTheme = createSelector( - [themeList, activeThemeId, isAutoTheme, systemColor], - (themeList, activeThemeId, isAutoTheme, systemColor) => { - const themeId = isAutoTheme && systemColor == 'dark' ? 'black' : activeThemeId - return themeList.find(theme => theme.id === themeId) || themeList[0] - }) -export const theme = createSelector(activeTheme, activeTheme => activeTheme.colors) -export const isDarkTheme = createSelector(activeTheme, activeTheme => activeTheme.isDark) -export const statusBarStyle = createSelector(isDarkTheme, isDarkTheme => isDarkTheme ? 'light-content' : 'dark-content') - -export const versionInfo = state => state.common.versionInfo - -export const prevSelectListId = state => state.common.setting.list.prevSelectListId -export const addMusicLocationType = state => state.common.setting.list.addMusicLocationType - -export const togglePlayMethod = state => state.common.setting.player.togglePlayMethod - -export const downloadFileName = state => state.common.setting.download.fileName - - -export const sourceNameType = state => state.common.setting.sourceNameType - -export const isClickPlayList = state => state.common.setting.list.isClickPlayList - -export const isEnableDesktopLyric = state => state.common.setting.desktopLyric.enable -export const isLockDesktopLyric = state => state.common.setting.desktopLyric.isLock -export const themeDesktopLyric = state => state.common.setting.desktopLyric.theme -export const desktopLyricPosition = state => state.common.setting.desktopLyric.position -export const desktopLyricTextPosition = state => state.common.setting.desktopLyric.textPosition -export const desktopLyricStyle = state => state.common.setting.desktopLyric.style -export const desktopLyricSingleLine = state => state.common.setting.desktopLyric.isSingleLine -export const desktopLyricShowToggleAnima = state => state.common.setting.desktopLyric.showToggleAnima -export const desktopLyricWidth = state => state.common.setting.desktopLyric.width -export const desktopLyricMaxLineNum = state => state.common.setting.desktopLyric.maxLineNum - -export const timeoutExit = state => state.common.setting.player.timeoutExit -export const timeoutExitPlayed = state => state.common.setting.player.timeoutExitPlayed -export const isShowLyricTranslation = state => state.common.setting.player.isShowLyricTranslation -export const isShowLyricRoma = state => state.common.setting.player.isShowLyricRoma -export const isS2t = state => state.common.setting.player.isS2t - -export const activeApiSourceId = state => state.common.setting.apiSource - -export const isEnableSync = state => state.common.setting.sync.enable -export const syncStatus = state => state.common.syncStatus - -const apiSourceListFormated = apiSourceInfo.map(api => ({ - id: api.id, - name: api.name, - disabled: api.disabled, -})) -export const apiSourceList = state => apiSourceListFormated - -export const supportQualitys = state => apiSourceInfo.find(s => s.id == state.common.setting.apiSource).supportQualitys - -export const playerPortraitStyle = state => state.common.setting.player.portrait.style -export const playerLandscapeStyle = state => state.common.setting.player.landscape.style - -export const shareType = state => state.common.setting.shareType - -export const isShowNotificationImage = state => state.common.setting.player.isShowNotificationImage diff --git a/src/store/modules/common/index.js b/src/store/modules/common/index.js deleted file mode 100644 index f9cf685c9..000000000 --- a/src/store/modules/common/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import * as action from './action' -import * as getter from './getter' - -export { action, getter } -export { default as reducer } from './reducer' diff --git a/src/store/modules/common/index.ts b/src/store/modules/common/index.ts new file mode 100644 index 000000000..52b08af5c --- /dev/null +++ b/src/store/modules/common/index.ts @@ -0,0 +1,5 @@ +import common from './common' + +export default { + common, +} diff --git a/src/store/modules/common/reducer.js b/src/store/modules/common/reducer.js deleted file mode 100644 index 49f178dd2..000000000 --- a/src/store/modules/common/reducer.js +++ /dev/null @@ -1,590 +0,0 @@ -import { initSetting } from '@/config/setting' -import { TYPES } from './action' -import music from '@/utils/music' -import { Themes } from '@/theme' -import { NAV_VIEW_NAMES, VERSION_STATUS } from '@/config/constant' - - -const setting = initSetting() - - -global.globalObj = { - qualityList: music.supportQuality[setting.setting.apiSource], - apiSource: setting.setting.apiSource, -} - -const initialState = { - ...setting, - nav: { - activeIndex: 0, - menus: [ - { id: 'search', name: '搜索', icon: 'search-2' }, - { id: 'songList', name: '歌单', icon: 'album' }, - { id: 'top', name: '排行榜', icon: 'leaderboard' }, - { id: 'love', name: '收藏', icon: 'love' }, - // { id: 'download', name: '下载', icon: 'download-2' }, - { id: 'setting', name: '设置', icon: 'setting' }, - ], - }, - qualityList: music.supportQuality[setting.setting.apiSource], - themes: Themes, - systemColor: null, - versionInfo: { - status: VERSION_STATUS.checking, - downloadProgress: { - total: 0, - current: 0, - }, - showModal: false, - version: null, - desc: '', - history: [], - }, - syncStatus: { - status: false, - message: '', - }, - componentIds: {}, -} - -initialState.nav.menus.forEach(({ id }, index) => { - NAV_VIEW_NAMES[id] = index -}) - -const mutations = { - [TYPES.updateSetting](state, setting) { - return { - ...state, - setting: { - ...state.setting, - ...setting, - }, - } - }, - [TYPES.setComponentId](state, { name, id }) { - return { - ...state, - componentIds: { - ...state.componentIds, - [name]: id, - }, - } - }, - [TYPES.removeComponentId](state, removeId) { - const newComponentIds = { ...state.componentIds } - for (const [name, id] of Object.entries(state.componentIds)) { - if (id == removeId) { - newComponentIds[name] = null - break - } - } - return { - ...state, - componentIds: newComponentIds, - } - }, - [TYPES.setNavActiveIndex](state, index) { - if (index === state.nav.activeIndex) return state - return { - ...state, - nav: { - ...state.nav, - activeIndex: index, - }, - } - }, - [TYPES.setPrevSelectListId](state, id) { - return { - ...state, - setting: { - ...state.setting, - list: { - ...state.setting.list, - prevSelectListId: id, - }, - }, - } - }, - [TYPES.setAddMusicLocationType](state, type) { - return { - ...state, - setting: { - ...state.setting, - list: { - ...state.setting.list, - addMusicLocationType: type, - }, - }, - } - }, - [TYPES.setAgreePact](state, isAgreePact) { - return { - ...state, - setting: { - ...state.setting, - isAgreePact, - }, - } - }, - [TYPES.setSearchSource](state, { searchSource, tempSearchSource }) { - const newState = { - ...state, - setting: { - ...state.setting, - search: { - ...state.setting.search, - }, - }, - } - if (searchSource != null) newState.setting.search.searchSource = searchSource - if (tempSearchSource != null) newState.setting.search.tempSearchSource = tempSearchSource - return newState - }, - [TYPES.setLeaderboard](state, { tabId, source }) { - const newState = { - ...state, - setting: { - ...state.setting, - leaderboard: { - ...state.setting.leaderboard, - }, - }, - } - if (tabId != null) newState.setting.leaderboard.tabId = tabId - if (source != null) newState.setting.leaderboard.source = source - return newState - }, - [TYPES.setSongList](state, { sortId, tagInfo, source }) { - const newState = { - ...state, - setting: { - ...state.setting, - songList: { - ...state.setting.songList, - }, - }, - } - if (tagInfo != null) newState.setting.songList.tagInfo = tagInfo - if (sortId != null) newState.setting.songList.sortId = sortId - if (source != null) newState.setting.songList.source = source - return newState - }, - [TYPES.setTop](state, { tabId, source }) { - const newState = { - ...state, - setting: { - ...state.setting, - leaderboard: { - ...state.setting.leaderboard, - }, - }, - } - if (tabId != null) newState.setting.leaderboard.tabId = tabId - if (source != null) newState.setting.leaderboard.source = source - return newState - }, - [TYPES.setApiSource](state, id) { - global.globalObj.apiSource = id - global.globalObj.supportQuality = music.supportQuality[id] - - return { - ...state, - setting: { - ...state.setting, - apiSource: id, - }, - } - }, - [TYPES.setIgnoreVersion](state, version) { - return { - ...state, - setting: { - ...state.setting, - ignoreVersion: version, - }, - } - }, - [TYPES.setTheme](state, id) { - return { - ...state, - setting: { - ...state.setting, - themeId: id, - }, - } - }, - [TYPES.setIsAutoTheme](state, enabled) { - return { - ...state, - setting: { - ...state.setting, - isAutoTheme: enabled, - }, - } - }, - [TYPES.setSystemColor](state, color) { - return { - ...state, - systemColor: color, - } - }, - [TYPES.setLang](state, id) { - return { - ...state, - setting: { - ...state.setting, - langId: id, - }, - } - }, - [TYPES.setSourceNameType](state, id) { - return { - ...state, - setting: { - ...state.setting, - sourceNameType: id, - }, - } - }, - [TYPES.setPlayNextMode](state, mode) { - return { - ...state, - setting: { - ...state.setting, - player: { - ...state.setting.player, - togglePlayMethod: mode, - }, - }, - } - }, - [TYPES.setStartupAutoPlay](state, startupAutoPlay) { - return { - ...state, - setting: { - ...state.setting, - startupAutoPlay, - }, - } - }, - [TYPES.setAutoHidePlayBar](state, autoHidePlayBar) { - return { - ...state, - setting: { - ...state.setting, - autoHidePlayBar, - }, - } - }, - [TYPES.setPlayerCacheSize](state, size) { - return { - ...state, - setting: { - ...state.setting, - player: { - ...state.setting.player, - cacheSize: size, - }, - }, - } - }, - [TYPES.setIsPlayHighQuality](state, highQuality) { - return { - ...state, - setting: { - ...state.setting, - player: { - ...state.setting.player, - highQuality, - }, - }, - } - }, - [TYPES.setIsHandleAudioFocus](state, isHandleAudioFocus) { - return { - ...state, - setting: { - ...state.setting, - player: { - ...state.setting.player, - isHandleAudioFocus, - }, - }, - } - }, - [TYPES.setIsShowLyricTranslation](state, isShowLyricTranslation) { - return { - ...state, - setting: { - ...state.setting, - player: { - ...state.setting.player, - isShowLyricTranslation, - }, - }, - } - }, - [TYPES.setIsShowLyricRoma](state, isShowLyricRoma) { - return { - ...state, - setting: { - ...state.setting, - player: { - ...state.setting.player, - isShowLyricRoma, - }, - }, - } - }, - [TYPES.setIsS2T](state, isS2t) { - return { - ...state, - setting: { - ...state.setting, - player: { - ...state.setting.player, - isS2t, - }, - }, - } - }, - [TYPES.setIsShowDesktopLyric](state, isShowDesktopLyric) { - return { - ...state, - setting: { - ...state.setting, - desktopLyric: { - ...state.setting.desktopLyric, - enable: isShowDesktopLyric, - }, - }, - } - }, - [TYPES.setIsLockDesktopLyric](state, isLock) { - return { - ...state, - setting: { - ...state.setting, - desktopLyric: { - ...state.setting.desktopLyric, - isLock, - }, - }, - } - }, - [TYPES.setThemeDesktopLyric](state, theme) { - return { - ...state, - setting: { - ...state.setting, - desktopLyric: { - ...state.setting.desktopLyric, - theme, - }, - }, - } - }, - [TYPES.setIsClickPlayList](state, enable) { - return { - ...state, - setting: { - ...state.setting, - list: { - ...state.setting.list, - isClickPlayList: enable, - }, - }, - } - }, - [TYPES.setDesktopLyricStyle](state, style) { - return { - ...state, - setting: { - ...state.setting, - desktopLyric: { - ...state.setting.desktopLyric, - style: { - ...state.setting.desktopLyric.style, - ...style, - }, - }, - }, - } - }, - [TYPES.setDesktopLyricPosition](state, position) { - return { - ...state, - setting: { - ...state.setting, - desktopLyric: { - ...state.setting.desktopLyric, - position, - }, - }, - } - }, - [TYPES.setDesktopLyricSingleLine](state, isSingleLine) { - return { - ...state, - setting: { - ...state.setting, - desktopLyric: { - ...state.setting.desktopLyric, - isSingleLine, - }, - }, - } - }, - [TYPES.setDesktopLyricShowToggleAnima](state, showToggleAnima) { - return { - ...state, - setting: { - ...state.setting, - desktopLyric: { - ...state.setting.desktopLyric, - showToggleAnima, - }, - }, - } - }, - [TYPES.setDesktopLyricWidth](state, width) { - return { - ...state, - setting: { - ...state.setting, - desktopLyric: { - ...state.setting.desktopLyric, - width, - }, - }, - } - }, - [TYPES.setDesktopLyricMaxLineNum](state, maxLineNum) { - return { - ...state, - setting: { - ...state.setting, - desktopLyric: { - ...state.setting.desktopLyric, - maxLineNum, - }, - }, - } - }, - [TYPES.setDesktopLyricTextPosition](state, textPosition) { - return { - ...state, - setting: { - ...state.setting, - desktopLyric: { - ...state.setting.desktopLyric, - textPosition, - }, - }, - } - }, - [TYPES.setVersionInfo](state, versionInfo) { - return { - ...state, - versionInfo: { - ...state.versionInfo, - ...versionInfo, - }, - } - }, - [TYPES.setTimeoutExit](state, { time, isPlayed }) { - const newState = { - ...state, - setting: { - ...state.setting, - player: { - ...state.setting.player, - }, - }, - } - if (time != null) newState.setting.player.timeoutExit = time - if (isPlayed != null) newState.setting.player.timeoutExitPlayed = isPlayed - - return newState - }, - [TYPES.setIsEnableSync](state, isEnableSync) { - const newState = { - ...state, - setting: { - ...state.setting, - sync: { - ...state.setting.sync, - enable: isEnableSync, - }, - }, - } - return newState - }, - [TYPES.setSyncStatus](state, { status, message }) { - const newState = { - ...state, - syncStatus: { - ...state.syncStatus, - }, - } - if (status != null) newState.syncStatus.status = status - if (message != null) newState.syncStatus.message = message - return newState - }, - [TYPES.setPlayerPortraitStyle](state, style) { - return { - ...state, - setting: { - ...state.setting, - player: { - ...state.setting.player, - portrait: { - ...state.setting.player.portrait, - style, - }, - }, - }, - } - }, - [TYPES.setPlayerLandscapeStyle](state, style) { - return { - ...state, - setting: { - ...state.setting, - player: { - ...state.setting.player, - landscape: { - ...state.setting.player.landscape, - style, - }, - }, - }, - } - }, - [TYPES.setShareType](state, shareType) { - return { - ...state, - setting: { - ...state.setting, - shareType, - }, - } - }, - [TYPES.setIsShowNotificationImage](state, flag) { - return { - ...state, - setting: { - ...state.setting, - player: { - ...state.setting.player, - isShowNotificationImage: flag, - }, - }, - } - }, -} - -export default (state = initialState, action) => - mutations[action.type] - ? mutations[action.type](state, action.payload) - : state diff --git a/src/store/modules/index.js b/src/store/modules/index.js deleted file mode 100644 index 612096585..000000000 --- a/src/store/modules/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import * as common from './common' -import * as search from './search' -import * as player from './player' -import * as list from './list' -import * as songList from './songList' -import * as top from './top' - -export { - common, - search, - player, - list, - songList, - top, -} diff --git a/src/store/modules/index.ts b/src/store/modules/index.ts new file mode 100644 index 000000000..6227e8411 --- /dev/null +++ b/src/store/modules/index.ts @@ -0,0 +1,19 @@ +import common from './common' +// import * as search from './search' +// import * as player from './player' +// import * as list from './list' +// import * as songList from './songList' +// import * as top from './top' + +// export { +// common, +// search, +// player, +// list, +// songList, +// top, +// } + +export default { + ...common, +} diff --git a/src/store/modules/list/action.js b/src/store/modules/list/action.js deleted file mode 100644 index 7f607cc8d..000000000 --- a/src/store/modules/list/action.js +++ /dev/null @@ -1,417 +0,0 @@ -import { action as playerAction } from '@/store/modules/player' -import { action as commonAction } from '@/store/modules/common' -import { findMusic } from '@/utils/music' -import { - getAllListData, - saveList, - removeList, - saveListAllSort, - clearMusicUrlAndLyric, - saveListScrollPosition, - saveListSort, -} from '@/utils/tools' -import { list as listSync } from '@/plugins/sync' -import { log } from '@/utils/log' - -export const TYPES = { - initList: null, - setList: null, - listAdd: null, - listMove: null, - listAddMultiple: null, - listMoveMultiple: null, - listRemove: null, - listRemoveMultiple: null, - listClear: null, - updateMusicInfo: null, - createUserList: null, - removeUserList: null, - setUserListName: null, - setUserListPosition: null, - setMusicPosition: null, - setOtherSource: null, - clearCache: null, - jumpPosition: null, - setSyncList: null, -} - -for (const key of Object.keys(TYPES)) { - TYPES[key] = `list__${key}` -} - - -export const initList = listData => async(dispatch, getState) => { - let defaultList - let loveList - let userList - let listPosition - let listSort - if (listData) { - defaultList = listData.defaultList - loveList = listData.loveList - userList = listData.userList - listSort = listData.listSort || {} - } else { - try { - listData = await getAllListData() - } catch (err) { - log.error(err.stack) - return - } - defaultList = listData.defaultList - loveList = listData.loveList - userList = listData.userList - listPosition = listData.listPosition - listSort = listData.listSort - } - global.listScrollPosition = listPosition || {} - global.listSort = listSort - - let isNeedSaveSortInfo = false - userList.sort((a, b) => { - if (listSort[a.id] == null) return listSort[b.id] == null ? -1 : 1 - return listSort[b.id] == null ? 1 : listSort[a.id] - listSort[b.id] - }) - userList.forEach((list, index) => { - if (listSort[list.id] == null) { - isNeedSaveSortInfo = true - listSort[list.id] = index - delete list.location - } - }) - if (isNeedSaveSortInfo) await saveListAllSort(listSort) - - let needSaveLists = [] - const allList = [...(userList ?? [])] - if (loveList) allList.unshift(loveList) - if (defaultList) allList.unshift(defaultList) - - // 临时 - 过滤无效歌曲 - allList.forEach(list => { - let isNeedSaveList = false - const newList = list.list.filter(musicInfo => { - if (!musicInfo) return false - - // PC v1.8.2以前的Lyric - if (musicInfo.lxlrc) { - delete musicInfo.lxlrc - isNeedSaveList = true - } - if (musicInfo.lrc) { - delete musicInfo.lrc - isNeedSaveList = true - } - if (musicInfo.tlrc) { - delete musicInfo.tlrc - isNeedSaveList = true - } - - return !!musicInfo.songmid - }) - if (newList.length != list.list.length) { - list.list = newList - isNeedSaveList = true - } - if (isNeedSaveList) needSaveLists.push(list) - }) - if (needSaveLists.length) saveList(needSaveLists) - - // console.log(userList.map(l => `${listSort[l.id]} - ${l.name}`)) - dispatch({ - type: TYPES.initList, - payload: { defaultList, loveList, userList }, - }) - - // if (listData.isSync) { - // const keys = Object.keys(global.allList) - // dispatch(playerAction.checkPlayList(keys)) - // saveList(keys) - // } else { - // listSync.sendListAction('init_list', { defaultList, loveList, userList }) - // } -} - -const handleSaveListAllSort = async(userList) => { - const listPosition = {} - userList.forEach((list, index) => { - listPosition[list.id] = index - delete list.location - }) - global.listScrollPosition = listPosition - await saveListAllSort(listPosition) -} - -export const setSyncList = ({ defaultList, loveList, userList }) => async(dispatch, getState) => { - const state = getState() - const userListIds = userList.map(l => l.id) - const removeUserListIds = state.list.userList.filter(l => !userListIds.includes(l.id)).map(l => l.id) - if (removeUserListIds.includes(state.common.setting.list.prevSelectListId)) { - dispatch(commonAction.setPrevSelectListId(state.list.defaultList.id)) - } - dispatch({ - type: TYPES.setSyncList, - payload: { defaultList, loveList, userList }, - }) - await removeList(removeUserListIds) - - await handleSaveListAllSort(userList) - - dispatch(playerAction.checkPlayList([...Object.keys(global.allList), ...removeUserListIds])) - saveList([defaultList, loveList, ...userList]) -} - -export const setList = ({ id, list, name, source, sourceListId, isSync }) => async(dispatch, getState) => { - const targetList = global.allList[id] - if (targetList) { - if (name && targetList.name === name) { - if (!isSync) listSync.sendListAction('set_list', { id, list, name, source, sourceListId }) - dispatch({ - type: TYPES.listClear, - payload: id, - }) - dispatch(listAddMultiple({ id, list, isSync: true })) - return - } - - id += '_' + Math.random() - } - if (!isSync) listSync.sendListAction('set_list', { id, list, name, source, sourceListId }) - - await dispatch(createUserList({ id, list, name, source, sourceListId, isSync: true })) -} - -export const listAdd = ({ musicInfo, id, addMusicLocationType, isSync }) => (dispatch, getState) => { - if (!addMusicLocationType) addMusicLocationType = getState().common.setting.list.addMusicLocationType - - if (!isSync) { - listSync.sendListAction('list_add', { id, musicInfo, addMusicLocationType }) - } - - dispatch({ - type: TYPES.listAdd, - payload: { - musicInfo, - id, - addMusicLocationType, - }, - }) - dispatch(playerAction.checkPlayList([id])) - saveList(global.allList[id]) -} - -export const listMove = ({ fromId, musicInfo, toId, isSync }) => (dispatch, getState) => { - if (!isSync) { - listSync.sendListAction('list_move', { fromId, musicInfo, toId }) - } - - dispatch({ - type: TYPES.listMove, - payload: { fromId, musicInfo, toId }, - }) - dispatch(playerAction.checkPlayList([fromId, toId])) - saveList([global.allList[fromId], global.allList[toId]]) -} - -export const listAddMultiple = ({ id, list, addMusicLocationType, isSync }) => (dispatch, getState) => { - if (!addMusicLocationType) addMusicLocationType = getState().common.setting.list.addMusicLocationType - - if (!isSync) { - listSync.sendListAction('list_add_multiple', { id, list, addMusicLocationType }) - } - - dispatch({ - type: TYPES.listAddMultiple, - payload: { id, list, addMusicLocationType }, - }) - dispatch(playerAction.checkPlayList([id])) - saveList(global.allList[id]) -} - -export const listMoveMultiple = ({ fromId, toId, list, isSync }) => (dispatch, getState) => { - if (!isSync) { - listSync.sendListAction('list_move_multiple', { fromId, toId, list }) - } - - dispatch({ - type: TYPES.listRemoveMultiple, - payload: { id: fromId, ids: list.map(s => s.songmid) }, - }) - dispatch({ - type: TYPES.listAddMultiple, - payload: { id: toId, list }, - }) - dispatch(playerAction.checkPlayList([fromId, toId])) - saveList([global.allList[fromId], global.allList[toId]]) -} - -export const listRemove = ({ listId, id, isSync }) => (dispatch, getState) => { - if (!isSync) { - listSync.sendListAction('list_remove', { listId, id }) - } - - dispatch({ - type: TYPES.listRemove, - payload: { listId, id }, - }) - dispatch(playerAction.checkPlayList([listId])) - saveList(global.allList[listId]) -} - -export const listRemoveMultiple = ({ listId, ids, isSync }) => (dispatch, getState) => { - if (!isSync) { - listSync.sendListAction('list_remove_multiple', { listId, ids }) - } - - dispatch({ - type: TYPES.listRemoveMultiple, - payload: { listId, ids }, - }) - dispatch(playerAction.checkPlayList([listId])) - saveList(global.allList[listId]) -} - -export const listClear = ({ id, isSync }) => (dispatch, getState) => { - if (!isSync) { - listSync.sendListAction('list_clear', { id }) - } - - dispatch({ - type: TYPES.listClear, - payload: id, - }) - dispatch(playerAction.checkPlayList([id])) - saveList(global.allList[id]) -} - -export const updateMusicInfo = ({ listId, id, data, isSync }) => (dispatch, getState) => { - if (!isSync) { - listSync.sendListAction('update_music_info', { listId, id, data }) - } - - dispatch({ - type: TYPES.updateMusicInfo, - payload: { listId, id, data }, - }) - saveList(global.allList[listId]) -} - -export const createUserList = ({ name, id = `userlist_${Date.now()}`, list = [], source, sourceListId, position, isSync }) => async(dispatch, getState) => { - if (!isSync) { - listSync.sendListAction('create_user_list', { name, id, list, source, sourceListId, position }) - } - - dispatch({ - type: TYPES.createUserList, - payload: { name, id, source, sourceListId, position }, - }) - dispatch(listAddMultiple({ id, list, isSync: true })) - await saveList(global.allList[id]) - const state = getState() - await saveListSort(id, state.list.userList.length) - await saveListScrollPosition(id, 0) -} - -export const removeUserList = ({ id, isSync }) => async(dispatch, getState) => { - if (!isSync) { - listSync.sendListAction('remove_user_list', { id }) - } - - const { list, common } = getState() - const index = list.userList.findIndex(l => l.id === id) - if (index < 0) return - if (common.setting.list.prevSelectListId == id) { - dispatch(commonAction.setPrevSelectListId(list.defaultList.id)) - } - dispatch({ - type: TYPES.removeUserList, - payload: index, - }) - await removeList(id) - console.log(common.setting.list.prevSelectListId, id) - dispatch(playerAction.checkPlayList([id])) -} - -const getOtherSourcePromises = new Map() - -export const getOtherSource = ({ musicInfo, id }) => (dispatch, getState) => { - if (musicInfo.otherSource?.length) return Promise.resolve(musicInfo.otherSource) - let key = `${musicInfo.source}_${musicInfo.songmid}` - if (getOtherSourcePromises.has(key)) return getOtherSourcePromises.get(key) - const promise = findMusic(musicInfo).then(otherSource => { - const targetList = global.allList[id] - if (targetList) { - const index = targetList.indexOf(musicInfo) - if (index > -1) { - dispatch({ - type: TYPES.setOtherSource, - payload: { otherSource, id, index }, - }) - } - } - return otherSource - }).finally(() => { - if (getOtherSourcePromises.has(key)) getOtherSourcePromises.delete(key) - }) - getOtherSourcePromises.set(key, promise) - return promise -} - -export const setUserListName = ({ id, name, isSync }) => async(dispatch, getState) => { - if (!isSync) { - listSync.sendListAction('set_user_list_name', { id, name }) - } - - dispatch({ - type: TYPES.setUserListName, - payload: { id, name }, - }) - const targetList = global.allList[id] - await saveList(targetList) -} -export const setUserListPosition = ({ id, position, isSync }) => async(dispatch, getState) => { - if (!isSync) { - listSync.sendListAction('set_user_list_position', { id, position }) - } - - dispatch({ - type: TYPES.setUserListPosition, - payload: { id, position }, - }) - - await handleSaveListAllSort(getState().list.userList) - - await saveList(global.allList[id]) -} -export const setMusicPosition = ({ id, position, list, isSync }) => async(dispatch, getState) => { - if (!isSync) { - listSync.sendListAction('set_music_position', { id, position, list }) - } - // const targetList = global.allList[id] - // if (!targetList) return - dispatch({ - type: TYPES.listRemoveMultiple, - payload: { listId: id, ids: list.map(m => m.songmid) }, - }) - dispatch({ - type: TYPES.setMusicPosition, - payload: { id, position, list }, - }) - dispatch(playerAction.checkPlayList([id])) - await saveList(global.allList[id]) -} - -export const setJumpPosition = isJumpPosition => async(dispatch, getState) => { - dispatch({ - type: TYPES.jumpPosition, - payload: isJumpPosition, - }) -} - -export const clearCache = () => async(dispatch, getState) => { - dispatch({ - type: TYPES.clearCache, - payload: null, - }) - await saveList(Object.values(global.allList)) - await clearMusicUrlAndLyric() -} diff --git a/src/store/modules/list/getter.js b/src/store/modules/list/getter.js deleted file mode 100644 index 737909cca..000000000 --- a/src/store/modules/list/getter.js +++ /dev/null @@ -1,25 +0,0 @@ -import { createSelector } from 'reselect' - - -// sourceInfo(state, getters, rootState, { sourceNames }) { -// return { sources: sources.map(item => ({ id: item.id, name: sourceNames[item.id] })), sortList } -// }, -// tags: state => state.tags, -// isVisibleListDetail: state => state.isVisibleListDetail, -// selectListInfo: state => state.selectListInfo, -// listData(state) { -// return state.list -// }, -// listDetail(state) { -// return state.listDetail -// }, - -export const defaultList = state => state.list.defaultList -export const loveList = state => state.list.loveList -export const userList = state => state.list.userList -export const isJumpPosition = state => state.list.isJumpPosition - -export const allList = createSelector([defaultList, loveList, userList], (defaultList, loveList, userList) => { - return [defaultList, loveList, ...userList] -}) - diff --git a/src/store/modules/list/index.js b/src/store/modules/list/index.js deleted file mode 100644 index f9cf685c9..000000000 --- a/src/store/modules/list/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import * as action from './action' -import * as getter from './getter' - -export { action, getter } -export { default as reducer } from './reducer' diff --git a/src/store/modules/list/reducer.js b/src/store/modules/list/reducer.js deleted file mode 100644 index c7f187220..000000000 --- a/src/store/modules/list/reducer.js +++ /dev/null @@ -1,338 +0,0 @@ -import { TYPES } from './action' - -const allList = global.allList = {} - -const allListInit = (defaultList, loveList, userList) => { - for (const id of Object.keys(allList)) { - delete allList[id] - } - allList[defaultList.id] = defaultList - allList[loveList.id] = loveList - for (const list of userList) allList[list.id] = list -} -const allListUpdate = list => { - allList[list.id] = list -} -const allListRemove = list => { - delete allList[list.id] -} - -// state -const initialState = { - isInitedList: false, - defaultList: { - id: 'default', - name: '试听列表', - list: [], - }, - loveList: { - id: 'love', - name: '我的收藏', - list: [], - }, - tempList: { - id: 'temp', - name: '临时列表', - list: [], - }, - userList: [], - listPosition: {}, - isJumpPosition: false, -} - -const updateStateList = (state, ids) => { - let isClonedUserList = false - let index - for (const id of ids) { - switch (id) { - case state.defaultList.id: - allList[id] = state.defaultList = { ...state.defaultList } - break - case state.loveList.id: - allList[id] = state.loveList = { ...state.loveList } - break - default: - if (!isClonedUserList) { - isClonedUserList = true - state.userList = [...state.userList] - } - index = state.userList.findIndex(l => l.id == id) - if (index < 0) continue - allList[id] = state.userList[index] = { ...state.userList[index] } - break - } - } - return state -} - -const mutations = { - [TYPES.initList](state, { defaultList, loveList, userList }) { - const newState = { ...state } - const ids = [] - if (defaultList != null) { - newState.defaultList = { ...state.defaultList, list: defaultList.list } - ids.push(defaultList.id) - } - if (loveList != null) { - newState.loveList = { ...state.loveList, list: loveList.list } - ids.push(loveList.id) - } - if (userList != null) { - newState.userList = userList - for (const list of userList) { - ids.push(list.id) - } - } - allListInit(newState.defaultList, newState.loveList, newState.userList) - newState.isInitedList = true - return updateStateList(newState, [ids]) - // console.log(allList.default, newState, ids) - // return newState - }, - [TYPES.setSyncList](state, { defaultList, loveList, userList }) { - const newState = { ...state } - newState.defaultList = defaultList - newState.loveList = loveList - newState.userList = userList - allListInit(newState.defaultList, newState.loveList, newState.userList) - return newState - }, - /* [TYPES.initList](state, { defaultList, loveList, userList }) { - const newState = { ...state } - if (defaultList != null) newState.defaultList = { ...state.defaultList, list: defaultList.list } - if (loveList != null) newState.loveList = { ...state.loveList, list: loveList.list } - if (userList != null) newState.userList = userList - allListInit(state.defaultList, state.loveList, state.userList) - state.isInitedList = true - return newState - }, - [TYPES.setList](state, { id, list, name, location }) { - const targetList = allList[id] - if (targetList) { - if (name && targetList.name === name) { - targetList.list.splice(0, targetList.list.length, ...list) - targetList.location = location - return - } - - id += '_' + Math.random() - } - const newList = { - name, - id, - list, - location, - } - allListUpdate(newList) - return { ...state, userList: [...state.userList, newList] } - }, */ - [TYPES.listAdd](state, { id, musicInfo, addMusicLocationType }) { - const targetList = allList[id] - if (!targetList) return state - if (targetList.list.some(s => s.songmid === musicInfo.songmid)) return state - switch (addMusicLocationType) { - case 'top': - targetList.list = [musicInfo, ...targetList.list] - break - case 'bottom': - default: - targetList.list = [...targetList.list, musicInfo] - break - } - return updateStateList({ ...state }, [id]) - }, - [TYPES.listMove](state, { fromId, musicInfo, toId, addMusicLocationType }) { - const fromList = allList[fromId] - const toList = allList[toId] - if (!fromList || !toList) return state - const newFromList = [...fromList.list] - let songmid = musicInfo.songmid - newFromList.splice(fromList.list.findIndex(m => m.songmid == songmid), 1) - fromList.list = newFromList - const index = toList.list.findIndex(s => s.songmid === musicInfo.songmid) - if (index < 0) { - switch (addMusicLocationType) { - case 'top': - toList.list = [musicInfo, ...toList.list] - break - case 'bottom': - default: - toList.list = [...toList.list, musicInfo] - break - } - } - return updateStateList({ ...state }, [fromId, toId]) - }, - [TYPES.listAddMultiple](state, { id, list, addMusicLocationType }) { - const targetList = allList[id] - if (!targetList) return state - let newList - const map = {} - const ids = [] - switch (addMusicLocationType) { - case 'top': - newList = [...list, ...targetList.list] - for (let i = newList.length - 1; i > -1; i--) { - const item = newList[i] - if (map[item.songmid]) continue - ids.unshift(item.songmid) - map[item.songmid] = item - } - break - case 'bottom': - default: - newList = [...targetList.list, ...list] - for (const item of newList) { - if (map[item.songmid]) continue - ids.push(item.songmid) - map[item.songmid] = item - } - break - } - targetList.list = ids.map(id => map[id]) - return updateStateList({ ...state }, [id]) - }, - [TYPES.listRemove](state, { listId, id }) { - const targetList = allList[listId] - // console.log(targetList, id, index) - if (!targetList) return state - const index = targetList.list.findIndex(item => item.songmid == id) - if (index < 0) return state - const newTargetList = [...targetList.list] - newTargetList.splice(index, 1) - targetList.list = newTargetList - return updateStateList({ ...state }, [listId]) - }, - [TYPES.listRemoveMultiple](state, { listId, ids: musicIds }) { - const targetList = allList[listId] - if (!targetList) return state - const map = {} - const ids = [] - for (const item of targetList.list) { - ids.push(item.songmid) - map[item.songmid] = item - } - for (const songmid of musicIds) { - if (map[songmid]) delete map[songmid] - } - const newList = [] - for (const id of ids) if (map[id]) newList.push(map[id]) - - targetList.list = newList - return updateStateList({ ...state }, [listId]) - }, - [TYPES.listClear](state, id) { - const targetList = allList[id] - if (!targetList) return state - targetList.list = [] - return updateStateList({ ...state }, [id]) - }, - [TYPES.updateMusicInfo](state, { listId, id, data }) { - const targetList = allList[listId] - if (!targetList) return state - const targetMusicInfo = targetList.list.find(item => item.songmid == id) - if (!targetMusicInfo) return state - const newTargetList = [...targetList.list] - Object.assign(targetMusicInfo, data) - targetList.list = newTargetList - return updateStateList({ ...state }, [listId]) - }, - - [TYPES.createUserList](state, { name, id, source, sourceListId, position }) { - let newList = state.userList.find(item => item.id === id) - if (newList) return state - const newState = { ...state } - newList = { - name, - id, - list: [], - source, - sourceListId, - } - const userList = [...state.userList] - if (position == null) { - userList.push(newList) - } else { - newList.locationUpdateTime = Date.now() - userList.splice(position + 1, 0, newList) - } - newState.userList = userList - allListUpdate(newList) - return newState - }, - [TYPES.removeUserList](state, index) { - const newState = { ...state } - const newUserList = [...newState.userList] - const removedList = newUserList.splice(index, 1)[0] - allListRemove(removedList) - newState.userList = newUserList - return newState - }, - [TYPES.setUserListName](state, { id, name }) { - const targetList = allList[id] - if (!targetList) return state - targetList.name = name - return updateStateList({ ...state }, [id]) - }, - [TYPES.setUserListPosition](state, { id, position }) { - const targetList = allList[id] - if (!targetList) return state - const index = state.userList.findIndex(l => l.id == targetList.id) - if (index < 0) return state - const newState = { ...state, userList: [...state.userList] } - newState.userList.splice(index, 1) - newState.userList.splice(Math.max(Math.min(position, newState.userList.length), 0), 0, targetList) - return newState - }, - [TYPES.setMusicPosition](state, { id, position, list }) { - const targetList = allList[id] - if (!targetList) return state - targetList.list.splice(position - 1, 0, ...list) - return updateStateList({ ...state }, [id]) - }, - // { fromId, toId, list } - // [TYPES.setListScroll](state, { id, location }) { - // const targetList = allList[id] - // if (!targetList) return state - // targetList.location = location - // return updateStateList({ ...state }, [id]) - // }, - [TYPES.setOtherSource](state, { otherSource, id, index }) { - const targetList = allList[id] - if (!targetList) return state - const newTargetList = [...targetList.list] - newTargetList[index].otherSource = otherSource - targetList.list = newTargetList - return updateStateList({ ...state }, [id]) - }, - [TYPES.clearCache](state) { - const lists = Object.values(global.allList) - for (const { list } of lists) { - for (const item of list) { - if (item.otherSource) item.otherSource = null - if (item.typeUrl['128k']) delete item.typeUrl['128k'] - if (item.typeUrl['320k']) delete item.typeUrl['320k'] - if (item.typeUrl.flac) delete item.typeUrl.flac - if (item.typeUrl.wav) delete item.typeUrl.wav - - // PC v1.8.2以前的Lyric - if (item.lxlrc) delete item.lxlrc - if (item.lrc) delete item.lrc - if (item.tlrc) delete item.tlrc - } - } - return state - }, - - [TYPES.jumpPosition](state, isJumpPosition) { - return { - ...state, - isJumpPosition, - } - }, -} - -export default (state = initialState, action) => mutations[action.type] - ? mutations[action.type](state, action.payload) - : state - diff --git a/src/store/modules/player/action.js b/src/store/modules/player/action.js deleted file mode 100644 index 4ed2663ae..000000000 --- a/src/store/modules/player/action.js +++ /dev/null @@ -1,963 +0,0 @@ -import { AppState } from 'react-native' -import music from '@/utils/music' -import { initial as msInitial, isInitialized } from '@/plugins/player' -import { - playMusic as msPlayMusic, - play, - stop, - pause, - seekTo, - resetPlay, - getPosition, - isEmpty, - destroy as msDestroy, -} from '@/plugins/player/utils' -import { - buildTrack, - buildTracks, - delayUpdateMusicInfo, -} from '@/plugins/player/playList' -import { getRandom } from '@/utils' -import { getMusicUrl, saveMusicUrl, getLyric, saveLyric, assertApiSupport, savePlayInfo, saveList, checkNotificationPermission } from '@/utils/tools' -import { playInfo as playInfoGetter } from './getter' -import { play as lrcPlay, setLyric, pause as lrcPause, stop as lrcStop, toggleTranslation as lrcToggleTranslation, toggleRoma as lrcToggleRoma } from '@/utils/lyric' -import { - showLyric, hideLyric, - setLyric as lrcdSetLyric, - toggleLock, - setTheme, - setLyricTextPosition, - setAlpha, - setTextSize, - setWidth, - setMaxLineNum, - setSingleLine, - setShowToggleAnima, -} from '@/utils/lyricDesktop' -import { action as listAction } from '@/store/modules/list' -import { LIST_ID_PLAY_LATER, MUSIC_TOGGLE_MODE } from '@/config/constant' -import { i18n } from '@/plugins/i18n' -// import { defaultList } from '../list/getter' -import { tranditionalize } from '@/utils/simplify-chinese-main' - -export const TYPES = { - setPic: null, - setList: null, - setPlayIndex: null, - addMusicToPlayedList: null, - removeMusicFormPlayedList: null, - clearPlayedList: null, - visiblePlayerDetail: null, - playNext: null, - playPrev: null, - setStatus: null, - setGetingUrlState: null, - setPlayMusicInfo: null, - setTempPlayList: null, - removeTempPlayList: null, - clearTempPlayeList: null, - updateListInfo: null, -} - -export const STATUS = { - none: 'NONE', - playing: 'PLAYING', - pause: 'PAUSE', - stop: 'STOP', - error: 'ERROR', - buffering: 'BUFFERING', - connecting: 'CONNECTING', - gettingUrl: 'GETTING_URL', -} - -for (const key of Object.keys(TYPES)) { - TYPES[key] = `player__${key}` -} - -let timeout -let _playMusicInfo = null -let playMusicId = null -// let nextMusic = null - -const getPlayType = (state, songInfo) => { - let type = '128k' - const list = global.globalObj.qualityList[songInfo.source] - if (state.common.setting.player.highQuality && songInfo._types['320k'] && list && list.includes('320k')) type = '320k' - return type -} - -// const handleRestorePlay = (state, dispatch, playMusicInfo, musicInfo) => { -// if (!musicInfo.img) { -// dispatch(getPic(musicInfo)).then(async() => { -// if (playMusicId != id) return -// const musicUrl = await getMusicUrl(musicInfo, type) -// if (musicUrl) { -// console.log('+++updateMusicInfo+++') -// // setTimeout(() => { -// updateMusicInfo(buildTrack(musicInfo, type, musicUrl)) -// // }, 1000) -// } -// }) -// } -// dispatch(getLrc(musicInfo)).then(({ lyric, tlyric }) => { -// if (playMusicId != id) return -// setLyric(lyric) -// const player = getState().player -// if (player.status == STATUS.playing && !player.isGettingUrl) { -// getPosition().then(position => { -// lrcPlay(position * 1000) -// }) -// } -// }) -// if (state.common.setting.player.togglePlayMethod == 'random') dispatch({ type: TYPES.addMusicToPlayedList, payload: playMusicInfo }) -// } - -const handlePlayMusic = async({ getState, dispatch, playMusicInfo, musicInfo, isRefresh = false, time = 0 }) => { - const state = getState() - - // if (global.restorePlayInfo) { - // handleRestorePlay(state, dispatch, playMusicInfo, musicInfo) - - // global.restorePlayInfo = null - // return - // } - - const type = getPlayType(state, musicInfo) - if (timeout) { - clearTimeout(timeout) - timeout = null - } - // setLyric('') - console.log('Handle Play Music ====================>', musicInfo.name) - global.playInfo.currentPlayMusicInfo = _playMusicInfo = musicInfo - let id = `${musicInfo.source}//${musicInfo.songmid}//${type}` - playMusicId = id - - global.playInfo.isPlaying = false - if (global.restorePlayInfo) { - const track = buildTrack({ musicInfo, type }) - delayUpdateMusicInfo(track) - track.id += track.id + '//restorePlay' - playMusicId = playMusicId + '//restorePlay' - msPlayMusic([track]) - if (!isRefresh && state.common.setting.player.togglePlayMethod == 'random') dispatch({ type: TYPES.addMusicToPlayedList, payload: playMusicInfo }) - - // console.log(musicInfo.img) - if (!musicInfo.img) { - dispatch(getPic(musicInfo)).then(async() => { - const musicUrl = await getMusicUrl(musicInfo, type) - if (playMusicId != id) return - if (musicUrl && state.common.setting.player.isShowNotificationImage) { - // console.log('+++updateMusicInfo+++') - // setTimeout(() => { - delayUpdateMusicInfo(buildTrack({ musicInfo, type, url: musicUrl })) - // }, 1000) - } - }) - } - dispatch(getLrc(musicInfo)).then(({ lyric, tlyric, rlyric }) => { - if (playMusicId != id) return - const { common, player } = getState() - setLyric(common.setting.player.isS2t ? tranditionalize(lyric) : lyric, common.setting.player.isS2t ? tranditionalize(tlyric) : tlyric, rlyric) - if (player.status == STATUS.playing && !player.isGettingUrl) { - getPosition().then(position => { - lrcPlay(position * 1000) - }) - } - }) - return - } - - dispatch(setGetingUrlState(true)) - dispatch(setStatus({ - status: STATUS.gettingUrl, - text: '加载中...', - })) - delayUpdateMusicInfo(buildTrack({ musicInfo, type })) - Promise.all([ - dispatch(getUrl({ musicInfo, type, isRefresh })), - resetPlay(), - ]).then(([url]) => { - // console.log('url get done', getState().player.status) - if (playMusicId != id) return - switch (getState().player.status) { - case STATUS.stop: - case STATUS.pause: - return - } - msPlayMusic(buildTracks({ musicInfo, type, url }), time) - }).catch(err => { - if (playMusicId != id) return - dispatch(setStatus({ status: STATUS.error, text: err.message })) - if (AppState.currentState == 'active') { - console.log('wait 2s...') - timeout = setTimeout(() => { - console.log('play next music') - dispatch(playNext()) - }, 2000) - } else { - console.log('play next music') - dispatch(playNext()) - } - }).finally(() => { - if (playMusicId != id) return - if (getState().player.isGettingUrl) dispatch(setGetingUrlState(false)) - // console.log('set url getting done') - }) - // console.log(AppState.currentState) - if (!isRefresh && !playMusicInfo.isTempPlay && state.common.setting.player.togglePlayMethod == 'random') dispatch({ type: TYPES.addMusicToPlayedList, payload: playMusicInfo }) - - // console.log(musicInfo.img) - if (!musicInfo.img) { - dispatch(getPic(musicInfo)).then(() => { - if (playMusicId != id || !state.common.setting.player.isShowNotificationImage) return - delayUpdateMusicInfo(buildTrack({ musicInfo, type })) - }) - } - dispatch(getLrc(musicInfo)).then(({ lyric, tlyric, rlyric }) => { - if (playMusicId != id) return - const { common, player } = getState() - setLyric(common.setting.player.isS2t ? tranditionalize(lyric) : lyric, common.setting.player.isS2t ? tranditionalize(tlyric) : tlyric, rlyric) - if (player.status == STATUS.playing && !player.isGettingUrl) { - getPosition().then(position => { - lrcPlay(position * 1000) - }) - } - }) - - // nextMusic = getNextMusicInfo(state) - const playInfo = playInfoGetter(getState()) - - if (!playInfo.isTempPlay) { - savePlayInfo({ - time: 0, - maxTime: playInfo.musicInfo.interval || 0, - listId: playInfo.listId, - list: playInfo.listId == null ? playInfo.list : null, - index: playInfo.playIndex, - }) - } -} -/* -const getNextMusicInfo = state => { - const currentMusic = state.player.listInfo.list[state.player.playIndex] - let playedList = [...state.player.playedList] - const currentList = state.player.listInfo.list - if (state.common.setting.player.togglePlayMethod == 'random' && state.player.playedList.length) { - let index = playedList.indexOf(currentMusic) - index += 1 - while (true) { - if (index < playedList.length) { - const listIndex = currentList.indexOf(playedList[index]) - if (listIndex < 0) { - playedList.splice(index, 1) - continue - } - return currentList[listIndex] - } - break - } - } - let list - while (true) { - const tempPlayedList = [...playedList] - list = currentList.filter(s => { - const index = tempPlayedList.indexOf(s) - if (index > -1) { - tempPlayedList.splice(index, 1) - return false - } - return assertApiSupport(s.source) - }) - - if (!list.length && playedList.length) { - playedList = [] - continue - } - break - } - - if (!list.length) return null - - const playIndex = list.indexOf(currentMusic) - let index - // console.log(playIndex, list) - switch (state.common.setting.player.togglePlayMethod) { - case 'listLoop': - index = playIndex === list.length - 1 ? 0 : playIndex + 1 - break - case 'random': - index = getRandom(0, list.length) - break - case 'list': - index = playIndex === list.length - 1 ? -1 : playIndex + 1 - break - case 'singleLoop': - index = playIndex - break - default: - return - } - if (index < 0) return null - return list[index] -} - */ -export const stopMusic = () => async(dispatch, getState) => { - _playMusicInfo = null - await dispatch(playMusic(null)) - dispatch(setStatus({ status: STATUS.stop, text: '' })) - lrcStop() - savePlayInfo(null) - delayUpdateMusicInfo({}) -} - -export const pauseMusic = () => async(dispatch, getState) => { - const state = getState() - if (state.isGettingUrl) { - dispatch(setStatus({ status: STATUS.pause, text: '已暂停' })) - return - } - lrcPause() - dispatch(setStatus({ status: STATUS.pause, text: '已暂停' })) - await pause() -} - -export const setStatus = ({ status, text }) => { - console.log(status, text) - return { - type: TYPES.setStatus, - payload: { status, text }, - } -} - - -const handleGetUrl = function(dispatch, listId, musicInfo, type, retryedSource = [], originMusic) { - // console.log(musicInfo.source) - if (!originMusic) originMusic = musicInfo - let reqPromise - try { - reqPromise = music[musicInfo.source].getMusicUrl(musicInfo, type).promise - } catch (err) { - reqPromise = Promise.reject(err) - } - return reqPromise.catch(err => { - if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source) - return dispatch(listAction.getOtherSource({ musicInfo: originMusic, listId })).then(otherSource => { - console.log('find otherSource', otherSource.map(s => s.source)) - if (otherSource.length) { - for (const item of otherSource) { - if (retryedSource.includes(item.source) || !assertApiSupport(item.source)) continue - console.log('try toggle to: ', item.source, item.name, item.singer, item.interval) - return handleGetUrl(dispatch, listId, item, type, retryedSource, originMusic) - } - } - return Promise.reject(err) - }) - }) -} -const handleGetPic = function(dispatch, listId, musicInfo, retryedSource = [], originMusic) { - // console.log(musicInfo.source) - if (!originMusic) originMusic = musicInfo - let reqPromise - try { - reqPromise = music[musicInfo.source].getPic(musicInfo).promise - } catch (err) { - reqPromise = Promise.reject(err) - } - return reqPromise.catch(err => { - if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source) - return dispatch(listAction.getOtherSource({ musicInfo: originMusic, listId })).then(otherSource => { - console.log('find otherSource', otherSource.map(s => s.source)) - if (otherSource.length) { - for (const item of otherSource) { - if (retryedSource.includes(item.source)) continue - console.log('try toggle to: ', item.source, item.name, item.singer, item.interval) - return handleGetPic(dispatch, listId, item, retryedSource, originMusic) - } - } - return Promise.reject(err) - }) - }) -} -const handleGetLyric = function(dispatch, listId, musicInfo, retryedSource = [], originMusic) { - if (!originMusic) originMusic = musicInfo - let reqPromise - try { - reqPromise = music[musicInfo.source].getLyric(musicInfo).promise - } catch (err) { - reqPromise = Promise.reject(err) - } - return reqPromise.catch(err => { - if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source) - return dispatch(listAction.getOtherSource({ musicInfo: originMusic, listId })).then(otherSource => { - console.log('find otherSource', otherSource.map(s => s.source)) - if (otherSource.length) { - for (const item of otherSource) { - if (retryedSource.includes(item.source)) continue - console.log('try toggle to: ', item.source, item.name, item.singer, item.interval) - return handleGetLyric(dispatch, listId, item, retryedSource, originMusic) - } - } - return Promise.reject(err) - }) - }) -} - -export const getUrl = ({ musicInfo, type, isRefresh }) => async(dispatch, getState) => { - const cachedUrl = await getMusicUrl(musicInfo, type) - if (cachedUrl && !isRefresh) return cachedUrl - - dispatch(setStatus({ - status: STATUS.gettingUrl, - text: isRefresh ? 'URL刷新中...' : 'URL获取中...', - })) - - return handleGetUrl(dispatch, getState().player.listInfo.id, musicInfo, type).then(result => { - saveMusicUrl(musicInfo, type, result.url) - // console.log('get' + musicInfo.name + ' url success: ' + result.url) - return result.url - }).catch(err => { - console.log('get' + musicInfo.name + ' url fail: ' + err.message) - return Promise.reject(err) - }) -} - -export const refreshMusicUrl = (musicInfo, restorePlayTime) => (dispatch, getState) => { - const state = getState() - const targetMusic = state.player.listInfo.list.find(s => s.songmid == musicInfo.songmid) - if (!targetMusic) { - console.log('[refreshMusicUrl]Not found target music: ', musicInfo.name) - dispatch(playNext()) - return - } - const songmid = targetMusic.songmid - const index = state.player.listInfo.list.findIndex(m => m.songmid == songmid) - return handlePlayMusic({ - getState, - dispatch, - index, - musicInfo: targetMusic, - isRefresh: true, - time: restorePlayTime, - }) -} - -export const playMusic = playMusicInfo => async(dispatch, getState) => { - // console.log(playMusicInfo) - const { player, common } = getState() - - if (!isInitialized()) { - await checkNotificationPermission() - await msInitial({ - cacheSize: common.setting.player.cacheSize, - isHandleAudioFocus: common.setting.player.isHandleAudioFocus, - }) - } - - // 从暂停播放恢复播放 - if (playMusicInfo === undefined) { - if (player.isGettingUrl || !_playMusicInfo) return - // console.log(player.isGettingUrl, _playMusicInfo) - if (/\/\/restorePlay$/.test(playMusicId) || player.status == STATUS.none || isEmpty()) { - handlePlayMusic({ - getState, - dispatch, - playMusicInfo: player.playMusicInfo, - musicInfo: player.playMusicInfo.musicInfo, - }) - return - } - console.log('play') - await play() - return - } - - // 停止播放 - let playIndex = player.playIndex - if (playMusicInfo === null) { - playIndex = -1 - dispatch({ - type: TYPES.setPlayMusicInfo, - payload: { - playMusicInfo, - playIndex, - }, - }) - global.playInfo.currentPlayMusicInfo = _playMusicInfo = playMusicInfo - playMusicId = '' - global.playInfo.isPlaying = false - await stop() - } else { // 设置歌曲信息并播放歌曲 - setLyric('') - let listId = playMusicInfo.listId - // console.log(playMusicInfo) - if (listId != LIST_ID_PLAY_LATER && !playMusicInfo.isTempPlay && listId === player.listInfo.id) { - const currentSongmid = playMusicInfo.musicInfo.songmid || playMusicInfo.musicInfo.musicInfo.songmid - playIndex = player.listInfo.list.findIndex(m => (m.songmid || m.musicInfo.songmid) == currentSongmid) - } - dispatch({ - type: TYPES.setPlayMusicInfo, - payload: { - playMusicInfo, - playIndex, - }, - }) - handlePlayMusic({ - getState, - dispatch, - playMusicInfo, - musicInfo: playMusicInfo.musicInfo, - }) - } -} - -export const setProgress = time => async(dispatch, getState) => { - const { player } = getState() - if (player.isGettingUrl || !_playMusicInfo) return - await seekTo(time) - if (player.status != STATUS.playing) dispatch(playMusic()) -} - -export const getPic = musicInfo => (dispatch, getState) => { - return handleGetPic(dispatch, getState().player.listInfo.id, musicInfo).then(url => { - // picRequest = null - dispatch({ type: TYPES.setPic, payload: { musicInfo, url } }) - const state = getState() - if (state.player.listInfo.id) saveList(global.allList[state.player.listInfo.id]) - }).catch(err => { - // picRequest = null - return Promise.reject(err) - }) -} -export const getLrc = musicInfo => async(dispatch, getState) => { - let lyricInfo = await getLyric(musicInfo) - if (lyricInfo.lyric && lyricInfo.tlyric != null) { - if (lyricInfo.rlyric == null) { - if (musicInfo.source != 'wy') return lyricInfo - } return lyricInfo - } - - return handleGetLyric(dispatch, getState().player.listInfo.id, musicInfo).then(({ lyric, tlyric, rlyric }) => { - // picRequest = null - lyricInfo = { lyric, tlyric, rlyric } - saveLyric(musicInfo, lyricInfo) - return lyricInfo - }).catch(err => { - // picRequest = null - return Promise.reject(err) - }) -} - -export const setList = ({ list, index }) => (dispatch, getState) => { - if (!(list && list.list && list.list[index])) return - dispatch(setListInfo(list)) - - const state = getState() - if (state.player.playedList.length) dispatch({ type: TYPES.clearPlayedList }) - if (state.player.tempPlayList.length) dispatch({ type: TYPES.clearTempPlayeList }) - return dispatch(playMusic({ - musicInfo: list.list[index], - listId: list.id, - })) -} - -const filterList = async({ playedList, listInfo, savePath, dispatch }) => { - // if (this.list.listName === null) return - let list - let canPlayList = [] - const filteredPlayedList = playedList.filter(({ listId, isTempPlay }) => listInfo.id === listId && !isTempPlay).map(({ musicInfo }) => musicInfo) - if (listInfo.id == 'download') { - list = [] - // for (const item of listInfo.list) { - // const filePath = path.join(savePath, item.fileName) - // if (!await checkPath(filePath) || !item.isComplate || /\.ape$/.test(filePath)) continue - - // canPlayList.push(item) - - // // 排除已播放音乐 - // let index = filteredPlayedList.indexOf(item) - // if (index > -1) { - // filteredPlayedList.splice(index, 1) - // continue - // } - // list.push(item) - // } - } else { - list = listInfo.list.filter(s => { - // if (!assertApiSupport(s.source)) return false - canPlayList.push(s) - - let index = filteredPlayedList.findIndex(m => (m.songmid || m.musicInfo.songmid) == s.songmid) - if (index > -1) { - filteredPlayedList.splice(index, 1) - return false - } - return true - }) - } - if (!list.length && playedList.length) { - dispatch({ type: TYPES.clearPlayedList }) - return canPlayList - } - return list -} - -export const playPrev = () => async(dispatch, getState) => { - const { player, common } = getState() - const currentListId = player.listInfo.id - const currentList = player.listInfo.list - const playInfo = playInfoGetter(getState()) - if (player.playedList.length) { - let currentSongmid - if (player.playMusicInfo.isTempPlay) { - const musicInfo = currentList[playInfo.listPlayIndex] - if (musicInfo) currentSongmid = musicInfo.songmid || musicInfo.musicInfo.songmid - } else { - currentSongmid = player.playMusicInfo.musicInfo.songmid || player.playMusicInfo.musicInfo.musicInfo.songmid - } - // 从已播放列表移除播放列表已删除的歌曲 - let index - for (index = player.playedList.findIndex(m => (m.musicInfo.songmid || m.musicInfo.musicInfo.songmid) === currentSongmid) - 1; index > -1; index--) { - const playMusicInfo = player.playedList[index] - const currentSongmid = playMusicInfo.musicInfo.songmid || playMusicInfo.musicInfo.musicInfo.songmid - if (playMusicInfo.listId == currentListId && !currentList.some(m => (m.songmid || m.musicInfo.songmid) === currentSongmid)) { - dispatch({ type: TYPES.removeMusicFormPlayedList, payload: index }) - continue - } - break - } - - if (index > -1) { - dispatch(playMusic(player.playedList[index])) - return - } - } - - let filteredList = await filterList({ - listInfo: player.listInfo, - playedList: player.playedList, - savePath: common.setting.download.savePath, - dispatch, - }) - - if (!filteredList.length) return dispatch(playMusic(null)) - - let listPlayIndex = playInfo.listPlayIndex - const currentListLength = player.listInfo.list.length - 1 - if (listPlayIndex == -1 && currentListLength) { - listPlayIndex = global.prevListPlayIndex >= currentListLength ? 0 : global.prevListPlayIndex + 1 - } - let currentIndex = listPlayIndex - if (currentIndex < 0) currentIndex = 0 - let nextIndex = currentIndex - if (!playInfo.isTempPlay) { - switch (common.setting.player.togglePlayMethod) { - case MUSIC_TOGGLE_MODE.random: - nextIndex = getRandom(0, filteredList.length) - break - case MUSIC_TOGGLE_MODE.listLoop: - case MUSIC_TOGGLE_MODE.list: - case MUSIC_TOGGLE_MODE.singleLoop: - case MUSIC_TOGGLE_MODE.none: - nextIndex = currentIndex === 0 ? filteredList.length - 1 : currentIndex - 1 - break - default: - nextIndex = -1 - return - } - if (nextIndex < 0) return - } - - dispatch(playMusic({ - musicInfo: filteredList[nextIndex], - listId: currentListId, - })) -} - -export const playNext = isAutoToggle => async(dispatch, getState) => { - const { player, common } = getState() - if (player.tempPlayList.length) { - const playMusicInfo = player.tempPlayList[0] - dispatch(removeTempPlayList(0)) - dispatch(playMusic(playMusicInfo)) - return - } - const currentListId = player.listInfo.id - const currentList = player.listInfo.list - const playInfo = playInfoGetter(getState()) - if (player.playedList.length) { - let currentSongmid - if (player.playMusicInfo.isTempPlay) { - const musicInfo = currentList[playInfo.listPlayIndex] - if (musicInfo) currentSongmid = musicInfo.songmid || musicInfo.musicInfo.songmid - } else { - currentSongmid = player.playMusicInfo.musicInfo.songmid || player.playMusicInfo.musicInfo.musicInfo.songmid - } - // 从已播放列表移除播放列表已删除的歌曲 - let index - for (index = player.playedList.findIndex(m => (m.musicInfo.songmid || m.musicInfo.musicInfo.songmid) === currentSongmid) + 1; index < player.playedList.length; index++) { - const playMusicInfo = player.playedList[index] - const currentSongmid = playMusicInfo.musicInfo.songmid || playMusicInfo.musicInfo.musicInfo.songmid - if (playMusicInfo.listId == currentListId && !currentList.some(m => (m.songmid || m.musicInfo.songmid) === currentSongmid)) { - dispatch({ type: TYPES.removeMusicFormPlayedList, payload: index }) - continue - } - break - } - - if (index < player.playedList.length) { - dispatch(playMusic(player.playedList[index])) - return - } - } - - let filteredList = await filterList({ - listInfo: player.listInfo, - playedList: player.playedList, - savePath: common.setting.download.savePath, - dispatch, - }) - - // console.log(filteredList) - if (!filteredList.length) return dispatch(playMusic(null)) - let listPlayIndex = playInfo.listPlayIndex - const currentListLength = player.listInfo.list.length - 1 - if (listPlayIndex == -1 && currentListLength) { - listPlayIndex = global.prevListPlayIndex > currentListLength ? currentListLength : global.prevListPlayIndex - 1 - } - const currentIndex = listPlayIndex - let nextIndex = currentIndex - let togglePlayMethod = common.setting.player.togglePlayMethod - if (isAutoToggle !== true) { - switch (togglePlayMethod) { - case MUSIC_TOGGLE_MODE.list: - case MUSIC_TOGGLE_MODE.singleLoop: - case MUSIC_TOGGLE_MODE.none: - togglePlayMethod = MUSIC_TOGGLE_MODE.listLoop - } - } - switch (togglePlayMethod) { - case MUSIC_TOGGLE_MODE.listLoop: - nextIndex = currentIndex === filteredList.length - 1 ? 0 : currentIndex + 1 - break - case MUSIC_TOGGLE_MODE.random: - nextIndex = getRandom(0, filteredList.length) - break - case MUSIC_TOGGLE_MODE.list: - nextIndex = currentIndex === filteredList.length - 1 ? -1 : currentIndex + 1 - break - case MUSIC_TOGGLE_MODE.singleLoop: - break - default: - nextIndex = -1 - break - } - - if (nextIndex < 0) { - dispatch(setStatus({ status: STATUS.stop, text: i18n.t('stopped') })) - lrcPause() - return - } - - dispatch(playMusic({ - musicInfo: filteredList[nextIndex], - listId: currentListId, - })) -} - - -export const setPlayIndex = index => ({ - type: TYPES.setPlayIndex, - payload: index, -}) - -export const addMusicToPlayedList = playMusicInfo => ({ - type: TYPES.addMusicToPlayedList, - payload: playMusicInfo, -}) - -export const removeMusicFormPlayedList = index => ({ - type: TYPES.removeMusicFormPlayedList, - payload: index, -}) - -export const clearPlayedList = () => ({ - type: TYPES.clearPlayedList, -}) - -export const visiblePlayerDetail = visible => ({ - type: TYPES.visiblePlayerDetail, - payload: visible, -}) - -export const setGetingUrlState = flag => ({ - type: TYPES.setGetingUrlState, - payload: flag, -}) -export const setTempPlayList = list => (dispatch, getState) => { - dispatch({ - type: TYPES.setTempPlayList, - payload: list.map(({ musicInfo, listId }) => ({ musicInfo, listId, isTempPlay: true })), - }) - if (!getState().player.playMusicInfo) dispatch(playNext()) -} -export const removeTempPlayList = index => ({ - type: TYPES.removeTempPlayList, - payload: index, -}) - -export const setListInfo = listInfo => ({ - type: TYPES.setList, - payload: listInfo, -}) - -export const toggleTranslation = isShow => async(dispatch, getState) => { - lrcToggleTranslation(isShow) - const player = getState().player - if (player.status == STATUS.playing && !player.isGettingUrl) { - getPosition().then(position => { - lrcPlay(position * 1000) - }) - } -} - -export const toggleRoma = isShow => async(dispatch, getState) => { - lrcToggleRoma(isShow) - const player = getState().player - if (player.status == STATUS.playing && !player.isGettingUrl) { - getPosition().then(position => { - lrcPlay(position * 1000) - }) - } -} - -export const toggleS2T = () => async(dispatch, getState) => { - if (!global.playInfo.currentPlayMusicInfo) return - let id = playMusicId - dispatch(getLrc(global.playInfo.currentPlayMusicInfo)).then(({ lyric, tlyric, rlyric }) => { - if (playMusicId != id) return - const { common, player } = getState() - setLyric(common.setting.player.isS2t ? tranditionalize(lyric) : lyric, common.setting.player.isS2t ? tranditionalize(tlyric) : tlyric, rlyric) - if (player.status == STATUS.playing && !player.isGettingUrl) { - getPosition().then(position => { - lrcPlay(position * 1000) - }) - } - }) -} - -export const toggleDesktopLyric = isShow => async(dispatch, getState) => { - if (isShow) { - const { common, player } = getState() - const desktopLyric = common.setting.desktopLyric - const [{ lyric, tlyric, rlyric }] = await Promise.all([ - _playMusicInfo - ? getLyric(_playMusicInfo).catch(() => ({ lyric: '', tlyric: '', rlyric: '' })) - : Promise.resolve({ lyric: '', tlyric: '', rlyric: '' }), - showLyric({ - isShowToggleAnima: desktopLyric.showToggleAnima, - isSingleLine: desktopLyric.isSingleLine, - isLock: desktopLyric.isLock, - themeId: desktopLyric.theme, - opacity: desktopLyric.style.opacity, - textSize: desktopLyric.style.fontSize, - width: desktopLyric.width, - maxLineNum: desktopLyric.maxLineNum, - positionX: desktopLyric.position.x, - positionY: desktopLyric.position.y, - textPositionX: desktopLyric.textPosition.x, - textPositionY: desktopLyric.textPosition.y, - }), - ]) - await lrcdSetLyric(common.setting.player.isS2t ? tranditionalize(lyric) : lyric, common.setting.player.isS2t ? tranditionalize(tlyric) : tlyric, rlyric) - if (player.status == STATUS.playing && !player.isGettingUrl) { - getPosition().then(position => { - lrcPlay(position * 1000) - }) - } - } else { - hideLyric() - } -} - -export const toggleDesktopLyricLock = isLock => async(dispatch, getState) => { - toggleLock(isLock) -} -export const setDesktopLyricSingleLine = isSingleLine => async(dispatch, getState) => { - setSingleLine(isSingleLine) -} -export const setDesktopLyricShowToggleAnima = showToggleAnima => async(dispatch, getState) => { - setShowToggleAnima(showToggleAnima) -} -export const setDesktopLyricWidth = width => async(dispatch, getState) => { - setWidth(width) -} -export const setDesktopLyricMaxLineNum = maxLineNum => async(dispatch, getState) => { - setMaxLineNum(maxLineNum) -} -export const setDesktopLyricTheme = theme => async(dispatch, getState) => { - setTheme(theme) -} -export const setDesktopLyricStyle = style => async(dispatch, getState) => { - if (style.opacity != null) setAlpha(style.opacity) - if (style.fontSize != null) setTextSize(style.fontSize) -} -export const setDesktopLyricTextPosition = position => async(dispatch, getState) => { - setLyricTextPosition(position.x, position.y) -} - -export const checkPlayList = listIds => async(dispatch, getState) => { - const { player, list: listState } = getState() - if (!_playMusicInfo || !listIds.some(id => player.listInfo.id === id)) return - const listInfo = global.allList[player.listInfo.id] - if (!listInfo) { - if (player.playMusicInfo.listId == LIST_ID_PLAY_LATER) { - dispatch(setListInfo(listState.defaultList)) - dispatch(setPlayIndex(-1)) - } else { - if (listState.defaultList.list.length) { - await dispatch(setList({ list: listState.defaultList, index: 0 })) - } else { - await dispatch(stopMusic()) - } - } - return - } - - const isChnagedList = listInfo !== player.listInfo - - const list = listInfo.list - - if (isChnagedList) dispatch(setListInfo(listInfo)) - if (player.playMusicInfo.isTempPlay) return - if (player.playMusicInfo.listId != LIST_ID_PLAY_LATER) { - // if (player.playIndex > listInfo.list.length) { - // dispatch(setPlayIndex(listInfo.list.length)) - // } - // } else { - let songmid = _playMusicInfo.songmid - let index = list.findIndex(m => m.songmid == songmid) - // console.log(index) - if (index < 0) { - // console.log(this.playIndex) - if (list.length) { - dispatch(setPlayIndex(Math.min(player.playIndex - 1, list.length - 1))) - // if (isChnagedList) dispatch(setListInfo(listInfo)) - await dispatch(playNext()) - } else { - // if (isChnagedList) dispatch(setListInfo(listInfo)) - await dispatch(stopMusic()) - } - } else { - // console.log(isChnagedList) - // if (isChnagedList) dispatch(setListInfo(listInfo)) - dispatch(setPlayIndex(index)) - } - // console.log(this.playIndex) - } -} - -export const destroy = () => async(dispatch, getState) => { - await msDestroy() - dispatch(setStatus({ status: STATUS.none, text: '' })) -} diff --git a/src/store/modules/player/getter.js b/src/store/modules/player/getter.js deleted file mode 100644 index e24bcc1f4..000000000 --- a/src/store/modules/player/getter.js +++ /dev/null @@ -1,67 +0,0 @@ -import { createSelector } from 'reselect' -import { LIST_ID_PLAY_LATER } from '@/config/constant' - - -// sourceInfo(state, getters, rootState, { sourceNames }) { -// return { sources: sources.map(item => ({ id: item.id, name: sourceNames[item.id] })), sortList } -// }, -// tags: state => state.tags, -// isVisibleListDetail: state => state.isVisibleListDetail, -// selectListInfo: state => state.selectListInfo, -// listData(state) { -// return state.list -// }, -// listDetail(state) { -// return state.listDetail -// }, - -export const player = state => state.player - -export const playIndex = state => state.player.playIndex - -export const status = state => state.player.status - -export const isGettingUrl = state => state.player.isGettingUrl - -export const statusText = state => state.player.statusText - -export const listInfo = state => state.player.listInfo - -export const playList = state => state.player.listInfo.list - -export const playMusicInfo = state => state.player.playMusicInfo - -export const playInfo = createSelector([playMusicInfo, listInfo, playIndex], (playMusicInfo, listInfo, playIndex) => { - if (playMusicInfo == null) return { listId: null, playIndex: -1, playListId: null, listPlayIndex: -1, isPlayList: false, musicInfo: null } - const playListId = listInfo.id - let listId = playMusicInfo.listId - const isTempPlay = !!playMusicInfo.isTempPlay - const isPlayList = listId === playListId - let newPlayIndex = -1 - let listPlayIndex = Math.min(playIndex, listInfo.list.length - 1) - - if (listId != LIST_ID_PLAY_LATER) { - const currentSongmid = playMusicInfo.musicInfo.songmid || playMusicInfo.musicInfo.musicInfo.songmid - if (isPlayList) { - newPlayIndex = listInfo.list.findIndex(m => (m.songmid || m.musicInfo.songmid) == currentSongmid) - if (!isTempPlay) listPlayIndex = newPlayIndex - } else if (listId == 'download') { - playIndex = global.downloadList.findIndex(m => m.musicInfo.songmid == currentSongmid) - } else { - let list = global.allList[listId] - if (list) newPlayIndex = list.list.findIndex(m => m.songmid == currentSongmid) - } - } - if (listPlayIndex > -1) global.prevListPlayIndex = listPlayIndex - - return { - listId, - list: listInfo.list, - playIndex: newPlayIndex, - playListId, - listPlayIndex, - isPlayList, - isTempPlay, - musicInfo: playMusicInfo.musicInfo, - } -}) diff --git a/src/store/modules/player/index.js b/src/store/modules/player/index.js deleted file mode 100644 index 6f426f867..000000000 --- a/src/store/modules/player/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import * as actions from './action' -import * as getter from './getter' - -const { STATUS, ...action } = actions - -export { action, getter, STATUS } -export { default as reducer } from './reducer' diff --git a/src/store/modules/player/reducer.js b/src/store/modules/player/reducer.js deleted file mode 100644 index db1628210..000000000 --- a/src/store/modules/player/reducer.js +++ /dev/null @@ -1,132 +0,0 @@ -import { TYPES, STATUS } from './action' -import { LIST_ID_PLAY_LATER } from '@/config/constant' - -const initialState = { - listInfo: { - list: [], - id: null, - }, - playIndex: -1, - isShowPlayerDetail: false, - playedList: [], - - playMusicInfo: null, - tempPlayList: [], - - statusText: '', - status: STATUS.none, - isGettingUrl: false, -} - - -// mitations -const mutations = { - [TYPES.setPic](state, datas) { - let targetMusic - if (!state.playMusicInfo) return state - switch (state.playMusicInfo.listId) { - case LIST_ID_PLAY_LATER: - targetMusic = datas.musicInfo - break - default: - targetMusic = state.listInfo.list.find(s => s.songmid === datas.musicInfo.songmid) - break - } - // console.log('+++++++targetMusic+++++++', targetMusic) - datas.musicInfo.img = datas.url - targetMusic.img = datas.url - const newState = { ...state } - if (state.playMusicInfo.musicInfo.source == datas.musicInfo.source && state.playMusicInfo.musicInfo.songmid === datas.musicInfo.songmid) { - const newPlayMusicInfo = { ...newState.playMusicInfo } - let index = newState.playedList.indexOf(newState.playMusicInfo) - if (index > -1) newState.playedList.splice(index, 1, newPlayMusicInfo) - newState.playMusicInfo = newPlayMusicInfo - } - return newState - }, - [TYPES.setList](state, list) { - return { - ...state, - listInfo: { - ...list, - }, - } - }, - [TYPES.setPlayIndex](state, index) { - return { - ...state, - playIndex: index, - } - // console.log(state.changePlay) - }, - [TYPES.addMusicToPlayedList](state, playMusicInfo) { - if (state.playedList.includes(playMusicInfo)) return state - state.playedList.push(playMusicInfo) - return { - ...state, - } - }, - [TYPES.removeMusicFormPlayedList](state, index) { - state.playedList.splice(index, 1) - return { - ...state, - } - }, - [TYPES.clearPlayedList](state) { - return { - ...state, - playedList: [], - } - }, - [TYPES.visiblePlayerDetail](state, visible) { - return { - ...state, - isShowPlayerDetail: visible, - } - }, - [TYPES.setStatus](state, { status, text }) { - const newState = { ...state } - if (status != null) newState.status = status - if (text != null) newState.statusText = text - return newState - }, - [TYPES.setGetingUrlState](state, flag) { - return { - ...state, - isGettingUrl: flag, - } - }, - [TYPES.setTempPlayList](state, list) { - return { - ...state, - tempPlayList: [...state.tempPlayList, ...list], - } - }, - [TYPES.removeTempPlayList](state, index) { - const tempPlayList = [...state.tempPlayList] - tempPlayList.splice(index, 1) - return { - ...state, - tempPlayList, - } - }, - [TYPES.clearTempPlayeList](state) { - return { - ...state, - tempPlayList: [], - } - }, - [TYPES.setPlayMusicInfo](state, { playMusicInfo, playIndex }) { - return { - ...state, - playMusicInfo, - playIndex, - } - }, -} - -export default (state = initialState, action) => - mutations[action.type] - ? mutations[action.type](state, action.payload) - : state - diff --git a/src/store/modules/search/action.js b/src/store/modules/search/action.js index 1ae31d8e6..db38efd13 100644 --- a/src/store/modules/search/action.js +++ b/src/store/modules/search/action.js @@ -1,4 +1,4 @@ -import music from '@/utils/music' +import music from '@/utils/musicSdk' import { deduplicationList } from '@/utils/tools' export const TYPES = { @@ -55,7 +55,7 @@ export const search = ({ page, limit }) => (dispatch, getState) => { .finally(() => dispatch({ type: TYPES.loading, payload: false })) } else { dispatch({ type: TYPES.loading, payload: true }) - return (music[state.common.setting.search.searchSource]?.musicSearch.search(text, page, limit) ?? Promise.reject(new Error('source not found'))).catch(error => { + return music[state.common.setting.search.searchSource].musicSearch.search(text, page, limit).catch(error => { console.log(error) return { allPage: 1, diff --git a/src/store/modules/search/reducer.js b/src/store/modules/search/reducer.js index a282f9b57..edcb1fa4a 100644 --- a/src/store/modules/search/reducer.js +++ b/src/store/modules/search/reducer.js @@ -1,6 +1,6 @@ import { TYPES } from './action' -import music from '@/utils/music' +import music from '@/utils/musicSdk' let historyList if (historyList == null) { diff --git a/src/store/modules/songList/action.js b/src/store/modules/songList/action.js index 309b8bde1..8dc24e2be 100644 --- a/src/store/modules/songList/action.js +++ b/src/store/modules/songList/action.js @@ -1,4 +1,4 @@ -import music from '@/utils/music' +import music from '@/utils/musicSdk' import { deduplicationList } from '@/utils/tools' const cache = new Map() @@ -28,7 +28,7 @@ export const getTags = () => (dispatch, getState) => { const state = getState() let source = state.common.setting.songList.source if (state.songList.tags[source]) return Promise.resolve() - return music[source]?.songList.getTags().then(result => dispatch(setTags({ tags: result, source }))) ?? Promise.reject(new Error('source not found')) + return music[source].songList.getTags().then(result => dispatch(setTags({ tags: result, source }))) } export const getList = ({ page = 1, isRefresh = false }) => (dispatch, getState) => { const allState = getState() diff --git a/src/store/modules/songList/reducer.js b/src/store/modules/songList/reducer.js index 3fdce253d..81cba0fff 100644 --- a/src/store/modules/songList/reducer.js +++ b/src/store/modules/songList/reducer.js @@ -1,5 +1,5 @@ import { TYPES } from './action' -import music from '@/utils/music' +import music from '@/utils/musicSdk' import { deduplicationList } from '@/utils/tools' const sortList = {} const sources = [] diff --git a/src/store/modules/top/action.js b/src/store/modules/top/action.js index c6960f01a..c8f1e3528 100644 --- a/src/store/modules/top/action.js +++ b/src/store/modules/top/action.js @@ -1,4 +1,4 @@ -import music from '@/utils/music' +import music from '@/utils/musicSdk' import { deduplicationList } from '@/utils/tools' const cache = new Map() @@ -23,8 +23,8 @@ export const getBoardsList = () => (dispatch, getState) => { // let key = `${source}${tabId}${page}` // if (state.list.length && state.key == key) return true // commit('clearList') - if (state.top.boards[source]?.length) return Promise.resolve() - return music[source]?.leaderboard.getBoards().then(result => dispatch(setBoardsList({ boards: result, source }))) ?? Promise.reject(new Error('source not found')) + if (state.top.boards[source].length) return Promise.resolve() + return music[source].leaderboard.getBoards().then(result => dispatch(setBoardsList({ boards: result, source }))) } const getListLimit = ({ source, tabId, bangId, page }) => { @@ -37,7 +37,7 @@ const getListLimit = ({ source, tabId, bangId, page }) => { if (listCache.has(prevPageKey)) { sourcePage = listCache.get(prevPageKey).sourcePage } - return music[source]?.leaderboard.getList(bangId, sourcePage + 1).then(result => { + return music[source].leaderboard.getList(bangId, sourcePage + 1).then(result => { let p = page if (listCache.has(tempListKey)) { const list = listCache.get(tempListKey) @@ -71,7 +71,7 @@ const getListLimit = ({ source, tabId, bangId, page }) => { p++ } while (result.list.length > 0) return listCache.get(`${source}__${tabId}__${page}`).data - }) ?? Promise.reject(new Error('source not found')) + }) } export const getList = ({ page, isRefresh = false }) => (dispatch, getState) => { diff --git a/src/store/modules/top/reducer.js b/src/store/modules/top/reducer.js index 12ac29847..9773e9a59 100644 --- a/src/store/modules/top/reducer.js +++ b/src/store/modules/top/reducer.js @@ -1,5 +1,5 @@ import { TYPES } from './action' -import music from '@/utils/music' +import music from '@/utils/musicSdk' import { deduplicationList } from '@/utils/tools' const sourceList = {} diff --git a/src/store/player/action.ts b/src/store/player/action.ts new file mode 100644 index 000000000..e94c1aace --- /dev/null +++ b/src/store/player/action.ts @@ -0,0 +1,107 @@ +import { arrPush, arrUnshift, formatPlayTime2 } from '@/utils' +import state from './state' + +type PlayerMusicInfoKeys = keyof LX.Player.MusicInfo +const musicInfoKeys: PlayerMusicInfoKeys[] = Object.keys(state.musicInfo) as PlayerMusicInfoKeys[] + +export default { + updatePlayIndex(playIndex: number, playerPlayIndex: number) { + state.playInfo.playIndex = playIndex + state.playInfo.playerPlayIndex = playerPlayIndex + + global.state_event.playInfoChanged({ ...state.playInfo }) + }, + setPlayListId(playerListId: string | null) { + state.playInfo.playerListId = playerListId + + global.state_event.playInfoChanged({ ...state.playInfo }) + }, + setPlayMusicInfo(listId: string | null, musicInfo: LX.Download.ListItem | LX.Music.MusicInfo | null, isTempPlay: boolean = false) { + state.playMusicInfo = { listId, musicInfo, isTempPlay } + + global.state_event.playMusicInfoChanged(state.playMusicInfo) + }, + setMusicInfo(_musicInfo: Partial<LX.Player.MusicInfo>) { + for (const key of musicInfoKeys) { + const val = _musicInfo[key] + if (val !== undefined) { + // @ts-expect-error + state.musicInfo[key] = val + } + } + + global.state_event.playerMusicInfoChanged({ ...state.musicInfo }) + }, + setIsPlay(isPlay: boolean) { + state.isPlay = isPlay + + global.state_event.playStateChanged(isPlay) + }, + setStatusText(statusText: string) { + state.statusText = statusText + global.state_event.playStateTextChanged(statusText) + }, + setNowPlayTime(time: number) { + state.progress.nowPlayTime = time + state.progress.nowPlayTimeStr = formatPlayTime2(time) + state.progress.progress = state.progress.maxPlayTime ? time / state.progress.maxPlayTime : 0 + + global.state_event.playProgressChanged({ ...state.progress }) + }, + setMaxplayTime(time: number) { + state.progress.maxPlayTime = time + state.progress.maxPlayTimeStr = formatPlayTime2(time) + state.progress.progress = time ? state.progress.nowPlayTime / time : 0 + + global.state_event.playProgressChanged({ ...state.progress }) + }, + setProgress(currentTime: number, totalTime: number) { + state.progress.nowPlayTime = currentTime + state.progress.nowPlayTimeStr = formatPlayTime2(currentTime) + state.progress.maxPlayTime = totalTime + state.progress.maxPlayTimeStr = formatPlayTime2(totalTime) + state.progress.progress = totalTime ? state.progress.nowPlayTime / currentTime : 0 + + global.state_event.playProgressChanged({ ...state.progress }) + }, + addPlayedList(info: LX.Player.PlayMusicInfo) { + if (state.playedList.some(m => m.musicInfo.id == info.musicInfo.id)) return + state.playedList.push(info) + + global.state_event.playPlayedListChanged({ ...state.playedList }) + }, + removePlayedList(index: number) { + state.playedList.splice(index, 1) + + global.state_event.playPlayedListChanged({ ...state.playedList }) + }, + clearPlayedList() { + state.playedList = [] + + global.state_event.playPlayedListChanged({ ...state.playedList }) + }, + addTempPlayList(list: LX.Player.TempPlayListItem[]) { + const topList: Array<{ listId: string, musicInfo: LX.Music.MusicInfo | LX.Download.ListItem }> = [] + const bottomList = list.filter(({ isTop, ...musicInfo }) => { + if (isTop) { + topList.push(musicInfo) + return false + } + return true + }) + if (topList.length) arrUnshift(state.tempPlayList, topList.map(({ musicInfo, listId }) => ({ musicInfo, listId, isTempPlay: true }))) + if (bottomList.length) arrPush(state.tempPlayList, bottomList.map(({ musicInfo, listId }) => ({ musicInfo, listId, isTempPlay: true }))) + + global.state_event.playTempPlayListChanged({ ...state.tempPlayList }) + }, + removeTempPlayList(index: number) { + state.tempPlayList.splice(index, 1) + + global.state_event.playTempPlayListChanged({ ...state.tempPlayList }) + }, + clearTempPlayeList() { + state.tempPlayList = [] + + global.state_event.playTempPlayListChanged({ ...state.tempPlayList }) + }, +} diff --git a/src/store/player/hook.ts b/src/store/player/hook.ts new file mode 100644 index 000000000..8c5eb8b57 --- /dev/null +++ b/src/store/player/hook.ts @@ -0,0 +1,85 @@ +import { isActive } from '@/utils/tools' +import { useEffect, useState } from 'react' +import state, { type InitState } from './state' + +export const usePlayerMusicInfo = () => { + const [value, update] = useState(state.musicInfo) + + useEffect(() => { + global.state_event.on('playerMusicInfoChanged', update) + return () => { + global.state_event.off('playerMusicInfoChanged', update) + } + }, []) + + return value +} + +export const usePlayMusicInfo = () => { + const [value, update] = useState(state.playMusicInfo) + + useEffect(() => { + global.state_event.on('playMusicInfoChanged', update) + return () => { + global.state_event.off('playMusicInfoChanged', update) + } + }, []) + + return value +} + +export const usePlayInfo = () => { + const [value, update] = useState(state.playInfo) + + useEffect(() => { + global.state_event.on('playInfoChanged', update) + return () => { + global.state_event.off('playInfoChanged', update) + } + }, []) + + return value +} + +export const useStatusText = () => { + const [value, update] = useState(state.statusText) + + useEffect(() => { + global.state_event.on('playStateTextChanged', update) + return () => { + global.state_event.off('playStateTextChanged', update) + } + }, []) + + return value +} + +export const useIsPlay = () => { + const [value, update] = useState(state.isPlay) + + useEffect(() => { + global.state_event.on('playStateChanged', update) + return () => { + global.state_event.off('playStateChanged', update) + } + }, []) + + return value +} + +export const useProgress = (autoUpdate = true) => { + const [value, update] = useState(state.progress) + + useEffect(() => { + if (!autoUpdate) return + const handleUpdate = (progress: InitState['progress']) => { + if (isActive()) update(progress) + } + global.state_event.on('playProgressChanged', handleUpdate) + return () => { + global.state_event.off('playProgressChanged', handleUpdate) + } + }, [autoUpdate]) + + return value +} diff --git a/src/store/player/state.ts b/src/store/player/state.ts new file mode 100644 index 000000000..aa2a0c1f7 --- /dev/null +++ b/src/store/player/state.ts @@ -0,0 +1,75 @@ +export interface InitState { + playMusicInfo: { + /** + * 当前播放歌曲的列表 id + */ + musicInfo: LX.Player.PlayMusicInfo['musicInfo'] | null + /** + * 当前播放歌曲的列表 id + */ + listId: LX.Player.PlayMusicInfo['listId'] | null + /** + * 是否属于 “稍后播放” + */ + isTempPlay: boolean + } + playInfo: LX.Player.PlayInfo + musicInfo: LX.Player.MusicInfo + + isPlay: boolean + statusText: string + + playedList: LX.Player.PlayMusicInfo[] + tempPlayList: LX.Player.PlayMusicInfo[] + + progress: { + nowPlayTime: number + maxPlayTime: number + progress: number + nowPlayTimeStr: string + maxPlayTimeStr: string + } +} + +const state: InitState = { + playInfo: { + playIndex: -1, + playerListId: null, + playerPlayIndex: -1, + }, + playMusicInfo: { + listId: null, + musicInfo: null, + isTempPlay: false, + }, + musicInfo: { + id: null, + pic: null, + lrc: null, + tlrc: null, + rlrc: null, + lxlrc: null, + rawlrc: null, + // url: null, + name: '', + singer: '', + album: '', + }, + + isPlay: false, + statusText: '', + + playedList: [], + tempPlayList: [], + + progress: { + nowPlayTime: 0, + maxPlayTime: 0, + progress: 0, + nowPlayTimeStr: '00:00', + maxPlayTimeStr: '00:00', + }, +} + + +export default state diff --git a/src/store/reducer.js b/src/store/reducer.js deleted file mode 100644 index 0110c35ac..000000000 --- a/src/store/reducer.js +++ /dev/null @@ -1,27 +0,0 @@ -// import { persistCombineReducers } from 'redux-persist' -// import AsyncStorage from '@react-native-async-storage/async-storage' -import { combineReducers } from 'redux' - -import * as modules from './modules' - -// const config = { -// key: 'LIFTED_REDUX_STORE', -// storage: AsyncStorage, -// } - -const reducers = {} - - -for (const [moduleName, { reducer }] of Object.entries(modules)) { - reducers[moduleName] = reducer -} - -const combinedReducers = combineReducers(reducers) - -// const appReducer = persistCombineReducers(config, reducers) - -export { - reducers, - combinedReducers, -} -// export default (state, action) => appReducer(state, action) diff --git a/src/store/search/action.ts b/src/store/search/action.ts new file mode 100644 index 000000000..92539a19b --- /dev/null +++ b/src/store/search/action.ts @@ -0,0 +1,64 @@ +import state, { type InitState } from './state' +// let isInitedSearchHistory = false +// const saveSearchHistoryListThrottle = throttle((list: LX.List.SearchHistoryList) => { +// saveSearchHistoryList(list) +// }, 500) + + +// export const getHistoryList = async() => { +// if (isInitedSearchHistory) return +// historyList.push(...(await getSearchHistoryList() ?? [])) +// isInitedSearchHistory = true +// } +// export const addHistoryWord = async(word: string) => { +// if (!appSetting['search.isShowHistorySearch']) return +// if (!isInitedSearchHistory) await getHistoryList() +// let index = historyList.indexOf(word) +// if (index > -1) historyList.splice(index, 1) +// if (historyList.length >= 15) historyList.splice(14, historyList.length - 14) +// historyList.unshift(word) +// saveSearchHistoryListThrottle(toRaw(historyList)) +// } +// export const removeHistoryWord = (index: number) => { +// historyList.splice(index, 1) +// saveSearchHistoryListThrottle(toRaw(historyList)) +// } +// export const clearHistoryList = (id: string) => { +// historyList.splice(0, historyList.length) +// saveSearchHistoryList([]) +// } + + +export default { + setSearchType(type: InitState['searchType']) { + state.searchType = type + }, + setSearchText(text: string) { + state.searchText = text + }, + setTipListInfo(keyword: InitState['tipListInfo']['text'], source: InitState['tipListInfo']['source']) { + state.tipListInfo.text = keyword + state.tipListInfo.source = source + }, + setTipList(list: InitState['tipListInfo']['list']) { + state.tipListInfo.list = list + }, + setHistoryWord(list: string[]) { + state.historyList = list + }, + addHistoryWord(word: string) { + let index = state.historyList.indexOf(word) + if (index > -1) state.historyList.splice(index, 1) + if (state.historyList.length >= 15) state.historyList.splice(14, state.historyList.length - 14) + state.historyList.unshift(word) + return [...state.historyList] + }, + removeHistoryWord(index: number) { + state.historyList.splice(index, 1) + return [...state.historyList] + }, + clearHistoryList() { + state.historyList = [] + return state.historyList + }, +} diff --git a/src/store/search/music/action.ts b/src/store/search/music/action.ts new file mode 100644 index 000000000..64a341cf0 --- /dev/null +++ b/src/store/search/music/action.ts @@ -0,0 +1,91 @@ +import state, { type InitState, type ListInfo, type Source } from './state' +import { sortInsert, similar, arrPush } from '@/utils/common' +import { deduplicationList, toNewMusicInfo } from '@/utils' + + +export interface SearchResult { + list: LX.Music.MusicInfoOnline[] + allPage: number + limit: number + total: number + source: LX.OnlineSource +} + + +/** + * 按搜索关键词重新排序列表 + * @param list 歌曲列表 + * @param keyword 搜索关键词 + * @returns 排序后的列表 + */ +const handleSortList = (list: LX.Music.MusicInfoOnline[], keyword: string) => { + let arr: any[] = [] + for (const item of list) { + sortInsert(arr, { + num: similar(keyword, `${item.name} ${item.singer}`), + data: item, + }) + } + return arr.map(item => item.data).reverse() +} + + +const setLists = (results: SearchResult[], page: number, text: string): LX.Music.MusicInfoOnline[] => { + let pages = [] + let total = 0 + // let limit = 0 + let list = [] as LX.Music.MusicInfoOnline[] + for (const source of results) { + state.maxPages[source.source] = source.allPage + if (source.allPage < page) continue + arrPush(list, source.list) + pages.push(source.allPage) + total += source.total + // limit = Math.max(source.limit, limit) + } + list = handleSortList(list.map(s => toNewMusicInfo(s) as LX.Music.MusicInfoOnline), text) + let listInfo = state.listInfos.all + listInfo.maxPage = Math.max(...pages) + listInfo.total = total + // listInfo.limit = limit + listInfo.page = page + listInfo.list = deduplicationList(page > 1 ? [...listInfo.list, ...list] : list) + + return listInfo.list +} + +const setList = (datas: SearchResult, page: number, text: string): LX.Music.MusicInfoOnline[] => { + // console.log(datas.source, datas.list) + let listInfo = state.listInfos[datas.source] as ListInfo + const list = datas.list.map(s => toNewMusicInfo(s) as LX.Music.MusicInfoOnline) + listInfo.list = deduplicationList(page == 1 ? list : [...listInfo.list, ...list]) + listInfo.total = datas.total + listInfo.maxPage = datas.allPage + listInfo.page = page + listInfo.limit = datas.limit + + return listInfo.list +} + +export default { + setSource(source: InitState['source']) { + state.source = source + }, + setSearchText(searchText: InitState['searchText']) { + state.searchText = searchText + }, + setListInfo(result: SearchResult | SearchResult[], page: number, text: string) { + if (Array.isArray(result)) { + return setLists(result, page, text) + } else { + return setList(result, page, text) + } + }, + clearListInfo(sourceId: Source) { + let listInfo = state.listInfos[sourceId] as ListInfo + listInfo.list = [] + listInfo.page = 0 + listInfo.maxPage = 0 + listInfo.total = 0 + }, +} diff --git a/src/store/search/music/state.ts b/src/store/search/music/state.ts new file mode 100644 index 000000000..0f7834804 --- /dev/null +++ b/src/store/search/music/state.ts @@ -0,0 +1,58 @@ +import music from '@/utils/musicSdk' + +export declare interface ListInfo { + list: LX.Music.MusicInfoOnline[] + total: number + page: number + maxPage: number + limit: number + key: string | null +} + +interface ListInfos extends Partial<Record<LX.OnlineSource, ListInfo>> { + 'all': ListInfo +} + +export type Source = LX.OnlineSource | 'all' + +export interface InitState { + searchText: string + source: Source + sources: Source[] + listInfos: ListInfos + maxPages: Partial<Record<LX.OnlineSource, number>> +} + +const state: InitState = { + searchText: '', + source: 'kw', + sources: [], + listInfos: { + all: { + page: 1, + maxPage: 0, + limit: 30, + total: 0, + list: [], + key: null, + }, + }, + maxPages: {}, +} + +for (const source of music.sources) { + if (!music[source.id as LX.OnlineSource]?.musicSearch) continue + state.sources.push(source.id as LX.OnlineSource) + state.listInfos[source.id as LX.OnlineSource] = { + page: 1, + maxPage: 0, + limit: 30, + total: 0, + list: [], + key: '', + } + state.maxPages[source.id as LX.OnlineSource] = 0 +} +state.sources.push('all') + +export default state diff --git a/src/store/search/songlist/action.ts b/src/store/search/songlist/action.ts new file mode 100644 index 000000000..4535eb52f --- /dev/null +++ b/src/store/search/songlist/action.ts @@ -0,0 +1,90 @@ +import { sortInsert, similar } from '@/utils/common' + +import type { InitState, ListInfoItem, SearchListInfo, Source } from './state' +import state from './state' + +export interface SearchResult { + list: ListInfoItem[] + limit: number + total: number + source: LX.OnlineSource +} + + +/** + * 按搜索关键词重新排序列表 + * @param list 歌曲列表 + * @param keyword 搜索关键词 + * @returns 排序后的列表 + */ +const handleSortList = (list: ListInfoItem[], keyword: string) => { + let arr: any[] = [] + for (const item of list) { + sortInsert(arr, { + num: similar(keyword, item.name), + data: item, + }) + } + return arr.map(item => item.data).reverse() +} + + +let maxTotals: Partial<Record<LX.OnlineSource, number>> = { + +} +const setLists = (results: SearchResult[], page: number, text: string): ListInfoItem[] => { + let totals = [] + // let limit = 0 + let list = [] + for (const source of results) { + list.push(...source.list) + totals.push(source.total) + maxTotals[source.source] = source.total + state.maxPages[source.source] = Math.ceil(source.total / source.limit) + // limit = Math.max(source.limit, limit) + } + + let listInfo = state.listInfos.all + listInfo.total = Math.max(...totals) + listInfo.page = page + list = handleSortList(list, text) + listInfo.list = page > 1 ? [...listInfo.list, ...list] : list + return listInfo.list +} + +const setList = (datas: SearchResult, page: number, text: string): ListInfoItem[] => { + // console.log(datas.source, datas.list) + let listInfo = state.listInfos[datas.source] as SearchListInfo + listInfo.list = page == 1 ? datas.list : [...listInfo.list, ...datas.list] + listInfo.total = datas.total + listInfo.page = page + listInfo.limit = datas.limit + return listInfo.list +} + + +export default { + setSource(source: InitState['source']) { + state.source = source + }, + setSearchText(searchText: InitState['searchText']) { + state.searchText = searchText + }, + setListInfo(result: SearchResult | SearchResult[], page: number, text: string) { + if (Array.isArray(result)) { + return setLists(result, page, text) + } else { + return setList(result, page, text) + } + }, + clearListInfo(sourceId: Source) { + let listInfo = state.listInfos[sourceId] as SearchListInfo + listInfo.page = 1 + listInfo.limit = 20 + listInfo.total = 0 + listInfo.list = [] + listInfo.key = null + listInfo.tagId = '' + listInfo.sortId = '' + }, +} diff --git a/src/store/search/songlist/state.ts b/src/store/search/songlist/state.ts new file mode 100644 index 000000000..31450fca8 --- /dev/null +++ b/src/store/search/songlist/state.ts @@ -0,0 +1,61 @@ +import music from '@/utils/musicSdk' + + +// import { deduplicationList } from '@common/utils/renderer' + +import { type ListInfo } from '@/store/songlist/state' +export type { ListInfoItem } from '@/store/songlist/state' + +export type SearchListInfo = Omit<ListInfo, 'source' | 'maxPage'> + + +interface ListInfos extends Partial<Record<LX.OnlineSource, SearchListInfo>> { + 'all': SearchListInfo +} + +export type Source = LX.OnlineSource | 'all' + +export interface InitState { + searchText: string + source: Source + sources: Source[] + listInfos: ListInfos + maxPages: Partial<Record<Source, number>> +} + +const state: InitState = { + searchText: '', + source: 'kw', + sources: [], + listInfos: { + all: { + page: 1, + limit: 15, + total: 0, + list: [], + key: null, + tagId: '', + sortId: '', + }, + }, + maxPages: {}, +} + +export const maxPages: Partial<Record<LX.OnlineSource, number>> = {} +for (const source of music.sources) { + if (!music[source.id as LX.OnlineSource]?.songList?.search) continue + state.sources.push(source.id as LX.OnlineSource) + state.listInfos[source.id as LX.OnlineSource] = { + page: 1, + limit: 18, + total: 0, + list: [], + key: null, + tagId: '', + sortId: '', + } + maxPages[source.id as LX.OnlineSource] = 0 +} +state.sources.push('all') + +export default state diff --git a/src/store/search/state.ts b/src/store/search/state.ts new file mode 100644 index 000000000..f275e0ae8 --- /dev/null +++ b/src/store/search/state.ts @@ -0,0 +1,29 @@ +export type SearchType = 'music' | 'songlist' + +export interface InitState { + temp_source: 'kw' + // temp_source: LX.OnlineSource + searchType: SearchType + searchText: string + tipListInfo: { + text: string + source: 'kw' + list: string[] + } + historyList: string[] +} + +const state: InitState = { + temp_source: 'kw', + searchType: 'music', + searchText: '', + tipListInfo: { + text: '', + source: 'kw', + list: [], + }, + historyList: [], +} + + +export default state diff --git a/src/store/setting/action.ts b/src/store/setting/action.ts new file mode 100644 index 000000000..32f63b6d2 --- /dev/null +++ b/src/store/setting/action.ts @@ -0,0 +1,21 @@ +import { updateSetting as mergeSetting } from '@/config/setting' +import state from './state' + + +export default { + // mergeSetting(newSetting: Partial<LX.AppSetting>) { + // for (const [key, value] of Object.entries(newSetting)) { + // // @ts-expect-error + // state[key] = value + // } + // }, + initSetting(newSetting: LX.AppSetting) { + state.setting = newSetting + }, + updateSetting(newSetting: Partial<LX.AppSetting>) { + const result = mergeSetting(newSetting) + state.setting = result.setting + global.state_event.configUpdated(result.updatedSettingKeys, result.updatedSetting) + }, +} + diff --git a/src/store/setting/hook.ts b/src/store/setting/hook.ts new file mode 100644 index 000000000..db55ec3ef --- /dev/null +++ b/src/store/setting/hook.ts @@ -0,0 +1,35 @@ +import { useEffect, useState } from 'react' +import state from './state' + +export const useSetting = () => { + const [setting, updateSetting] = useState(state.setting) + + useEffect(() => { + const handleUpdate = () => { + updateSetting(state.setting) + } + global.state_event.on('configUpdated', handleUpdate) + return () => { + global.state_event.off('configUpdated', handleUpdate) + } + }, []) + + return setting +} + +export const useSettingValue = <T extends keyof LX.AppSetting>(key: T): LX.AppSetting[T] => { + const [value, update] = useState(state.setting[key]) + + useEffect(() => { + const handleUpdate = (keys: Array<keyof LX.AppSetting>) => { + if (!keys.includes(key)) return + update(state.setting[key]) + } + global.state_event.on('configUpdated', handleUpdate) + return () => { + global.state_event.off('configUpdated', handleUpdate) + } + }, [key]) + + return value +} diff --git a/src/store/setting/state.ts b/src/store/setting/state.ts new file mode 100644 index 000000000..860b83381 --- /dev/null +++ b/src/store/setting/state.ts @@ -0,0 +1,13 @@ +import defaultSetting from '@/config/defaultSetting' + + +interface InitState { + setting: LX.AppSetting +} + +const state: InitState = { + setting: { ...defaultSetting }, +} + + +export default state diff --git a/src/store/songlist/action.ts b/src/store/songlist/action.ts new file mode 100644 index 000000000..8efd9aa68 --- /dev/null +++ b/src/store/songlist/action.ts @@ -0,0 +1,68 @@ +import type { TagInfo, ListDetailInfo, ListInfo, ListInfoItem, Source } from './state' +import state from './state' + +export default { + setTags(tagInfo: TagInfo, source: LX.OnlineSource) { + state.tags[source] = tagInfo + }, + setListInfo(source: Source, tagId: string, sortId: string) { + state.listInfo.source = source + state.listInfo.tagId = tagId + state.listInfo.sortId = sortId + }, + setList(result: ListInfo, tagId: string, sortId: string, page: number) { + state.listInfo.list = page == 1 ? [...result.list] : [...state.listInfo.list, ...result.list] + state.listInfo.total = result.total + state.listInfo.limit = result.limit + state.listInfo.page = page + state.listInfo.source = result.source + state.listInfo.tagId = tagId + state.listInfo.sortId = sortId + state.listInfo.maxPage = Math.ceil(result.total / result.limit) + + return state.listInfo + }, + clearList() { + state.listInfo.list = [] + state.listInfo.total = 0 + state.listInfo.page = 1 + state.listInfo.key = '' + state.listInfo.maxPage = 1 + }, + setListDetailInfo(source: Source, id: string) { + state.listDetailInfo.source = source + state.listDetailInfo.id = id + }, + setListDetail(result: ListDetailInfo, id: string, page: number) { + state.listDetailInfo.list = page == 1 ? [...result.list] : [...state.listDetailInfo.list, ...result.list] + state.listDetailInfo.id = id + state.listDetailInfo.source = result.source + state.listDetailInfo.total = result.total + state.listDetailInfo.limit = result.limit + state.listDetailInfo.page = page + state.listDetailInfo.info = { ...result.info } + state.listInfo.maxPage = Math.ceil(result.total / result.limit) + + return state.listDetailInfo + }, + clearListDetail() { + state.listDetailInfo.list = [] + state.listDetailInfo.id = '' + state.listDetailInfo.source = 'kw' + state.listDetailInfo.total = 0 + state.listDetailInfo.limit = 30 + state.listDetailInfo.page = 1 + state.listDetailInfo.key = null + state.listDetailInfo.info = {} + state.listDetailInfo.maxPage = 1 + }, + setSelectListInfo(info: ListInfoItem) { + state.selectListInfo.author = info.author + state.selectListInfo.desc = info.desc + state.selectListInfo.id = info.id + state.selectListInfo.img = info.img + state.selectListInfo.name = info.name + state.selectListInfo.play_count = info.play_count + state.selectListInfo.source = info.source + }, +} diff --git a/src/store/songlist/state.ts b/src/store/songlist/state.ts new file mode 100644 index 000000000..2206d729d --- /dev/null +++ b/src/store/songlist/state.ts @@ -0,0 +1,137 @@ +import music from '@/utils/musicSdk' + +export declare interface SortInfo { + name: string + tid: 'recommend' | 'hot' | 'new' | 'hot_collect' | 'rise' + id: string +} + +export declare interface TagInfoItem<T extends LX.OnlineSource = LX.OnlineSource> { + parent_id: string + parent_name: string + id: string + name: string + source: T +} +export declare interface TagInfoTypeItem<T extends LX.OnlineSource = LX.OnlineSource> { + name: string + list: Array<TagInfoItem<T>> +} +export declare interface TagInfo<Source extends LX.OnlineSource = LX.OnlineSource> { + tags: Array<TagInfoTypeItem<Source>> + hotTag: Array<TagInfoItem<Source>> + source: Source +} + +type Tags = Partial<Record<LX.OnlineSource, TagInfo>> + +export declare interface ListInfoItem { + play_count?: string + id: string + author: string + name: string + time?: string + img?: string + // grade: basic.favorcnt / 10, + desc?: string + source: LX.OnlineSource + total?: string +} +export declare interface ListInfo { + list: ListInfoItem[] + total: number + page: number + limit: number + maxPage: number + key: string | null + source: LX.OnlineSource + tagId: string + sortId: string +} + +export declare interface ListDetailInfo { + list: LX.Music.MusicInfoOnline[] + source: LX.OnlineSource + desc: string | null + total: number + page: number + limit: number + maxPage: number + key: string | null + id: string + info: { + name?: string + img?: string + desc?: string + author?: string + play_count?: string + } +} + +// export const openSongListInputInfo = markRaw({ +// text: '', +// source: '', +// }) + +export type Source = LX.OnlineSource +export interface InitState { + sources: Source[] + sortList: Partial<Record<Source, SortInfo[]>> + tags: Tags + listInfo: ListInfo + selectListInfo: ListInfoItem + listDetailInfo: ListDetailInfo +} + + +const state: InitState = { + sources: [], + sortList: {}, + tags: {}, + listInfo: { + list: [], + total: 0, + page: 1, + limit: 30, + maxPage: 1, + key: null, + source: 'kw', + tagId: '', + sortId: '', + }, + selectListInfo: { + play_count: '', + id: '', + author: '', + name: '', + time: '', + img: '', + // grade: basic.favorcnt / 10, + desc: '', + source: 'kw', + }, + listDetailInfo: { + list: [], + id: '', + desc: null, + total: 0, + page: 1, + limit: 30, + maxPage: 1, + key: null, + source: 'kw', + info: {}, + }, +} + + +for (const source of music.sources) { + const songList = music[source.id as Source]?.songList + if (!songList) continue + state.sources.push(source.id as Source) + state.sortList[source.id as Source] = songList.sortList as SortInfo[] +} + + +export default state + diff --git a/src/store/store.js b/src/store/store.js deleted file mode 100644 index d3e24a2db..000000000 --- a/src/store/store.js +++ /dev/null @@ -1,48 +0,0 @@ -import { legacy_createStore as createStore, applyMiddleware } from 'redux' -import thunkMiddleware from 'redux-thunk' -import { initSubscriber } from './subscriber' -// import { persistStore, persistReducer } from 'redux-persist' -// import AsyncStorage from '@react-native-async-storage/async-storage' -// import { createSelector } from 'reselect' - -import { combinedReducers } from './reducer' - -// const persistConfig = { -// key: 'root', -// storage: AsyncStorage, -// } - -// const persistedReducer = persistReducer(persistConfig, reducer) - -const middlewares = [thunkMiddleware] - -// let debuggWrapper = data => data - - -// if (process.env.NODE_ENV === 'development') { -// const { createLogger } = require('redux-logger') -// // const { composeWithDevTools } = require('remote-redux-devtools') -// middlewares.push(createLogger({ -// collapsed: true, -// })) -// // debuggWrapper = composeWithDevTools({ realtime: true, port: 8097 }) -// } - - -const initializeStore = () => { - const store = createStore(combinedReducers, applyMiddleware(...middlewares)) - initSubscriber(store) - // const persistor = persistStore(store) - return store - // return { store, persistor } -} - -// const store = createStore(reducer, applyMiddleware(...middlewares)) -// initSubscriber(store) - -let store - -export default () => { - if (!store) store = initializeStore() - return store -} diff --git a/src/store/subscriber.js b/src/store/subscriber.js deleted file mode 100644 index 230756f2e..000000000 --- a/src/store/subscriber.js +++ /dev/null @@ -1,7 +0,0 @@ -import initSubscriber, { subscribe } from 'redux-subscriber' - -export { - initSubscriber, - subscribe, -} - diff --git a/src/store/sync/action.ts b/src/store/sync/action.ts new file mode 100644 index 000000000..cdc2df169 --- /dev/null +++ b/src/store/sync/action.ts @@ -0,0 +1,17 @@ +import state from './state' + + +export default { + setStatus(info: LX.Sync.Status) { + state.status = info.status + state.message = info.message + + global.state_event.syncStatusUpdated({ ...state }) + }, + setMessage(message: LX.Sync.Status['message']) { + state.message = message + + global.state_event.syncStatusUpdated({ ...state }) + }, +} + diff --git a/src/store/sync/hook.ts b/src/store/sync/hook.ts new file mode 100644 index 000000000..5ac7d9e09 --- /dev/null +++ b/src/store/sync/hook.ts @@ -0,0 +1,15 @@ +import { useEffect, useState } from 'react' +import state from './state' + +export const useStatus = () => { + const [value, update] = useState(state) + + useEffect(() => { + global.state_event.on('syncStatusUpdated', update) + return () => { + global.state_event.off('syncStatusUpdated', update) + } + }, []) + + return value +} diff --git a/src/store/sync/state.ts b/src/store/sync/state.ts new file mode 100644 index 000000000..3aef91140 --- /dev/null +++ b/src/store/sync/state.ts @@ -0,0 +1,8 @@ + +const state: LX.Sync.Status = { + status: false, + message: '', +} + + +export default state diff --git a/src/store/theme/action.ts b/src/store/theme/action.ts new file mode 100644 index 000000000..338731785 --- /dev/null +++ b/src/store/theme/action.ts @@ -0,0 +1,16 @@ +import { buildActiveThemeColors } from '@/theme/themes' +import state from './state' + + +export default { + setTheme(theme: LX.Theme) { + state.theme = buildActiveThemeColors(theme) + // ThemeContext.displayName + global.state_event.themeUpdated(state.theme) + }, + setShouldUseDarkColors(shouldUseDarkColors: boolean) { + if (state.shouldUseDarkColors == shouldUseDarkColors) return + state.shouldUseDarkColors = shouldUseDarkColors + }, +} + diff --git a/src/store/theme/hook.ts b/src/store/theme/hook.ts new file mode 100644 index 000000000..a7d5e4887 --- /dev/null +++ b/src/store/theme/hook.ts @@ -0,0 +1,38 @@ +import { useContext } from 'react' +import { ThemeContext } from './state' + +// export const useSetting = () => { +// const [setting, updateSetting] = useState(state.setting) + +// useEffect(() => { +// const handleUpdate = () => { +// updateSetting(state.setting) +// } +// global.state_event.on('configUpdated', handleUpdate) +// return () => { +// global.state_event.off('configUpdated', handleUpdate) +// } +// }, []) + +// return setting +// } + +// export const useSettingValue = <T extends keyof LX.AppSetting>(key: T): LX.AppSetting[T] => { +// const [value, update] = useState(state.setting[key]) + +// useEffect(() => { +// const handleUpdate = (keys: Array<keyof LX.AppSetting>) => { +// if (!keys.includes(key)) return +// update(state.setting[key]) +// } +// global.state_event.on('configUpdated', handleUpdate) +// return () => { +// global.state_event.off('configUpdated', handleUpdate) +// } +// }, [key]) + +// return value +// } + +export const useTheme = () => useContext(ThemeContext) + diff --git a/src/store/theme/state.ts b/src/store/theme/state.ts new file mode 100644 index 000000000..5d10b8e7b --- /dev/null +++ b/src/store/theme/state.ts @@ -0,0 +1,287 @@ +import { createContext } from 'react' +// import type { RootState } from '@/store' + + +interface InitState { + shouldUseDarkColors: boolean + theme: LX.ActiveTheme +} + +const theme = { + id: '', + name: '', + isDark: false, + 'c-primary': 'rgb(77, 175, 124)', + 'c-primary-dark-100': 'rgb(69,158,112)', + 'c-primary-dark-100-alpha-100': 'rgba(69, 158, 112, 0.90)', + 'c-primary-alpha-100': 'rgba(77, 175, 124, 0.90)', + 'c-primary-dark-100-alpha-200': 'rgba(69, 158, 112, 0.80)', + 'c-primary-alpha-200': 'rgba(77, 175, 124, 0.80)', + 'c-primary-dark-100-alpha-300': 'rgba(69, 158, 112, 0.70)', + 'c-primary-alpha-300': 'rgba(77, 175, 124, 0.70)', + 'c-primary-dark-100-alpha-400': 'rgba(69, 158, 112, 0.60)', + 'c-primary-alpha-400': 'rgba(77, 175, 124, 0.60)', + 'c-primary-dark-100-alpha-500': 'rgba(69, 158, 112, 0.50)', + 'c-primary-alpha-500': 'rgba(77, 175, 124, 0.50)', + 'c-primary-dark-100-alpha-600': 'rgba(69, 158, 112, 0.40)', + 'c-primary-alpha-600': 'rgba(77, 175, 124, 0.40)', + 'c-primary-dark-100-alpha-700': 'rgba(69, 158, 112, 0.30)', + 'c-primary-alpha-700': 'rgba(77, 175, 124, 0.30)', + 'c-primary-dark-100-alpha-800': 'rgba(69, 158, 112, 0.20)', + 'c-primary-alpha-800': 'rgba(77, 175, 124, 0.20)', + 'c-primary-dark-100-alpha-900': 'rgba(69, 158, 112, 0.10)', + 'c-primary-alpha-900': 'rgba(77, 175, 124, 0.10)', + 'c-primary-dark-200': 'rgb(62,142,101)', + 'c-primary-dark-200-alpha-100': 'rgba(62, 142, 101, 0.90)', + 'c-primary-dark-200-alpha-200': 'rgba(62, 142, 101, 0.80)', + 'c-primary-dark-200-alpha-300': 'rgba(62, 142, 101, 0.70)', + 'c-primary-dark-200-alpha-400': 'rgba(62, 142, 101, 0.60)', + 'c-primary-dark-200-alpha-500': 'rgba(62, 142, 101, 0.50)', + 'c-primary-dark-200-alpha-600': 'rgba(62, 142, 101, 0.40)', + 'c-primary-dark-200-alpha-700': 'rgba(62, 142, 101, 0.30)', + 'c-primary-dark-200-alpha-800': 'rgba(62, 142, 101, 0.20)', + 'c-primary-dark-200-alpha-900': 'rgba(62, 142, 101, 0.10)', + 'c-primary-dark-300': 'rgb(56,128,91)', + 'c-primary-dark-300-alpha-100': 'rgba(56, 128, 91, 0.90)', + 'c-primary-dark-300-alpha-200': 'rgba(56, 128, 91, 0.80)', + 'c-primary-dark-300-alpha-300': 'rgba(56, 128, 91, 0.70)', + 'c-primary-dark-300-alpha-400': 'rgba(56, 128, 91, 0.60)', + 'c-primary-dark-300-alpha-500': 'rgba(56, 128, 91, 0.50)', + 'c-primary-dark-300-alpha-600': 'rgba(56, 128, 91, 0.40)', + 'c-primary-dark-300-alpha-700': 'rgba(56, 128, 91, 0.30)', + 'c-primary-dark-300-alpha-800': 'rgba(56, 128, 91, 0.20)', + 'c-primary-dark-300-alpha-900': 'rgba(56, 128, 91, 0.10)', + 'c-primary-dark-400': 'rgb(50,115,82)', + 'c-primary-dark-400-alpha-100': 'rgba(50, 115, 82, 0.90)', + 'c-primary-dark-400-alpha-200': 'rgba(50, 115, 82, 0.80)', + 'c-primary-dark-400-alpha-300': 'rgba(50, 115, 82, 0.70)', + 'c-primary-dark-400-alpha-400': 'rgba(50, 115, 82, 0.60)', + 'c-primary-dark-400-alpha-500': 'rgba(50, 115, 82, 0.50)', + 'c-primary-dark-400-alpha-600': 'rgba(50, 115, 82, 0.40)', + 'c-primary-dark-400-alpha-700': 'rgba(50, 115, 82, 0.30)', + 'c-primary-dark-400-alpha-800': 'rgba(50, 115, 82, 0.20)', + 'c-primary-dark-400-alpha-900': 'rgba(50, 115, 82, 0.10)', + 'c-primary-dark-500': 'rgb(45,104,74)', + 'c-primary-dark-500-alpha-100': 'rgba(45, 104, 74, 0.90)', + 'c-primary-dark-500-alpha-200': 'rgba(45, 104, 74, 0.80)', + 'c-primary-dark-500-alpha-300': 'rgba(45, 104, 74, 0.70)', + 'c-primary-dark-500-alpha-400': 'rgba(45, 104, 74, 0.60)', + 'c-primary-dark-500-alpha-500': 'rgba(45, 104, 74, 0.50)', + 'c-primary-dark-500-alpha-600': 'rgba(45, 104, 74, 0.40)', + 'c-primary-dark-500-alpha-700': 'rgba(45, 104, 74, 0.30)', + 'c-primary-dark-500-alpha-800': 'rgba(45, 104, 74, 0.20)', + 'c-primary-dark-500-alpha-900': 'rgba(45, 104, 74, 0.10)', + 'c-primary-dark-600': 'rgb(41,94,67)', + 'c-primary-dark-600-alpha-100': 'rgba(41, 94, 67, 0.90)', + 'c-primary-dark-600-alpha-200': 'rgba(41, 94, 67, 0.80)', + 'c-primary-dark-600-alpha-300': 'rgba(41, 94, 67, 0.70)', + 'c-primary-dark-600-alpha-400': 'rgba(41, 94, 67, 0.60)', + 'c-primary-dark-600-alpha-500': 'rgba(41, 94, 67, 0.50)', + 'c-primary-dark-600-alpha-600': 'rgba(41, 94, 67, 0.40)', + 'c-primary-dark-600-alpha-700': 'rgba(41, 94, 67, 0.30)', + 'c-primary-dark-600-alpha-800': 'rgba(41, 94, 67, 0.20)', + 'c-primary-dark-600-alpha-900': 'rgba(41, 94, 67, 0.10)', + 'c-primary-dark-700': 'rgb(37,85,60)', + 'c-primary-dark-700-alpha-100': 'rgba(37, 85, 60, 0.90)', + 'c-primary-dark-700-alpha-200': 'rgba(37, 85, 60, 0.80)', + 'c-primary-dark-700-alpha-300': 'rgba(37, 85, 60, 0.70)', + 'c-primary-dark-700-alpha-400': 'rgba(37, 85, 60, 0.60)', + 'c-primary-dark-700-alpha-500': 'rgba(37, 85, 60, 0.50)', + 'c-primary-dark-700-alpha-600': 'rgba(37, 85, 60, 0.40)', + 'c-primary-dark-700-alpha-700': 'rgba(37, 85, 60, 0.30)', + 'c-primary-dark-700-alpha-800': 'rgba(37, 85, 60, 0.20)', + 'c-primary-dark-700-alpha-900': 'rgba(37, 85, 60, 0.10)', + 'c-primary-dark-800': 'rgb(33,77,54)', + 'c-primary-dark-800-alpha-100': 'rgba(33, 77, 54, 0.90)', + 'c-primary-dark-800-alpha-200': 'rgba(33, 77, 54, 0.80)', + 'c-primary-dark-800-alpha-300': 'rgba(33, 77, 54, 0.70)', + 'c-primary-dark-800-alpha-400': 'rgba(33, 77, 54, 0.60)', + 'c-primary-dark-800-alpha-500': 'rgba(33, 77, 54, 0.50)', + 'c-primary-dark-800-alpha-600': 'rgba(33, 77, 54, 0.40)', + 'c-primary-dark-800-alpha-700': 'rgba(33, 77, 54, 0.30)', + 'c-primary-dark-800-alpha-800': 'rgba(33, 77, 54, 0.20)', + 'c-primary-dark-800-alpha-900': 'rgba(33, 77, 54, 0.10)', + 'c-primary-dark-900': 'rgb(30,69,49)', + 'c-primary-dark-900-alpha-100': 'rgba(30, 69, 49, 0.90)', + 'c-primary-dark-900-alpha-200': 'rgba(30, 69, 49, 0.80)', + 'c-primary-dark-900-alpha-300': 'rgba(30, 69, 49, 0.70)', + 'c-primary-dark-900-alpha-400': 'rgba(30, 69, 49, 0.60)', + 'c-primary-dark-900-alpha-500': 'rgba(30, 69, 49, 0.50)', + 'c-primary-dark-900-alpha-600': 'rgba(30, 69, 49, 0.40)', + 'c-primary-dark-900-alpha-700': 'rgba(30, 69, 49, 0.30)', + 'c-primary-dark-900-alpha-800': 'rgba(30, 69, 49, 0.20)', + 'c-primary-dark-900-alpha-900': 'rgba(30, 69, 49, 0.10)', + 'c-primary-dark-1000': 'rgb(27,62,44)', + 'c-primary-dark-1000-alpha-100': 'rgba(27, 62, 44, 0.90)', + 'c-primary-dark-1000-alpha-200': 'rgba(27, 62, 44, 0.80)', + 'c-primary-dark-1000-alpha-300': 'rgba(27, 62, 44, 0.70)', + 'c-primary-dark-1000-alpha-400': 'rgba(27, 62, 44, 0.60)', + 'c-primary-dark-1000-alpha-500': 'rgba(27, 62, 44, 0.50)', + 'c-primary-dark-1000-alpha-600': 'rgba(27, 62, 44, 0.40)', + 'c-primary-dark-1000-alpha-700': 'rgba(27, 62, 44, 0.30)', + 'c-primary-dark-1000-alpha-800': 'rgba(27, 62, 44, 0.20)', + 'c-primary-dark-1000-alpha-900': 'rgba(27, 62, 44, 0.10)', + 'c-primary-light-100': 'rgb(113,191,150)', + 'c-primary-light-100-alpha-100': 'rgba(113, 191, 150, 0.90)', + 'c-primary-light-100-alpha-200': 'rgba(113, 191, 150, 0.80)', + 'c-primary-light-100-alpha-300': 'rgba(113, 191, 150, 0.70)', + 'c-primary-light-100-alpha-400': 'rgba(113, 191, 150, 0.60)', + 'c-primary-light-100-alpha-500': 'rgba(113, 191, 150, 0.50)', + 'c-primary-light-100-alpha-600': 'rgba(113, 191, 150, 0.40)', + 'c-primary-light-100-alpha-700': 'rgba(113, 191, 150, 0.30)', + 'c-primary-light-100-alpha-800': 'rgba(113, 191, 150, 0.20)', + 'c-primary-light-100-alpha-900': 'rgba(113, 191, 150, 0.10)', + 'c-primary-light-200': 'rgb(141,204,171)', + 'c-primary-light-200-alpha-100': 'rgba(141, 204, 171, 0.90)', + 'c-primary-light-200-alpha-200': 'rgba(141, 204, 171, 0.80)', + 'c-primary-light-200-alpha-300': 'rgba(141, 204, 171, 0.70)', + 'c-primary-light-200-alpha-400': 'rgba(141, 204, 171, 0.60)', + 'c-primary-light-200-alpha-500': 'rgba(141, 204, 171, 0.50)', + 'c-primary-light-200-alpha-600': 'rgba(141, 204, 171, 0.40)', + 'c-primary-light-200-alpha-700': 'rgba(141, 204, 171, 0.30)', + 'c-primary-light-200-alpha-800': 'rgba(141, 204, 171, 0.20)', + 'c-primary-light-200-alpha-900': 'rgba(141, 204, 171, 0.10)', + 'c-primary-light-300': 'rgb(164,214,188)', + 'c-primary-light-300-alpha-100': 'rgba(164, 214, 188, 0.90)', + 'c-primary-light-300-alpha-200': 'rgba(164, 214, 188, 0.80)', + 'c-primary-light-300-alpha-300': 'rgba(164, 214, 188, 0.70)', + 'c-primary-light-300-alpha-400': 'rgba(164, 214, 188, 0.60)', + 'c-primary-light-300-alpha-500': 'rgba(164, 214, 188, 0.50)', + 'c-primary-light-300-alpha-600': 'rgba(164, 214, 188, 0.40)', + 'c-primary-light-300-alpha-700': 'rgba(164, 214, 188, 0.30)', + 'c-primary-light-300-alpha-800': 'rgba(164, 214, 188, 0.20)', + 'c-primary-light-300-alpha-900': 'rgba(164, 214, 188, 0.10)', + 'c-primary-light-400': 'rgb(182,222,201)', + 'c-primary-light-400-alpha-100': 'rgba(182, 222, 201, 0.90)', + 'c-primary-light-400-alpha-200': 'rgba(182, 222, 201, 0.80)', + 'c-primary-light-400-alpha-300': 'rgba(182, 222, 201, 0.70)', + 'c-primary-light-400-alpha-400': 'rgba(182, 222, 201, 0.60)', + 'c-primary-light-400-alpha-500': 'rgba(182, 222, 201, 0.50)', + 'c-primary-light-400-alpha-600': 'rgba(182, 222, 201, 0.40)', + 'c-primary-light-400-alpha-700': 'rgba(182, 222, 201, 0.30)', + 'c-primary-light-400-alpha-800': 'rgba(182, 222, 201, 0.20)', + 'c-primary-light-400-alpha-900': 'rgba(182, 222, 201, 0.10)', + 'c-primary-light-500': 'rgb(197,229,212)', + 'c-primary-light-500-alpha-100': 'rgba(197, 229, 212, 0.90)', + 'c-primary-light-500-alpha-200': 'rgba(197, 229, 212, 0.80)', + 'c-primary-light-500-alpha-300': 'rgba(197, 229, 212, 0.70)', + 'c-primary-light-500-alpha-400': 'rgba(197, 229, 212, 0.60)', + 'c-primary-light-500-alpha-500': 'rgba(197, 229, 212, 0.50)', + 'c-primary-light-500-alpha-600': 'rgba(197, 229, 212, 0.40)', + 'c-primary-light-500-alpha-700': 'rgba(197, 229, 212, 0.30)', + 'c-primary-light-500-alpha-800': 'rgba(197, 229, 212, 0.20)', + 'c-primary-light-500-alpha-900': 'rgba(197, 229, 212, 0.10)', + 'c-primary-light-600': 'rgb(209,234,221)', + 'c-primary-light-600-alpha-100': 'rgba(209, 234, 221, 0.90)', + 'c-primary-light-600-alpha-200': 'rgba(209, 234, 221, 0.80)', + 'c-primary-light-600-alpha-300': 'rgba(209, 234, 221, 0.70)', + 'c-primary-light-600-alpha-400': 'rgba(209, 234, 221, 0.60)', + 'c-primary-light-600-alpha-500': 'rgba(209, 234, 221, 0.50)', + 'c-primary-light-600-alpha-600': 'rgba(209, 234, 221, 0.40)', + 'c-primary-light-600-alpha-700': 'rgba(209, 234, 221, 0.30)', + 'c-primary-light-600-alpha-800': 'rgba(209, 234, 221, 0.20)', + 'c-primary-light-600-alpha-900': 'rgba(209, 234, 221, 0.10)', + 'c-primary-light-700': 'rgb(218,238,228)', + 'c-primary-light-700-alpha-100': 'rgba(218, 238, 228, 0.90)', + 'c-primary-light-700-alpha-200': 'rgba(218, 238, 228, 0.80)', + 'c-primary-light-700-alpha-300': 'rgba(218, 238, 228, 0.70)', + 'c-primary-light-700-alpha-400': 'rgba(218, 238, 228, 0.60)', + 'c-primary-light-700-alpha-500': 'rgba(218, 238, 228, 0.50)', + 'c-primary-light-700-alpha-600': 'rgba(218, 238, 228, 0.40)', + 'c-primary-light-700-alpha-700': 'rgba(218, 238, 228, 0.30)', + 'c-primary-light-700-alpha-800': 'rgba(218, 238, 228, 0.20)', + 'c-primary-light-700-alpha-900': 'rgba(218, 238, 228, 0.10)', + 'c-primary-light-800': 'rgb(225,241,233)', + 'c-primary-light-800-alpha-100': 'rgba(225, 241, 233, 0.90)', + 'c-primary-light-800-alpha-200': 'rgba(225, 241, 233, 0.80)', + 'c-primary-light-800-alpha-300': 'rgba(225, 241, 233, 0.70)', + 'c-primary-light-800-alpha-400': 'rgba(225, 241, 233, 0.60)', + 'c-primary-light-800-alpha-500': 'rgba(225, 241, 233, 0.50)', + 'c-primary-light-800-alpha-600': 'rgba(225, 241, 233, 0.40)', + 'c-primary-light-800-alpha-700': 'rgba(225, 241, 233, 0.30)', + 'c-primary-light-800-alpha-800': 'rgba(225, 241, 233, 0.20)', + 'c-primary-light-800-alpha-900': 'rgba(225, 241, 233, 0.10)', + 'c-primary-light-900': 'rgb(231,244,237)', + 'c-primary-light-900-alpha-100': 'rgba(231, 244, 237, 0.90)', + 'c-primary-light-900-alpha-200': 'rgba(231, 244, 237, 0.80)', + 'c-primary-light-900-alpha-300': 'rgba(231, 244, 237, 0.70)', + 'c-primary-light-900-alpha-400': 'rgba(231, 244, 237, 0.60)', + 'c-primary-light-900-alpha-500': 'rgba(231, 244, 237, 0.50)', + 'c-primary-light-900-alpha-600': 'rgba(231, 244, 237, 0.40)', + 'c-primary-light-900-alpha-700': 'rgba(231, 244, 237, 0.30)', + 'c-primary-light-900-alpha-800': 'rgba(231, 244, 237, 0.20)', + 'c-primary-light-900-alpha-900': 'rgba(231, 244, 237, 0.10)', + 'c-primary-light-1000': 'rgb(255,255,255)', + 'c-primary-light-1000-alpha-100': 'rgba(255, 255, 255, 0.90)', + 'c-primary-light-1000-alpha-200': 'rgba(255, 255, 255, 0.80)', + 'c-primary-light-1000-alpha-300': 'rgba(255, 255, 255, 0.70)', + 'c-primary-light-1000-alpha-400': 'rgba(255, 255, 255, 0.60)', + 'c-primary-light-1000-alpha-500': 'rgba(255, 255, 255, 0.50)', + 'c-primary-light-1000-alpha-600': 'rgba(255, 255, 255, 0.40)', + 'c-primary-light-1000-alpha-700': 'rgba(255, 255, 255, 0.30)', + 'c-primary-light-1000-alpha-800': 'rgba(255, 255, 255, 0.20)', + 'c-primary-light-1000-alpha-900': 'rgba(255, 255, 255, 0.10)', + 'c-theme': 'rgb(77, 175, 124)', + + + 'c-000': 'rgb(255,255,255)', + 'c-050': 'rgb(244,244,244)', + 'c-100': 'rgb(233,233,233)', + 'c-150': 'rgb(222,222,222)', + 'c-200': 'rgb(211,211,211)', + 'c-250': 'rgb(200,200,200)', + 'c-300': 'rgb(188,188,188)', + 'c-350': 'rgb(177,177,177)', + 'c-400': 'rgb(166,166,166)', + 'c-450': 'rgb(155,155,155)', + 'c-500': 'rgb(144,144,144)', + 'c-550': 'rgb(133,133,133)', + 'c-600': 'rgb(122,122,122)', + 'c-650': 'rgb(111,111,111)', + 'c-700': 'rgb(100,100,100)', + 'c-750': 'rgb(89,89,89)', + 'c-800': 'rgb(77,77,77)', + 'c-850': 'rgb(66,66,66)', + 'c-900': 'rgb(55,55,55)', + 'c-950': 'rgb(44,44,44)', + 'c-1000': 'rgb(33, 33, 33)', +} + +const state: InitState = { + shouldUseDarkColors: false, + theme: { + ...theme, + 'c-app-background': theme['c-primary-light-600-alpha-600'], + 'c-main-background': 'rgba(255, 255, 255, 0.9)', + + 'c-badge-primary': theme['c-primary'], + 'c-badge-secondary': '#4baed5', + 'c-badge-tertiary': '#e7aa36', + + 'c-font': theme['c-850'], + 'c-font-label': theme['c-450'], + 'c-primary-font': theme['c-primary'], + 'c-primary-font-hover': theme['c-primary-alpha-300'], + 'c-primary-font-active': theme['c-primary-dark-100-alpha-200'], + 'c-primary-background': theme['c-primary-light-400-alpha-700'], + 'c-primary-background-hover': theme['c-primary-light-300-alpha-800'], + 'c-primary-background-active': theme['c-primary-light-100-alpha-800'], + 'c-primary-input-background': theme['c-primary-light-400-alpha-700'], + 'c-button-font': theme['c-primary-alpha-100'], + 'c-button-font-selected': theme['c-primary-dark-100-alpha-100'], + 'c-button-background': theme['c-primary-light-400-alpha-700'], + 'c-button-background-selected': theme['c-primary-alpha-600'], + 'c-button-background-hover': theme['c-primary-light-300-alpha-600'], + 'c-button-background-active': theme['c-primary-light-100-alpha-600'], + 'c-list-header-border-bottom': theme['c-primary-alpha-900'], + 'c-content-background': theme['c-primary-light-1000'], + 'c-border-background': theme['c-primary-light-100-alpha-700'], + + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + }, +} + +export const ThemeContext = createContext(state.theme) + +export default state diff --git a/src/store/useDispatch.js b/src/store/useDispatch.js deleted file mode 100644 index 31e14df77..000000000 --- a/src/store/useDispatch.js +++ /dev/null @@ -1,24 +0,0 @@ -import { useCallback } from 'react' -import { useDispatch } from 'react-redux' -import * as modules from './modules' - -const defaultAction = () => {} -export default (moduleName, name) => { - const dispatch = useDispatch() - - // console.log(selector) - // console.log(moduleName, key) - - return useCallback((...params) => { - const actions = modules[moduleName].action - let action - if (actions && actions[name]) action = actions[name] - else { - console.warn('action not found:', moduleName, name) - action = defaultAction - } - return dispatch(action(...params)) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) -} - diff --git a/src/store/version/action.ts b/src/store/version/action.ts new file mode 100644 index 000000000..ffd99a781 --- /dev/null +++ b/src/store/version/action.ts @@ -0,0 +1,26 @@ +import state, { type InitState } from './state' + + +export default { + setVersionInfo(info: Partial<InitState['versionInfo']>) { + Object.assign(state.versionInfo, info) + global.state_event.versionInfoUpdated({ ...state.versionInfo }) + }, + setIgnoreVersion(version: InitState['ignoreVersion']) { + state.ignoreVersion = version + global.state_event.versionInfoIgnoreVersionUpdated(version) + }, + setProgress(info: InitState['progress']) { + if (state.progress.total != info.total) { + state.progress.total = info.total + } + state.progress.current = info.current + + global.state_event.versionDownloadProgressUpdated({ ...state.progress }) + }, + setVisibleModal(visible: boolean) { + if (state.showModal == visible) return + state.showModal = visible + }, +} + diff --git a/src/store/version/hook.ts b/src/store/version/hook.ts new file mode 100644 index 000000000..ac8d2763f --- /dev/null +++ b/src/store/version/hook.ts @@ -0,0 +1,80 @@ +import { useEffect, useState } from 'react' +import state from './state' + +export const useVersionInfo = () => { + const [info, setInfo] = useState(state.versionInfo) + + useEffect(() => { + global.state_event.on('versionInfoUpdated', setInfo) + return () => { + global.state_event.off('versionInfoUpdated', setInfo) + } + }, []) + + return info +} + +export const useVersionDownloadProgressUpdated = () => { + const [status, setStatus] = useState(state.progress) + + useEffect(() => { + global.state_event.on('versionDownloadProgressUpdated', setStatus) + return () => { + global.state_event.off('versionDownloadProgressUpdated', setStatus) + } + }, []) + + return status +} + +export const useVersionInfoIgnoreVersionUpdated = () => { + const [version, setVersion] = useState(state.ignoreVersion) + + useEffect(() => { + global.state_event.on('versionInfoIgnoreVersionUpdated', setVersion) + return () => { + global.state_event.off('versionInfoIgnoreVersionUpdated', setVersion) + } + }, []) + + return version +} + +// export const useActiveListId = () => { +// const [id, setId] = useState(state.activeListId) + +// useEffect(() => { +// global.state_event.on('mylistToggled', setId) +// return () => { +// global.state_event.off('mylistToggled', setId) +// } +// }, []) + +// return id +// } + + +// export const useMusicList = () => { +// const [list, setList] = useState<LX.List.ListMusics>([]) + +// useEffect(() => { +// const handleToggle = (activeListId: string) => { +// void getListMusics(activeListId).then(setList) +// } +// const handleChange = (ids: string[]) => { +// if (!ids.includes(state.activeListId)) return +// void getListMusics(state.activeListId).then(setList) +// } +// global.state_event.on('mylistToggled', handleToggle) +// global.app_event.on('myListMusicUpdate', handleChange) + +// handleToggle(state.activeListId) + +// return () => { +// global.state_event.off('mylistToggled', handleToggle) +// global.app_event.off('myListMusicUpdate', handleChange) +// } +// }, []) + +// return list +// } diff --git a/src/store/version/state.ts b/src/store/version/state.ts new file mode 100644 index 000000000..d4821886d --- /dev/null +++ b/src/store/version/state.ts @@ -0,0 +1,48 @@ +import { version } from '../../../package.json' + +export interface ProgressInfo { + total: number + current: number +} + +export interface VersionInfo { + version: string + desc: string + history?: LX.VersionInfo[] +} + +export interface InitState { + showModal: boolean + versionInfo: { + version: string + newVersion: VersionInfo | null + showModal: boolean + isUnknown: boolean + isLatest: boolean + reCheck: boolean + status: LX.UpdateStatus + } + ignoreVersion: string | null + progress: ProgressInfo +} + +const state: InitState = { + showModal: false, + versionInfo: { + version, + newVersion: null, + showModal: false, + reCheck: false, + isUnknown: false, + isLatest: false, + status: 'checking', + }, + ignoreVersion: null, + progress: { + total: 0, + current: 0, + }, +} + + +export default state diff --git a/src/theme/themes/black.js b/src/theme/themes/black.js deleted file mode 100644 index bb2b69fff..000000000 --- a/src/theme/themes/black.js +++ /dev/null @@ -1,40 +0,0 @@ -export default { - id: 'black', - isDark: true, - colors: { - primary: '#050505', - - normal: '#a3a3a3', - normal10: '#999', - normal20: '#8f8f8f', - normal30: '#858585', - normal35: '#7a7a7a', - normal40: '#707070', - normal50: '#666', - normal60: '#5c5c5c', - normal70: '#525252', - normal75: '#4c4c4c', - - secondary_5: '#666', - secondary: '#999', - secondary10: '#474747', - secondary20: '#383838', - secondary30: '#2e2e2e', - secondary40: '#292929', - secondary45: '#1f1f1f', - - tertiary_5: '#9b7e83', - tertiary: '#a68c91', - tertiary10: '#b19b9f', - tertiary20: '#bca9ac', - tertiary30: '#c7b7ba', - tertiary40: '#d2c6c8', - tertiary45: '#ddd4d6', - - borderColor: '#0f0f0f', - borderColor2: '#1b1b1b', - borderColor3: '#292929', - borderColor4: '#363636', - borderColor5: '#424242', - }, -} diff --git a/src/theme/themes/blue.js b/src/theme/themes/blue.js deleted file mode 100644 index 4b874f7ea..000000000 --- a/src/theme/themes/blue.js +++ /dev/null @@ -1,40 +0,0 @@ -export default { - id: 'blue', - isDark: false, - colors: { - primary: '#fff', - - normal: '#333', - normal10: '#4c4c4c', - normal20: '#666', - normal30: '#808080', - normal35: '#8c8c8c', - normal40: '#999', - normal50: '#b2b2b2', - normal60: '#ccc', - normal70: '#e6e6e6', - normal75: '#f2f2f2', - - secondary_5: '#258bd0', - secondary: '#3498db', - secondary10: '#5eaee3', - secondary20: '#89c4eb', - secondary30: '#b5daf2', - secondary40: '#d2ebf9', - secondary45: '#e8f5fc', - - tertiary_5: '#41a581', - tertiary: '#48b78f', - tertiary10: '#5cbf9b', - tertiary20: '#6dc5a5', - tertiary30: '#7fccb0', - tertiary40: '#92d3bb', - tertiary45: '#a4dac6', - - borderColor: '#e6e6e6', - borderColor2: '#ebebeb', - borderColor3: '#f0f0f0', - borderColor4: '#f5f5f5', - borderColor5: '#fafafa', - }, -} diff --git a/src/theme/themes/colorUtils.js b/src/theme/themes/colorUtils.js new file mode 100644 index 000000000..cff9fa790 --- /dev/null +++ b/src/theme/themes/colorUtils.js @@ -0,0 +1,73 @@ +/* eslint-disable */ +// https://github.com/PimpTrizkit/PJs/wiki/12.-Shade,-Blend-and-Convert-a-Web-Color-(pSBC.js)#micro-functions-version-4 + +/** + * Blend color (Lighten or Darken) + * @param {number} p 混合百分比 范围 0.0 - 1.0 + * @param {string} c0 rgb(a) color1 + * @param {string} c1 rgb(a) color2 + * @returns color + */ +exports.RGB_Linear_Blend=(p,c0,c1)=>{ + var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,j=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")"; + return"rgb"+(x?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+i(e[3]=="a"?e.slice(5):e.slice(4))*p)+","+r(i(b)*P+i(f)*p)+","+r(i(c)*P+i(g)*p)+j; +} + +/** + * Blend color (Lighten or Darken) + * @param {number} p 混合百分比 范围 0.0 - 1.0 + * @param {string} c0 rgb(a) color1 + * @param {string} c1 rgb(a) color2 + * @returns color + */ +exports.RGB_Log_Blend=(p,c0,c1)=>{ + var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,j=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")"; + return"rgb"+(x?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+p*i(e[3]=="a"?e.slice(5):e.slice(4))**2)**0.5)+","+r((P*i(b)**2+p*i(f)**2)**0.5)+","+r((P*i(c)**2+p*i(g)**2)**0.5)+j; +} + + +/** + * Shade color (Lighten or Darken) + * @param {number} p Shade 百分比范围为 -1.0 - 1.0 负为黑色,正为白色 + * @param {string} c0 rgb(a) color + * @returns color + */ +exports.RGB_Linear_Shade=(p,c0)=>{ + var i=parseInt,r=Math.round,[a,b,c,d]=c0.split(","),n=p<0,t=n?0:255*p,P=n?1+p:1-p; + return"rgb"+(d?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+t)+","+r(i(b)*P+t)+","+r(i(c)*P+t)+(d?","+d:")"); +} + + +/** + * Shade color (Lighten or Darken) + * @param {number} p Shade 百分比范围为 -1.0 - 1.0 负为黑色,正为白色 + * @param {string} c0 rgb(a) color + * @returns color + */ +exports.RGB_Log_Shade=(p,c0)=>{ + var i=parseInt,r=Math.round,[a,b,c,d]=c0.split(","),n=p<0,t=n?0:p*255**2,P=n?1+p:1-p; + return"rgb"+(d?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+t)**0.5)+","+r((P*i(b)**2+t)**0.5)+","+r((P*i(c)**2+t)**0.5)+(d?","+d:")"); +} + + +/** + * 修改透明度 + * @param {number} p 透明度 -1.0 - 1.0 + * @param {string} color + * @returns color + */ +exports.RGB_Alpha_Shade = (p, color) => { + var i = parseInt + var n = p < 0 + var [r, g, b, a] = color.split(",") + r = r[3] == 'a' ? r.slice(5) : r.slice(4) + if (a) { + a = parseFloat(a) + a = a - (n ? (1 - a) * p : a * p) + a = n ? Math.max(0, a) : Math.min(1, a) + } else { + a = 1 - p + a = Math.min(1, a) + } + return `rgba(${i(r)}, ${i(g)}, ${i(b)}, ${a.toFixed(2)})` +} diff --git a/src/theme/themes/createThemes.js b/src/theme/themes/createThemes.js new file mode 100644 index 000000000..41f2990fb --- /dev/null +++ b/src/theme/themes/createThemes.js @@ -0,0 +1,294 @@ +//! 更新默认主题配置后,需要执行 npm run build:theme 重新构建index.json + +const fs = require('fs') +const path = require('path') +const { createThemeColors } = require('./utils') + +const defaultThemes = [ + { + id: 'green', + name: '绿意盎然', + isDark: false, + config: { + primary: 'rgb(77, 175, 124)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'var(c-primary-light-600-alpha-700)', + 'c-main-background': 'rgba(255, 255, 255, 1)', + 'bg-image': '', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': '#4baed5', + 'c-badge-tertiary': '#e7aa36', + }, + }, + { + id: 'blue', + name: '蓝田生玉', + isDark: false, + config: { + primary: 'rgb(52, 152, 219)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'var(c-primary-light-600-alpha-700)', + 'c-main-background': 'rgba(255, 255, 255, 1)', + 'bg-image': '', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': '#5cbf9b', + 'c-badge-tertiary': '#5cbf9b', + }, + }, + { + id: 'blue_plus', + name: '蛋雅深蓝', + isDark: false, + config: { + primary: 'rgb(77, 131, 175)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'var(c-primary-light-600-alpha-600)', + 'c-main-background': 'rgba(255, 255, 255, 1)', + 'bg-image': '', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': 'rgba(66.6, 150.7, 171, 1)', + 'c-badge-tertiary': 'rgba(54, 196, 231, 1)', + }, + }, + { + id: 'orange', + name: '橙黄橘绿', + isDark: false, + config: { + primary: 'rgb(245, 171, 53)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'var(c-primary-light-600-alpha-700)', + 'c-main-background': 'rgba(255, 255, 255, 1)', + 'bg-image': '', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': '#9ed458', + 'c-badge-tertiary': '#9ed458', + }, + }, + { + id: 'red', + name: '热情似火', + isDark: false, + config: { + primary: 'rgb(214, 69, 65)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'var(c-primary-light-600-alpha-700)', + 'c-main-background': 'rgba(255, 255, 255, 1)', + 'bg-image': '', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': '#dfbb6b', + 'c-badge-tertiary': '#dfbb6b', + }, + }, + { + id: 'pink', + name: '粉装玉琢', + isDark: false, + config: { + primary: 'rgb(241, 130, 141)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'var(c-primary-light-600-alpha-700)', + 'c-main-background': 'rgba(255, 255, 255, 1)', + 'bg-image': '', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': '#f5b684', + 'c-badge-tertiary': '#f5b684', + }, + }, + { + id: 'purple', + name: '重斤球紫', + isDark: false, + config: { + primary: 'rgb(155, 89, 182)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'var(c-primary-light-600-alpha-700)', + 'c-main-background': 'rgba(255, 255, 255, 1)', + 'bg-image': '', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': '#e5a39f', + 'c-badge-tertiary': '#e5a39f', + }, + }, + { + id: 'grey', + name: '灰常美丽', + isDark: false, + config: { + primary: 'rgb(108, 122, 137)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'var(c-primary-light-600-alpha-700)', + 'c-main-background': 'rgba(255, 255, 255, 1)', + 'bg-image': '', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': '#b19b9f', + 'c-badge-tertiary': '#b19b9f', + }, + }, + { + id: 'ming', + name: '青出于黑', + isDark: false, + config: { + primary: 'rgb(51, 110, 123)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'var(c-primary-light-600-alpha-700)', + 'c-main-background': 'rgba(255, 255, 255, 1)', + 'bg-image': '', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': '#6376a2', + 'c-badge-tertiary': '#6376a2', + }, + }, + { + id: 'blue2', + name: '清热板蓝', + isDark: false, + config: { + primary: 'rgb(79, 98, 208)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'var(c-primary-light-600-alpha-700)', + 'c-main-background': 'rgba(255, 255, 255, 1)', + 'bg-image': '', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': '#b080db', + 'c-badge-tertiary': '#b080db', + }, + }, + { + id: 'black', + name: '黑灯瞎火', + isDark: true, + config: { + primary: 'rgb(150, 150, 150)', + font: 'rgb(229, 229, 229)', + 'c-app-background': 'rgba(0, 0, 0, 0)', + 'c-main-background': 'rgba(19, 19, 19, 0.95)', + 'bg-image': 'landingMoon.png', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary-dark-200)', + 'c-badge-secondary': 'var(c-primary)', + 'c-badge-tertiary': 'var(c-primary-dark-300)', + }, + }, + { + id: 'mid_autumn', + name: '月里嫦娥', + isDark: false, + config: { + primary: 'rgb(74, 55, 82)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'rgba(255, 255, 255, 0)', + 'c-main-background': 'rgba(255, 255, 255, 0.9)', + 'bg-image': 'jqbg.jpg', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': '#af9479', + 'c-badge-tertiary': '#af9479', + }, + }, + { + id: 'naruto', + name: '木叶之村', + isDark: false, + config: { + primary: 'rgb(87, 144, 167)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'rgba(255, 255, 255, 0.15)', + 'c-main-background': 'rgba(255, 255, 255, 0.8)', + 'bg-image': 'myzcbg.jpg', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': 'var(c-primary)', + 'c-badge-secondary': 'var(c-primary-light-100)', + 'c-badge-tertiary': 'var(c-primary-light-100)', + }, + }, + { + id: 'china_ink', + name: '近墨者黑', + isDark: false, + config: { + primary: 'rgba(47, 47, 47, 1)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'rgba(255, 255, 255, 0)', + 'c-main-background': 'rgba(255, 255, 255, 0.8)', + 'bg-image': 'china_ink.jpg', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + + 'c-badge-primary': 'rgba(137, 70, 70, 1)', + 'c-badge-secondary': 'rgba(67, 139, 65, 1)', + 'c-badge-tertiary': 'rgba(132, 135, 65, 1)', + }, + }, + { + id: 'happy_new_year', + name: '新年快乐', + isDark: false, + config: { + primary: 'rgb(192, 57, 43)', + font: 'rgb(33, 33, 33)', + 'c-app-background': 'rgba(255, 255, 255, 0.15)', + 'c-main-background': 'rgba(255, 255, 255, 0.8)', + 'bg-image': 'xnkl.png', + 'bg-image-position': 'center', + 'bg-image-size': 'cover', + + 'c-badge-primary': '#7fb575', + 'c-badge-secondary': '#dfbb6b', + 'c-badge-tertiary': 'var(c-primary-light-100)', + }, + }, +] + +const themes = defaultThemes.map(({ config: { primary, font, ...extInfo }, ...themeInfo }) => { + return { + ...themeInfo, + isCustom: false, + config: { + themeColors: createThemeColors(primary, font, themeInfo.isDark), + extInfo, + }, + } +}) + +fs.writeFileSync(path.join(__dirname, 'themes.ts'), `/* eslint-disable */\n//! 此文件由 createThemes.js 生成\n\nexport default ${JSON.stringify(themes, null, 2)} as const`) + diff --git a/src/theme/themes/green.js b/src/theme/themes/green.js deleted file mode 100644 index 7c471b069..000000000 --- a/src/theme/themes/green.js +++ /dev/null @@ -1,40 +0,0 @@ -export default { - id: 'green', - isDark: false, - colors: { - primary: '#fff', - - normal: '#333', - normal10: '#4c4c4c', - normal20: '#666', - normal30: '#808080', - normal35: '#8c8c8c', - normal40: '#999', - normal50: '#b2b2b2', - normal60: '#ccc', - normal70: '#e6e6e6', - normal75: '#f2f2f2', - - secondary_5: '#46a071', - secondary: '#4eb17d', - secondary10: '#73bf97', - secondary20: '#95d0b2', - secondary30: '#b9dfcb', - secondary40: '#dcefe5', - secondary45: '#edf7f2', - - tertiary_5: '#5497b5', - tertiary: '#66a2bd', - tertiary10: '#77adc5', - tertiary20: '#89b8cd', - tertiary30: '#9ac3d5', - tertiary40: '#accedd', - tertiary45: '#bed9e4', - - borderColor: '#e6e6e6', - borderColor2: '#ebebeb', - borderColor3: '#f0f0f0', - borderColor4: '#f5f5f5', - borderColor5: '#fafafa', - }, -} diff --git a/src/theme/themes/grey.js b/src/theme/themes/grey.js deleted file mode 100644 index b5d2f672a..000000000 --- a/src/theme/themes/grey.js +++ /dev/null @@ -1,40 +0,0 @@ -export default { - id: 'grey', - isDark: false, - colors: { - primary: '#fff', - - normal: '#4c4c4c', - normal10: '#666', - normal20: '#808080', - normal30: '#8c8c8c', - normal35: '#969696', - normal40: '#a1a1a1', - normal50: '#b5b5b5', - normal60: '#c9c9c9', - normal70: '#e0e0e0', - normal75: '#f2f2f2', - - secondary_5: '#5a6672', - secondary: '#6c7a89', - secondary10: '#8892a0', - secondary20: '#a4acb7', - secondary30: '#c0c6cd', - secondary40: '#dde0e4', - secondary45: '#cfd3d9', - - tertiary_5: '#9b7e83', - tertiary: '#a68c91', - tertiary10: '#b19b9f', - tertiary20: '#bca9ac', - tertiary30: '#c7b7ba', - tertiary40: '#d2c6c8', - tertiary45: '#ddd4d6', - - borderColor: '#e6e6e6', - borderColor2: '#ebebeb', - borderColor3: '#f0f0f0', - borderColor4: '#f5f5f5', - borderColor5: '#fafafa', - }, -} diff --git a/src/theme/themes/images/china_ink.jpg b/src/theme/themes/images/china_ink.jpg new file mode 100644 index 000000000..68fd5130f Binary files /dev/null and b/src/theme/themes/images/china_ink.jpg differ diff --git a/src/theme/themes/images/jqbg.jpg b/src/theme/themes/images/jqbg.jpg new file mode 100644 index 000000000..c8fe56f8f Binary files /dev/null and b/src/theme/themes/images/jqbg.jpg differ diff --git a/src/theme/themes/images/landingMoon2.png b/src/theme/themes/images/landingMoon2.png new file mode 100644 index 000000000..51ad53c58 Binary files /dev/null and b/src/theme/themes/images/landingMoon2.png differ diff --git a/src/theme/themes/images/myzcbg.jpg b/src/theme/themes/images/myzcbg.jpg new file mode 100644 index 000000000..13c5116d5 Binary files /dev/null and b/src/theme/themes/images/myzcbg.jpg differ diff --git a/src/theme/themes/images/xnkl.png b/src/theme/themes/images/xnkl.png new file mode 100644 index 000000000..dd61284ad Binary files /dev/null and b/src/theme/themes/images/xnkl.png differ diff --git a/src/theme/themes/index.js b/src/theme/themes/index.js deleted file mode 100644 index e302c5286..000000000 --- a/src/theme/themes/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import green from './green' -import blue from './blue' -import orange from './orange' -import pink from './pink' -import red from './red' -import grey from './grey' -import black from './black' - -export default [ - green, - blue, - orange, - pink, - red, - grey, - black, -] diff --git a/src/theme/themes/index.ts b/src/theme/themes/index.ts new file mode 100644 index 000000000..e3c62aa19 --- /dev/null +++ b/src/theme/themes/index.ts @@ -0,0 +1,134 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +import { getUserTheme, saveUserTheme } from '@/utils/data' +import themes from '@/theme/themes/themes' +import settingState from '@/store/setting/state' +import themeState from '@/store/theme/state' +import { isUrl } from '@/utils' +import { externalDirectoryPath } from '@/utils/fs' +import { ImageSourcePropType } from 'react-native' + +export const BG_IMAGES = { + 'china_ink.jpg': require('./images/china_ink.jpg') as ImageSourcePropType, + 'jqbg.jpg': require('./images/jqbg.jpg') as ImageSourcePropType, + 'landingMoon.png': require('./images/landingMoon2.png') as ImageSourcePropType, + 'myzcbg.jpg': require('./images/myzcbg.jpg') as ImageSourcePropType, + 'xnkl.png': require('./images/xnkl.png') as ImageSourcePropType, +} as const + + +let userThemes: LX.Theme[] +export const getAllThemes = async() => { + userThemes ??= await getUserTheme() + return { + themes, + userThemes, + dataPath: externalDirectoryPath + '/theme_images', + } +} + +export const saveTheme = async(theme: LX.Theme) => { + const targetTheme = userThemes.find(t => t.id === theme.id) + if (targetTheme) Object.assign(targetTheme, theme) + else userThemes.push(theme) + await saveUserTheme(userThemes) +} + +export const removeTheme = async(id: string) => { + const index = userThemes.findIndex(t => t.id === id) + if (index < 0) return + userThemes.splice(index, 1) + await saveUserTheme(userThemes) +} + +export type LocalTheme = typeof themes[number] +type ColorsKey = keyof LX.Theme['config']['themeColors'] +type ExtInfoKey = keyof LX.Theme['config']['extInfo'] +const varColorRxp = /^var\((.+)\)$/ +export const buildActiveThemeColors = (theme: LX.Theme): LX.ActiveTheme => { + let bgImg: ImageSourcePropType | undefined + if (theme.isCustom) { + if (theme.config.extInfo['bg-image']) { + theme.config.extInfo['bg-image'] = + isUrl(theme.config.extInfo['bg-image']) + ? theme.config.extInfo['bg-image'] + : `${externalDirectoryPath}/theme_images/${theme.config.extInfo['bg-image']}` + } + } else { + const extInfo = (theme as LocalTheme).config.extInfo + if (extInfo['bg-image']) bgImg = BG_IMAGES[extInfo['bg-image']] + } + + theme.config.extInfo = { ...theme.config.extInfo } + + for (const [k, v] of Object.entries(theme.config.extInfo) as Array<[ExtInfoKey, LX.Theme['config']['extInfo'][ExtInfoKey]]>) { + if (!v.startsWith('var(')) continue + theme.config.extInfo[k] = theme.config.themeColors[v.replace(varColorRxp, '$1') as ColorsKey] + } + + return { + id: theme.id, + name: theme.name, + isDark: theme.isDark, + ...theme.config.themeColors, + ...theme.config.extInfo, + 'c-font': theme.config.themeColors['c-850'], + 'c-font-label': theme.config.themeColors['c-450'], + 'c-primary-font': theme.config.themeColors['c-primary'], + 'c-primary-font-hover': theme.config.themeColors['c-primary-alpha-300'], + 'c-primary-font-active': theme.config.themeColors['c-primary-dark-100-alpha-200'], + 'c-primary-background': theme.config.themeColors['c-primary-light-400-alpha-700'], + 'c-primary-background-hover': theme.config.themeColors['c-primary-light-300-alpha-800'], + 'c-primary-background-active': theme.config.themeColors['c-primary-light-100-alpha-800'], + 'c-primary-input-background': theme.config.themeColors['c-primary-light-400-alpha-700'], + 'c-button-font': theme.config.themeColors['c-primary-alpha-100'], + 'c-button-font-selected': theme.config.themeColors['c-primary-dark-100-alpha-100'], + 'c-button-background': theme.config.themeColors['c-primary-light-400-alpha-700'], + 'c-button-background-selected': theme.config.themeColors['c-primary-alpha-600'], + 'c-button-background-hover': theme.config.themeColors['c-primary-light-300-alpha-600'], + 'c-button-background-active': theme.config.themeColors['c-primary-light-100-alpha-600'], + 'c-list-header-border-bottom': theme.config.themeColors['c-primary-alpha-900'], + 'c-content-background': theme.config.themeColors['c-primary-light-1000'], + 'c-border-background': theme.config.themeColors['c-primary-light-100-alpha-700'], + 'bg-image': bgImg, + } as const +} + + +// const copyTheme = (theme: LX.Theme): LX.Theme => { +// return { +// ...theme, +// config: { +// ...theme.config, +// extInfo: { ...theme.config.extInfo }, +// themeColors: { ...theme.config.themeColors }, +// }, +// } +// } +// type IDS = LocalTheme['id'] +export const getTheme = async() => { + // fs.promises.readdir() + const shouldUseDarkColors = themeState.shouldUseDarkColors + // let themeId = settingState.setting['theme.id'] == 'auto' + // ? shouldUseDarkColors + // ? settingState.setting['theme.darkId'] + // : settingState.setting['theme.lightId'] + // // : 'china_ink' + // : settingState.setting['theme.id'] + let themeId = settingState.setting['common.isAutoTheme'] && shouldUseDarkColors + ? 'black' + : settingState.setting['theme.id'] + // themeId = 'naruto' + // themeId = 'pink' + // themeId = 'black' + let theme: LocalTheme | LX.Theme | undefined = themes.find(theme => theme.id == themeId) + if (!theme) { + userThemes = await getUserTheme() + theme = userThemes.find(theme => theme.id == themeId) + if (!theme) { + themeId = settingState.setting['theme.id'] == 'auto' && shouldUseDarkColors ? 'black' : 'green' + theme = themes.find(theme => theme.id == themeId) as LX.Theme + } + } + + return theme +} diff --git a/src/theme/themes/orange.js b/src/theme/themes/orange.js deleted file mode 100644 index 9b8fd5235..000000000 --- a/src/theme/themes/orange.js +++ /dev/null @@ -1,40 +0,0 @@ -export default { - id: 'orange', - isDark: false, - colors: { - primary: '#fff', - - normal: '#333', - normal10: '#4c4c4c', - normal20: '#666', - normal30: '#808080', - normal35: '#8c8c8c', - normal40: '#999', - normal50: '#b2b2b2', - normal60: '#ccc', - normal70: '#e6e6e6', - normal75: '#f2f2f2', - - secondary_5: '#f39a0c', - secondary: '#f5ab35', - secondary10: '#f7ba5a', - secondary20: '#f9ca80', - secondary30: '#fbdaa7', - secondary40: '#fdeace', - secondary45: '#fef2e1', - - tertiary_5: '#70a62b', - tertiary: '#89cb34', - tertiary10: '#9ed459', - tertiary20: '#b6de82', - tertiary30: '#cee9aa', - tertiary40: '#e5f3d3', - tertiary45: '#f1f8e7', - - borderColor: '#e6e6e6', - borderColor2: '#ebebeb', - borderColor3: '#f0f0f0', - borderColor4: '#f5f5f5', - borderColor5: '#fafafa', - }, -} diff --git a/src/theme/themes/pink.js b/src/theme/themes/pink.js deleted file mode 100644 index 696b84718..000000000 --- a/src/theme/themes/pink.js +++ /dev/null @@ -1,40 +0,0 @@ -export default { - id: 'pink', - isDark: false, - colors: { - primary: '#fff', - - normal: '#333', - normal10: '#4c4c4c', - normal20: '#666', - normal30: '#808080', - normal35: '#8c8c8c', - normal40: '#999', - normal50: '#b2b2b2', - normal60: '#ccc', - normal70: '#e6e6e6', - normal75: '#f2f2f2', - - secondary_5: '#ef6c79', - secondary: '#f1828d', - secondary10: '#f49aa3', - secondary20: '#f6b1b8', - secondary30: '#f9c8cd', - secondary40: '#fbdade', - secondary45: '#fde8ea', - - tertiary_5: '#f19a55', - tertiary: '#f3a86d', - tertiary10: '#f5b684', - tertiary20: '#f7c49c', - tertiary30: '#f9d2b3', - tertiary40: '#fbe0cb', - tertiary45: '#fce8d9', - - borderColor: '#e6e6e6', - borderColor2: '#ebebeb', - borderColor3: '#f0f0f0', - borderColor4: '#f5f5f5', - borderColor5: '#fafafa', - }, -} diff --git a/src/theme/themes/red.js b/src/theme/themes/red.js deleted file mode 100644 index c272b6493..000000000 --- a/src/theme/themes/red.js +++ /dev/null @@ -1,40 +0,0 @@ -export default { - id: 'red', - isDark: false, - colors: { - primary: '#fff', - - normal: '#333', - normal10: '#4c4c4c', - normal20: '#666', - normal30: '#808080', - normal35: '#8c8c8c', - normal40: '#999', - normal50: '#b2b2b2', - normal60: '#ccc', - normal70: '#e6e6e6', - normal75: '#f2f2f2', - - secondary_5: '#d2322d', - secondary: '#d64541', - secondary10: '#df6f6c', - secondary20: '#e89896', - secondary30: '#f1c1c0', - secondary40: '#f5d6d6', - secondary45: '#faeaea', - - tertiary_5: '#d29e2d', - tertiary: '#d7a842', - tertiary10: '#dbb257', - tertiary20: '#dfbb6b', - tertiary30: '#e4c581', - tertiary40: '#e9cf96', - tertiary45: '#edd8ab', - - borderColor: '#e6e6e6', - borderColor2: '#ebebeb', - borderColor3: '#f0f0f0', - borderColor4: '#f5f5f5', - borderColor5: '#fafafa', - }, -} diff --git a/src/theme/themes/themes.ts b/src/theme/themes/themes.ts new file mode 100644 index 000000000..4f2f8502b --- /dev/null +++ b/src/theme/themes/themes.ts @@ -0,0 +1,3785 @@ +/* eslint-disable */ +//! 此文件由 createThemes.js 生成 + +export default [ + { + "id": "green", + "name": "绿意盎然", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(77, 175, 124)", + "c-primary-dark-100": "rgb(69,158,112)", + "c-primary-dark-100-alpha-100": "rgba(69, 158, 112, 0.90)", + "c-primary-alpha-100": "rgba(77, 175, 124, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(69, 158, 112, 0.80)", + "c-primary-alpha-200": "rgba(77, 175, 124, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(69, 158, 112, 0.70)", + "c-primary-alpha-300": "rgba(77, 175, 124, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(69, 158, 112, 0.60)", + "c-primary-alpha-400": "rgba(77, 175, 124, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(69, 158, 112, 0.50)", + "c-primary-alpha-500": "rgba(77, 175, 124, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(69, 158, 112, 0.40)", + "c-primary-alpha-600": "rgba(77, 175, 124, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(69, 158, 112, 0.30)", + "c-primary-alpha-700": "rgba(77, 175, 124, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(69, 158, 112, 0.20)", + "c-primary-alpha-800": "rgba(77, 175, 124, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(69, 158, 112, 0.10)", + "c-primary-alpha-900": "rgba(77, 175, 124, 0.10)", + "c-primary-dark-200": "rgb(62,142,101)", + "c-primary-dark-200-alpha-100": "rgba(62, 142, 101, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(62, 142, 101, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(62, 142, 101, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(62, 142, 101, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(62, 142, 101, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(62, 142, 101, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(62, 142, 101, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(62, 142, 101, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(62, 142, 101, 0.10)", + "c-primary-dark-300": "rgb(56,128,91)", + "c-primary-dark-300-alpha-100": "rgba(56, 128, 91, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(56, 128, 91, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(56, 128, 91, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(56, 128, 91, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(56, 128, 91, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(56, 128, 91, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(56, 128, 91, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(56, 128, 91, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(56, 128, 91, 0.10)", + "c-primary-dark-400": "rgb(50,115,82)", + "c-primary-dark-400-alpha-100": "rgba(50, 115, 82, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(50, 115, 82, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(50, 115, 82, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(50, 115, 82, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(50, 115, 82, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(50, 115, 82, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(50, 115, 82, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(50, 115, 82, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(50, 115, 82, 0.10)", + "c-primary-dark-500": "rgb(45,104,74)", + "c-primary-dark-500-alpha-100": "rgba(45, 104, 74, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(45, 104, 74, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(45, 104, 74, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(45, 104, 74, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(45, 104, 74, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(45, 104, 74, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(45, 104, 74, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(45, 104, 74, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(45, 104, 74, 0.10)", + "c-primary-dark-600": "rgb(41,94,67)", + "c-primary-dark-600-alpha-100": "rgba(41, 94, 67, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(41, 94, 67, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(41, 94, 67, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(41, 94, 67, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(41, 94, 67, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(41, 94, 67, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(41, 94, 67, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(41, 94, 67, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(41, 94, 67, 0.10)", + "c-primary-dark-700": "rgb(37,85,60)", + "c-primary-dark-700-alpha-100": "rgba(37, 85, 60, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(37, 85, 60, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(37, 85, 60, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(37, 85, 60, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(37, 85, 60, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(37, 85, 60, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(37, 85, 60, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(37, 85, 60, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(37, 85, 60, 0.10)", + "c-primary-dark-800": "rgb(33,77,54)", + "c-primary-dark-800-alpha-100": "rgba(33, 77, 54, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(33, 77, 54, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(33, 77, 54, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(33, 77, 54, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(33, 77, 54, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(33, 77, 54, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(33, 77, 54, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(33, 77, 54, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(33, 77, 54, 0.10)", + "c-primary-dark-900": "rgb(30,69,49)", + "c-primary-dark-900-alpha-100": "rgba(30, 69, 49, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(30, 69, 49, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(30, 69, 49, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(30, 69, 49, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(30, 69, 49, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(30, 69, 49, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(30, 69, 49, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(30, 69, 49, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(30, 69, 49, 0.10)", + "c-primary-dark-1000": "rgb(27,62,44)", + "c-primary-dark-1000-alpha-100": "rgba(27, 62, 44, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(27, 62, 44, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(27, 62, 44, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(27, 62, 44, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(27, 62, 44, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(27, 62, 44, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(27, 62, 44, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(27, 62, 44, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(27, 62, 44, 0.10)", + "c-primary-light-100": "rgb(113,191,150)", + "c-primary-light-100-alpha-100": "rgba(113, 191, 150, 0.90)", + "c-primary-light-100-alpha-200": "rgba(113, 191, 150, 0.80)", + "c-primary-light-100-alpha-300": "rgba(113, 191, 150, 0.70)", + "c-primary-light-100-alpha-400": "rgba(113, 191, 150, 0.60)", + "c-primary-light-100-alpha-500": "rgba(113, 191, 150, 0.50)", + "c-primary-light-100-alpha-600": "rgba(113, 191, 150, 0.40)", + "c-primary-light-100-alpha-700": "rgba(113, 191, 150, 0.30)", + "c-primary-light-100-alpha-800": "rgba(113, 191, 150, 0.20)", + "c-primary-light-100-alpha-900": "rgba(113, 191, 150, 0.10)", + "c-primary-light-200": "rgb(141,204,171)", + "c-primary-light-200-alpha-100": "rgba(141, 204, 171, 0.90)", + "c-primary-light-200-alpha-200": "rgba(141, 204, 171, 0.80)", + "c-primary-light-200-alpha-300": "rgba(141, 204, 171, 0.70)", + "c-primary-light-200-alpha-400": "rgba(141, 204, 171, 0.60)", + "c-primary-light-200-alpha-500": "rgba(141, 204, 171, 0.50)", + "c-primary-light-200-alpha-600": "rgba(141, 204, 171, 0.40)", + "c-primary-light-200-alpha-700": "rgba(141, 204, 171, 0.30)", + "c-primary-light-200-alpha-800": "rgba(141, 204, 171, 0.20)", + "c-primary-light-200-alpha-900": "rgba(141, 204, 171, 0.10)", + "c-primary-light-300": "rgb(164,214,188)", + "c-primary-light-300-alpha-100": "rgba(164, 214, 188, 0.90)", + "c-primary-light-300-alpha-200": "rgba(164, 214, 188, 0.80)", + "c-primary-light-300-alpha-300": "rgba(164, 214, 188, 0.70)", + "c-primary-light-300-alpha-400": "rgba(164, 214, 188, 0.60)", + "c-primary-light-300-alpha-500": "rgba(164, 214, 188, 0.50)", + "c-primary-light-300-alpha-600": "rgba(164, 214, 188, 0.40)", + "c-primary-light-300-alpha-700": "rgba(164, 214, 188, 0.30)", + "c-primary-light-300-alpha-800": "rgba(164, 214, 188, 0.20)", + "c-primary-light-300-alpha-900": "rgba(164, 214, 188, 0.10)", + "c-primary-light-400": "rgb(182,222,201)", + "c-primary-light-400-alpha-100": "rgba(182, 222, 201, 0.90)", + "c-primary-light-400-alpha-200": "rgba(182, 222, 201, 0.80)", + "c-primary-light-400-alpha-300": "rgba(182, 222, 201, 0.70)", + "c-primary-light-400-alpha-400": "rgba(182, 222, 201, 0.60)", + "c-primary-light-400-alpha-500": "rgba(182, 222, 201, 0.50)", + "c-primary-light-400-alpha-600": "rgba(182, 222, 201, 0.40)", + "c-primary-light-400-alpha-700": "rgba(182, 222, 201, 0.30)", + "c-primary-light-400-alpha-800": "rgba(182, 222, 201, 0.20)", + "c-primary-light-400-alpha-900": "rgba(182, 222, 201, 0.10)", + "c-primary-light-500": "rgb(197,229,212)", + "c-primary-light-500-alpha-100": "rgba(197, 229, 212, 0.90)", + "c-primary-light-500-alpha-200": "rgba(197, 229, 212, 0.80)", + "c-primary-light-500-alpha-300": "rgba(197, 229, 212, 0.70)", + "c-primary-light-500-alpha-400": "rgba(197, 229, 212, 0.60)", + "c-primary-light-500-alpha-500": "rgba(197, 229, 212, 0.50)", + "c-primary-light-500-alpha-600": "rgba(197, 229, 212, 0.40)", + "c-primary-light-500-alpha-700": "rgba(197, 229, 212, 0.30)", + "c-primary-light-500-alpha-800": "rgba(197, 229, 212, 0.20)", + "c-primary-light-500-alpha-900": "rgba(197, 229, 212, 0.10)", + "c-primary-light-600": "rgb(209,234,221)", + "c-primary-light-600-alpha-100": "rgba(209, 234, 221, 0.90)", + "c-primary-light-600-alpha-200": "rgba(209, 234, 221, 0.80)", + "c-primary-light-600-alpha-300": "rgba(209, 234, 221, 0.70)", + "c-primary-light-600-alpha-400": "rgba(209, 234, 221, 0.60)", + "c-primary-light-600-alpha-500": "rgba(209, 234, 221, 0.50)", + "c-primary-light-600-alpha-600": "rgba(209, 234, 221, 0.40)", + "c-primary-light-600-alpha-700": "rgba(209, 234, 221, 0.30)", + "c-primary-light-600-alpha-800": "rgba(209, 234, 221, 0.20)", + "c-primary-light-600-alpha-900": "rgba(209, 234, 221, 0.10)", + "c-primary-light-700": "rgb(218,238,228)", + "c-primary-light-700-alpha-100": "rgba(218, 238, 228, 0.90)", + "c-primary-light-700-alpha-200": "rgba(218, 238, 228, 0.80)", + "c-primary-light-700-alpha-300": "rgba(218, 238, 228, 0.70)", + "c-primary-light-700-alpha-400": "rgba(218, 238, 228, 0.60)", + "c-primary-light-700-alpha-500": "rgba(218, 238, 228, 0.50)", + "c-primary-light-700-alpha-600": "rgba(218, 238, 228, 0.40)", + "c-primary-light-700-alpha-700": "rgba(218, 238, 228, 0.30)", + "c-primary-light-700-alpha-800": "rgba(218, 238, 228, 0.20)", + "c-primary-light-700-alpha-900": "rgba(218, 238, 228, 0.10)", + "c-primary-light-800": "rgb(225,241,233)", + "c-primary-light-800-alpha-100": "rgba(225, 241, 233, 0.90)", + "c-primary-light-800-alpha-200": "rgba(225, 241, 233, 0.80)", + "c-primary-light-800-alpha-300": "rgba(225, 241, 233, 0.70)", + "c-primary-light-800-alpha-400": "rgba(225, 241, 233, 0.60)", + "c-primary-light-800-alpha-500": "rgba(225, 241, 233, 0.50)", + "c-primary-light-800-alpha-600": "rgba(225, 241, 233, 0.40)", + "c-primary-light-800-alpha-700": "rgba(225, 241, 233, 0.30)", + "c-primary-light-800-alpha-800": "rgba(225, 241, 233, 0.20)", + "c-primary-light-800-alpha-900": "rgba(225, 241, 233, 0.10)", + "c-primary-light-900": "rgb(231,244,237)", + "c-primary-light-900-alpha-100": "rgba(231, 244, 237, 0.90)", + "c-primary-light-900-alpha-200": "rgba(231, 244, 237, 0.80)", + "c-primary-light-900-alpha-300": "rgba(231, 244, 237, 0.70)", + "c-primary-light-900-alpha-400": "rgba(231, 244, 237, 0.60)", + "c-primary-light-900-alpha-500": "rgba(231, 244, 237, 0.50)", + "c-primary-light-900-alpha-600": "rgba(231, 244, 237, 0.40)", + "c-primary-light-900-alpha-700": "rgba(231, 244, 237, 0.30)", + "c-primary-light-900-alpha-800": "rgba(231, 244, 237, 0.20)", + "c-primary-light-900-alpha-900": "rgba(231, 244, 237, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(77, 175, 124)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "var(c-primary-light-600-alpha-700)", + "c-main-background": "rgba(255, 255, 255, 1)", + "bg-image": "", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "#4baed5", + "c-badge-tertiary": "#e7aa36" + } + } + }, + { + "id": "blue", + "name": "蓝田生玉", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(52, 152, 219)", + "c-primary-dark-100": "rgb(47,137,197)", + "c-primary-dark-100-alpha-100": "rgba(47, 137, 197, 0.90)", + "c-primary-alpha-100": "rgba(52, 152, 219, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(47, 137, 197, 0.80)", + "c-primary-alpha-200": "rgba(52, 152, 219, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(47, 137, 197, 0.70)", + "c-primary-alpha-300": "rgba(52, 152, 219, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(47, 137, 197, 0.60)", + "c-primary-alpha-400": "rgba(52, 152, 219, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(47, 137, 197, 0.50)", + "c-primary-alpha-500": "rgba(52, 152, 219, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(47, 137, 197, 0.40)", + "c-primary-alpha-600": "rgba(52, 152, 219, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(47, 137, 197, 0.30)", + "c-primary-alpha-700": "rgba(52, 152, 219, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(47, 137, 197, 0.20)", + "c-primary-alpha-800": "rgba(52, 152, 219, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(47, 137, 197, 0.10)", + "c-primary-alpha-900": "rgba(52, 152, 219, 0.10)", + "c-primary-dark-200": "rgb(42,123,177)", + "c-primary-dark-200-alpha-100": "rgba(42, 123, 177, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(42, 123, 177, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(42, 123, 177, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(42, 123, 177, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(42, 123, 177, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(42, 123, 177, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(42, 123, 177, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(42, 123, 177, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(42, 123, 177, 0.10)", + "c-primary-dark-300": "rgb(38,111,159)", + "c-primary-dark-300-alpha-100": "rgba(38, 111, 159, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(38, 111, 159, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(38, 111, 159, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(38, 111, 159, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(38, 111, 159, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(38, 111, 159, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(38, 111, 159, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(38, 111, 159, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(38, 111, 159, 0.10)", + "c-primary-dark-400": "rgb(34,100,143)", + "c-primary-dark-400-alpha-100": "rgba(34, 100, 143, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(34, 100, 143, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(34, 100, 143, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(34, 100, 143, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(34, 100, 143, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(34, 100, 143, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(34, 100, 143, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(34, 100, 143, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(34, 100, 143, 0.10)", + "c-primary-dark-500": "rgb(31,90,129)", + "c-primary-dark-500-alpha-100": "rgba(31, 90, 129, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(31, 90, 129, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(31, 90, 129, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(31, 90, 129, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(31, 90, 129, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(31, 90, 129, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(31, 90, 129, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(31, 90, 129, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(31, 90, 129, 0.10)", + "c-primary-dark-600": "rgb(28,81,116)", + "c-primary-dark-600-alpha-100": "rgba(28, 81, 116, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(28, 81, 116, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(28, 81, 116, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(28, 81, 116, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(28, 81, 116, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(28, 81, 116, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(28, 81, 116, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(28, 81, 116, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(28, 81, 116, 0.10)", + "c-primary-dark-700": "rgb(25,73,104)", + "c-primary-dark-700-alpha-100": "rgba(25, 73, 104, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(25, 73, 104, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(25, 73, 104, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(25, 73, 104, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(25, 73, 104, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(25, 73, 104, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(25, 73, 104, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(25, 73, 104, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(25, 73, 104, 0.10)", + "c-primary-dark-800": "rgb(23,66,94)", + "c-primary-dark-800-alpha-100": "rgba(23, 66, 94, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(23, 66, 94, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(23, 66, 94, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(23, 66, 94, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(23, 66, 94, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(23, 66, 94, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(23, 66, 94, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(23, 66, 94, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(23, 66, 94, 0.10)", + "c-primary-dark-900": "rgb(21,59,85)", + "c-primary-dark-900-alpha-100": "rgba(21, 59, 85, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(21, 59, 85, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(21, 59, 85, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(21, 59, 85, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(21, 59, 85, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(21, 59, 85, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(21, 59, 85, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(21, 59, 85, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(21, 59, 85, 0.10)", + "c-primary-dark-1000": "rgb(19,53,77)", + "c-primary-dark-1000-alpha-100": "rgba(19, 53, 77, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(19, 53, 77, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(19, 53, 77, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(19, 53, 77, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(19, 53, 77, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(19, 53, 77, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(19, 53, 77, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(19, 53, 77, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(19, 53, 77, 0.10)", + "c-primary-light-100": "rgb(93,173,226)", + "c-primary-light-100-alpha-100": "rgba(93, 173, 226, 0.90)", + "c-primary-light-100-alpha-200": "rgba(93, 173, 226, 0.80)", + "c-primary-light-100-alpha-300": "rgba(93, 173, 226, 0.70)", + "c-primary-light-100-alpha-400": "rgba(93, 173, 226, 0.60)", + "c-primary-light-100-alpha-500": "rgba(93, 173, 226, 0.50)", + "c-primary-light-100-alpha-600": "rgba(93, 173, 226, 0.40)", + "c-primary-light-100-alpha-700": "rgba(93, 173, 226, 0.30)", + "c-primary-light-100-alpha-800": "rgba(93, 173, 226, 0.20)", + "c-primary-light-100-alpha-900": "rgba(93, 173, 226, 0.10)", + "c-primary-light-200": "rgb(125,189,232)", + "c-primary-light-200-alpha-100": "rgba(125, 189, 232, 0.90)", + "c-primary-light-200-alpha-200": "rgba(125, 189, 232, 0.80)", + "c-primary-light-200-alpha-300": "rgba(125, 189, 232, 0.70)", + "c-primary-light-200-alpha-400": "rgba(125, 189, 232, 0.60)", + "c-primary-light-200-alpha-500": "rgba(125, 189, 232, 0.50)", + "c-primary-light-200-alpha-600": "rgba(125, 189, 232, 0.40)", + "c-primary-light-200-alpha-700": "rgba(125, 189, 232, 0.30)", + "c-primary-light-200-alpha-800": "rgba(125, 189, 232, 0.20)", + "c-primary-light-200-alpha-900": "rgba(125, 189, 232, 0.10)", + "c-primary-light-300": "rgb(151,202,237)", + "c-primary-light-300-alpha-100": "rgba(151, 202, 237, 0.90)", + "c-primary-light-300-alpha-200": "rgba(151, 202, 237, 0.80)", + "c-primary-light-300-alpha-300": "rgba(151, 202, 237, 0.70)", + "c-primary-light-300-alpha-400": "rgba(151, 202, 237, 0.60)", + "c-primary-light-300-alpha-500": "rgba(151, 202, 237, 0.50)", + "c-primary-light-300-alpha-600": "rgba(151, 202, 237, 0.40)", + "c-primary-light-300-alpha-700": "rgba(151, 202, 237, 0.30)", + "c-primary-light-300-alpha-800": "rgba(151, 202, 237, 0.20)", + "c-primary-light-300-alpha-900": "rgba(151, 202, 237, 0.10)", + "c-primary-light-400": "rgb(172,213,241)", + "c-primary-light-400-alpha-100": "rgba(172, 213, 241, 0.90)", + "c-primary-light-400-alpha-200": "rgba(172, 213, 241, 0.80)", + "c-primary-light-400-alpha-300": "rgba(172, 213, 241, 0.70)", + "c-primary-light-400-alpha-400": "rgba(172, 213, 241, 0.60)", + "c-primary-light-400-alpha-500": "rgba(172, 213, 241, 0.50)", + "c-primary-light-400-alpha-600": "rgba(172, 213, 241, 0.40)", + "c-primary-light-400-alpha-700": "rgba(172, 213, 241, 0.30)", + "c-primary-light-400-alpha-800": "rgba(172, 213, 241, 0.20)", + "c-primary-light-400-alpha-900": "rgba(172, 213, 241, 0.10)", + "c-primary-light-500": "rgb(189,221,244)", + "c-primary-light-500-alpha-100": "rgba(189, 221, 244, 0.90)", + "c-primary-light-500-alpha-200": "rgba(189, 221, 244, 0.80)", + "c-primary-light-500-alpha-300": "rgba(189, 221, 244, 0.70)", + "c-primary-light-500-alpha-400": "rgba(189, 221, 244, 0.60)", + "c-primary-light-500-alpha-500": "rgba(189, 221, 244, 0.50)", + "c-primary-light-500-alpha-600": "rgba(189, 221, 244, 0.40)", + "c-primary-light-500-alpha-700": "rgba(189, 221, 244, 0.30)", + "c-primary-light-500-alpha-800": "rgba(189, 221, 244, 0.20)", + "c-primary-light-500-alpha-900": "rgba(189, 221, 244, 0.10)", + "c-primary-light-600": "rgb(202,228,246)", + "c-primary-light-600-alpha-100": "rgba(202, 228, 246, 0.90)", + "c-primary-light-600-alpha-200": "rgba(202, 228, 246, 0.80)", + "c-primary-light-600-alpha-300": "rgba(202, 228, 246, 0.70)", + "c-primary-light-600-alpha-400": "rgba(202, 228, 246, 0.60)", + "c-primary-light-600-alpha-500": "rgba(202, 228, 246, 0.50)", + "c-primary-light-600-alpha-600": "rgba(202, 228, 246, 0.40)", + "c-primary-light-600-alpha-700": "rgba(202, 228, 246, 0.30)", + "c-primary-light-600-alpha-800": "rgba(202, 228, 246, 0.20)", + "c-primary-light-600-alpha-900": "rgba(202, 228, 246, 0.10)", + "c-primary-light-700": "rgb(213,233,248)", + "c-primary-light-700-alpha-100": "rgba(213, 233, 248, 0.90)", + "c-primary-light-700-alpha-200": "rgba(213, 233, 248, 0.80)", + "c-primary-light-700-alpha-300": "rgba(213, 233, 248, 0.70)", + "c-primary-light-700-alpha-400": "rgba(213, 233, 248, 0.60)", + "c-primary-light-700-alpha-500": "rgba(213, 233, 248, 0.50)", + "c-primary-light-700-alpha-600": "rgba(213, 233, 248, 0.40)", + "c-primary-light-700-alpha-700": "rgba(213, 233, 248, 0.30)", + "c-primary-light-700-alpha-800": "rgba(213, 233, 248, 0.20)", + "c-primary-light-700-alpha-900": "rgba(213, 233, 248, 0.10)", + "c-primary-light-800": "rgb(221,237,249)", + "c-primary-light-800-alpha-100": "rgba(221, 237, 249, 0.90)", + "c-primary-light-800-alpha-200": "rgba(221, 237, 249, 0.80)", + "c-primary-light-800-alpha-300": "rgba(221, 237, 249, 0.70)", + "c-primary-light-800-alpha-400": "rgba(221, 237, 249, 0.60)", + "c-primary-light-800-alpha-500": "rgba(221, 237, 249, 0.50)", + "c-primary-light-800-alpha-600": "rgba(221, 237, 249, 0.40)", + "c-primary-light-800-alpha-700": "rgba(221, 237, 249, 0.30)", + "c-primary-light-800-alpha-800": "rgba(221, 237, 249, 0.20)", + "c-primary-light-800-alpha-900": "rgba(221, 237, 249, 0.10)", + "c-primary-light-900": "rgb(228,241,250)", + "c-primary-light-900-alpha-100": "rgba(228, 241, 250, 0.90)", + "c-primary-light-900-alpha-200": "rgba(228, 241, 250, 0.80)", + "c-primary-light-900-alpha-300": "rgba(228, 241, 250, 0.70)", + "c-primary-light-900-alpha-400": "rgba(228, 241, 250, 0.60)", + "c-primary-light-900-alpha-500": "rgba(228, 241, 250, 0.50)", + "c-primary-light-900-alpha-600": "rgba(228, 241, 250, 0.40)", + "c-primary-light-900-alpha-700": "rgba(228, 241, 250, 0.30)", + "c-primary-light-900-alpha-800": "rgba(228, 241, 250, 0.20)", + "c-primary-light-900-alpha-900": "rgba(228, 241, 250, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(52, 152, 219)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "var(c-primary-light-600-alpha-700)", + "c-main-background": "rgba(255, 255, 255, 1)", + "bg-image": "", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "#5cbf9b", + "c-badge-tertiary": "#5cbf9b" + } + } + }, + { + "id": "blue_plus", + "name": "蛋雅深蓝", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(77, 131, 175)", + "c-primary-dark-100": "rgb(69,118,158)", + "c-primary-dark-100-alpha-100": "rgba(69, 118, 158, 0.90)", + "c-primary-alpha-100": "rgba(77, 131, 175, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(69, 118, 158, 0.80)", + "c-primary-alpha-200": "rgba(77, 131, 175, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(69, 118, 158, 0.70)", + "c-primary-alpha-300": "rgba(77, 131, 175, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(69, 118, 158, 0.60)", + "c-primary-alpha-400": "rgba(77, 131, 175, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(69, 118, 158, 0.50)", + "c-primary-alpha-500": "rgba(77, 131, 175, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(69, 118, 158, 0.40)", + "c-primary-alpha-600": "rgba(77, 131, 175, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(69, 118, 158, 0.30)", + "c-primary-alpha-700": "rgba(77, 131, 175, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(69, 118, 158, 0.20)", + "c-primary-alpha-800": "rgba(77, 131, 175, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(69, 118, 158, 0.10)", + "c-primary-alpha-900": "rgba(77, 131, 175, 0.10)", + "c-primary-dark-200": "rgb(62,106,142)", + "c-primary-dark-200-alpha-100": "rgba(62, 106, 142, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(62, 106, 142, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(62, 106, 142, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(62, 106, 142, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(62, 106, 142, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(62, 106, 142, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(62, 106, 142, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(62, 106, 142, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(62, 106, 142, 0.10)", + "c-primary-dark-300": "rgb(56,95,128)", + "c-primary-dark-300-alpha-100": "rgba(56, 95, 128, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(56, 95, 128, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(56, 95, 128, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(56, 95, 128, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(56, 95, 128, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(56, 95, 128, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(56, 95, 128, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(56, 95, 128, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(56, 95, 128, 0.10)", + "c-primary-dark-400": "rgb(50,86,115)", + "c-primary-dark-400-alpha-100": "rgba(50, 86, 115, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(50, 86, 115, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(50, 86, 115, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(50, 86, 115, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(50, 86, 115, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(50, 86, 115, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(50, 86, 115, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(50, 86, 115, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(50, 86, 115, 0.10)", + "c-primary-dark-500": "rgb(45,77,104)", + "c-primary-dark-500-alpha-100": "rgba(45, 77, 104, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(45, 77, 104, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(45, 77, 104, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(45, 77, 104, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(45, 77, 104, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(45, 77, 104, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(45, 77, 104, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(45, 77, 104, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(45, 77, 104, 0.10)", + "c-primary-dark-600": "rgb(41,69,94)", + "c-primary-dark-600-alpha-100": "rgba(41, 69, 94, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(41, 69, 94, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(41, 69, 94, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(41, 69, 94, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(41, 69, 94, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(41, 69, 94, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(41, 69, 94, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(41, 69, 94, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(41, 69, 94, 0.10)", + "c-primary-dark-700": "rgb(37,62,85)", + "c-primary-dark-700-alpha-100": "rgba(37, 62, 85, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(37, 62, 85, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(37, 62, 85, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(37, 62, 85, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(37, 62, 85, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(37, 62, 85, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(37, 62, 85, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(37, 62, 85, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(37, 62, 85, 0.10)", + "c-primary-dark-800": "rgb(33,56,77)", + "c-primary-dark-800-alpha-100": "rgba(33, 56, 77, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(33, 56, 77, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(33, 56, 77, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(33, 56, 77, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(33, 56, 77, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(33, 56, 77, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(33, 56, 77, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(33, 56, 77, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(33, 56, 77, 0.10)", + "c-primary-dark-900": "rgb(30,50,69)", + "c-primary-dark-900-alpha-100": "rgba(30, 50, 69, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(30, 50, 69, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(30, 50, 69, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(30, 50, 69, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(30, 50, 69, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(30, 50, 69, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(30, 50, 69, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(30, 50, 69, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(30, 50, 69, 0.10)", + "c-primary-dark-1000": "rgb(27,45,62)", + "c-primary-dark-1000-alpha-100": "rgba(27, 45, 62, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(27, 45, 62, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(27, 45, 62, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(27, 45, 62, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(27, 45, 62, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(27, 45, 62, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(27, 45, 62, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(27, 45, 62, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(27, 45, 62, 0.10)", + "c-primary-light-100": "rgb(113,156,191)", + "c-primary-light-100-alpha-100": "rgba(113, 156, 191, 0.90)", + "c-primary-light-100-alpha-200": "rgba(113, 156, 191, 0.80)", + "c-primary-light-100-alpha-300": "rgba(113, 156, 191, 0.70)", + "c-primary-light-100-alpha-400": "rgba(113, 156, 191, 0.60)", + "c-primary-light-100-alpha-500": "rgba(113, 156, 191, 0.50)", + "c-primary-light-100-alpha-600": "rgba(113, 156, 191, 0.40)", + "c-primary-light-100-alpha-700": "rgba(113, 156, 191, 0.30)", + "c-primary-light-100-alpha-800": "rgba(113, 156, 191, 0.20)", + "c-primary-light-100-alpha-900": "rgba(113, 156, 191, 0.10)", + "c-primary-light-200": "rgb(141,176,204)", + "c-primary-light-200-alpha-100": "rgba(141, 176, 204, 0.90)", + "c-primary-light-200-alpha-200": "rgba(141, 176, 204, 0.80)", + "c-primary-light-200-alpha-300": "rgba(141, 176, 204, 0.70)", + "c-primary-light-200-alpha-400": "rgba(141, 176, 204, 0.60)", + "c-primary-light-200-alpha-500": "rgba(141, 176, 204, 0.50)", + "c-primary-light-200-alpha-600": "rgba(141, 176, 204, 0.40)", + "c-primary-light-200-alpha-700": "rgba(141, 176, 204, 0.30)", + "c-primary-light-200-alpha-800": "rgba(141, 176, 204, 0.20)", + "c-primary-light-200-alpha-900": "rgba(141, 176, 204, 0.10)", + "c-primary-light-300": "rgb(164,192,214)", + "c-primary-light-300-alpha-100": "rgba(164, 192, 214, 0.90)", + "c-primary-light-300-alpha-200": "rgba(164, 192, 214, 0.80)", + "c-primary-light-300-alpha-300": "rgba(164, 192, 214, 0.70)", + "c-primary-light-300-alpha-400": "rgba(164, 192, 214, 0.60)", + "c-primary-light-300-alpha-500": "rgba(164, 192, 214, 0.50)", + "c-primary-light-300-alpha-600": "rgba(164, 192, 214, 0.40)", + "c-primary-light-300-alpha-700": "rgba(164, 192, 214, 0.30)", + "c-primary-light-300-alpha-800": "rgba(164, 192, 214, 0.20)", + "c-primary-light-300-alpha-900": "rgba(164, 192, 214, 0.10)", + "c-primary-light-400": "rgb(182,205,222)", + "c-primary-light-400-alpha-100": "rgba(182, 205, 222, 0.90)", + "c-primary-light-400-alpha-200": "rgba(182, 205, 222, 0.80)", + "c-primary-light-400-alpha-300": "rgba(182, 205, 222, 0.70)", + "c-primary-light-400-alpha-400": "rgba(182, 205, 222, 0.60)", + "c-primary-light-400-alpha-500": "rgba(182, 205, 222, 0.50)", + "c-primary-light-400-alpha-600": "rgba(182, 205, 222, 0.40)", + "c-primary-light-400-alpha-700": "rgba(182, 205, 222, 0.30)", + "c-primary-light-400-alpha-800": "rgba(182, 205, 222, 0.20)", + "c-primary-light-400-alpha-900": "rgba(182, 205, 222, 0.10)", + "c-primary-light-500": "rgb(197,215,229)", + "c-primary-light-500-alpha-100": "rgba(197, 215, 229, 0.90)", + "c-primary-light-500-alpha-200": "rgba(197, 215, 229, 0.80)", + "c-primary-light-500-alpha-300": "rgba(197, 215, 229, 0.70)", + "c-primary-light-500-alpha-400": "rgba(197, 215, 229, 0.60)", + "c-primary-light-500-alpha-500": "rgba(197, 215, 229, 0.50)", + "c-primary-light-500-alpha-600": "rgba(197, 215, 229, 0.40)", + "c-primary-light-500-alpha-700": "rgba(197, 215, 229, 0.30)", + "c-primary-light-500-alpha-800": "rgba(197, 215, 229, 0.20)", + "c-primary-light-500-alpha-900": "rgba(197, 215, 229, 0.10)", + "c-primary-light-600": "rgb(209,223,234)", + "c-primary-light-600-alpha-100": "rgba(209, 223, 234, 0.90)", + "c-primary-light-600-alpha-200": "rgba(209, 223, 234, 0.80)", + "c-primary-light-600-alpha-300": "rgba(209, 223, 234, 0.70)", + "c-primary-light-600-alpha-400": "rgba(209, 223, 234, 0.60)", + "c-primary-light-600-alpha-500": "rgba(209, 223, 234, 0.50)", + "c-primary-light-600-alpha-600": "rgba(209, 223, 234, 0.40)", + "c-primary-light-600-alpha-700": "rgba(209, 223, 234, 0.30)", + "c-primary-light-600-alpha-800": "rgba(209, 223, 234, 0.20)", + "c-primary-light-600-alpha-900": "rgba(209, 223, 234, 0.10)", + "c-primary-light-700": "rgb(218,229,238)", + "c-primary-light-700-alpha-100": "rgba(218, 229, 238, 0.90)", + "c-primary-light-700-alpha-200": "rgba(218, 229, 238, 0.80)", + "c-primary-light-700-alpha-300": "rgba(218, 229, 238, 0.70)", + "c-primary-light-700-alpha-400": "rgba(218, 229, 238, 0.60)", + "c-primary-light-700-alpha-500": "rgba(218, 229, 238, 0.50)", + "c-primary-light-700-alpha-600": "rgba(218, 229, 238, 0.40)", + "c-primary-light-700-alpha-700": "rgba(218, 229, 238, 0.30)", + "c-primary-light-700-alpha-800": "rgba(218, 229, 238, 0.20)", + "c-primary-light-700-alpha-900": "rgba(218, 229, 238, 0.10)", + "c-primary-light-800": "rgb(225,234,241)", + "c-primary-light-800-alpha-100": "rgba(225, 234, 241, 0.90)", + "c-primary-light-800-alpha-200": "rgba(225, 234, 241, 0.80)", + "c-primary-light-800-alpha-300": "rgba(225, 234, 241, 0.70)", + "c-primary-light-800-alpha-400": "rgba(225, 234, 241, 0.60)", + "c-primary-light-800-alpha-500": "rgba(225, 234, 241, 0.50)", + "c-primary-light-800-alpha-600": "rgba(225, 234, 241, 0.40)", + "c-primary-light-800-alpha-700": "rgba(225, 234, 241, 0.30)", + "c-primary-light-800-alpha-800": "rgba(225, 234, 241, 0.20)", + "c-primary-light-800-alpha-900": "rgba(225, 234, 241, 0.10)", + "c-primary-light-900": "rgb(231,238,244)", + "c-primary-light-900-alpha-100": "rgba(231, 238, 244, 0.90)", + "c-primary-light-900-alpha-200": "rgba(231, 238, 244, 0.80)", + "c-primary-light-900-alpha-300": "rgba(231, 238, 244, 0.70)", + "c-primary-light-900-alpha-400": "rgba(231, 238, 244, 0.60)", + "c-primary-light-900-alpha-500": "rgba(231, 238, 244, 0.50)", + "c-primary-light-900-alpha-600": "rgba(231, 238, 244, 0.40)", + "c-primary-light-900-alpha-700": "rgba(231, 238, 244, 0.30)", + "c-primary-light-900-alpha-800": "rgba(231, 238, 244, 0.20)", + "c-primary-light-900-alpha-900": "rgba(231, 238, 244, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(77, 131, 175)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "var(c-primary-light-600-alpha-600)", + "c-main-background": "rgba(255, 255, 255, 1)", + "bg-image": "", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "rgba(66.6, 150.7, 171, 1)", + "c-badge-tertiary": "rgba(54, 196, 231, 1)" + } + } + }, + { + "id": "orange", + "name": "橙黄橘绿", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(245, 171, 53)", + "c-primary-dark-100": "rgb(221,154,48)", + "c-primary-dark-100-alpha-100": "rgba(221, 154, 48, 0.90)", + "c-primary-alpha-100": "rgba(245, 171, 53, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(221, 154, 48, 0.80)", + "c-primary-alpha-200": "rgba(245, 171, 53, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(221, 154, 48, 0.70)", + "c-primary-alpha-300": "rgba(245, 171, 53, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(221, 154, 48, 0.60)", + "c-primary-alpha-400": "rgba(245, 171, 53, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(221, 154, 48, 0.50)", + "c-primary-alpha-500": "rgba(245, 171, 53, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(221, 154, 48, 0.40)", + "c-primary-alpha-600": "rgba(245, 171, 53, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(221, 154, 48, 0.30)", + "c-primary-alpha-700": "rgba(245, 171, 53, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(221, 154, 48, 0.20)", + "c-primary-alpha-800": "rgba(245, 171, 53, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(221, 154, 48, 0.10)", + "c-primary-alpha-900": "rgba(245, 171, 53, 0.10)", + "c-primary-dark-200": "rgb(199,139,43)", + "c-primary-dark-200-alpha-100": "rgba(199, 139, 43, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(199, 139, 43, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(199, 139, 43, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(199, 139, 43, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(199, 139, 43, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(199, 139, 43, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(199, 139, 43, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(199, 139, 43, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(199, 139, 43, 0.10)", + "c-primary-dark-300": "rgb(179,125,39)", + "c-primary-dark-300-alpha-100": "rgba(179, 125, 39, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(179, 125, 39, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(179, 125, 39, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(179, 125, 39, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(179, 125, 39, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(179, 125, 39, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(179, 125, 39, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(179, 125, 39, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(179, 125, 39, 0.10)", + "c-primary-dark-400": "rgb(161,113,35)", + "c-primary-dark-400-alpha-100": "rgba(161, 113, 35, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(161, 113, 35, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(161, 113, 35, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(161, 113, 35, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(161, 113, 35, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(161, 113, 35, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(161, 113, 35, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(161, 113, 35, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(161, 113, 35, 0.10)", + "c-primary-dark-500": "rgb(145,102,32)", + "c-primary-dark-500-alpha-100": "rgba(145, 102, 32, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(145, 102, 32, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(145, 102, 32, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(145, 102, 32, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(145, 102, 32, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(145, 102, 32, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(145, 102, 32, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(145, 102, 32, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(145, 102, 32, 0.10)", + "c-primary-dark-600": "rgb(131,92,29)", + "c-primary-dark-600-alpha-100": "rgba(131, 92, 29, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(131, 92, 29, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(131, 92, 29, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(131, 92, 29, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(131, 92, 29, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(131, 92, 29, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(131, 92, 29, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(131, 92, 29, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(131, 92, 29, 0.10)", + "c-primary-dark-700": "rgb(118,83,26)", + "c-primary-dark-700-alpha-100": "rgba(118, 83, 26, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(118, 83, 26, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(118, 83, 26, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(118, 83, 26, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(118, 83, 26, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(118, 83, 26, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(118, 83, 26, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(118, 83, 26, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(118, 83, 26, 0.10)", + "c-primary-dark-800": "rgb(106,75,23)", + "c-primary-dark-800-alpha-100": "rgba(106, 75, 23, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(106, 75, 23, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(106, 75, 23, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(106, 75, 23, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(106, 75, 23, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(106, 75, 23, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(106, 75, 23, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(106, 75, 23, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(106, 75, 23, 0.10)", + "c-primary-dark-900": "rgb(95,68,21)", + "c-primary-dark-900-alpha-100": "rgba(95, 68, 21, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(95, 68, 21, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(95, 68, 21, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(95, 68, 21, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(95, 68, 21, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(95, 68, 21, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(95, 68, 21, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(95, 68, 21, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(95, 68, 21, 0.10)", + "c-primary-dark-1000": "rgb(86,61,19)", + "c-primary-dark-1000-alpha-100": "rgba(86, 61, 19, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(86, 61, 19, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(86, 61, 19, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(86, 61, 19, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(86, 61, 19, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(86, 61, 19, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(86, 61, 19, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(86, 61, 19, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(86, 61, 19, 0.10)", + "c-primary-light-100": "rgb(247,188,93)", + "c-primary-light-100-alpha-100": "rgba(247, 188, 93, 0.90)", + "c-primary-light-100-alpha-200": "rgba(247, 188, 93, 0.80)", + "c-primary-light-100-alpha-300": "rgba(247, 188, 93, 0.70)", + "c-primary-light-100-alpha-400": "rgba(247, 188, 93, 0.60)", + "c-primary-light-100-alpha-500": "rgba(247, 188, 93, 0.50)", + "c-primary-light-100-alpha-600": "rgba(247, 188, 93, 0.40)", + "c-primary-light-100-alpha-700": "rgba(247, 188, 93, 0.30)", + "c-primary-light-100-alpha-800": "rgba(247, 188, 93, 0.20)", + "c-primary-light-100-alpha-900": "rgba(247, 188, 93, 0.10)", + "c-primary-light-200": "rgb(249,201,125)", + "c-primary-light-200-alpha-100": "rgba(249, 201, 125, 0.90)", + "c-primary-light-200-alpha-200": "rgba(249, 201, 125, 0.80)", + "c-primary-light-200-alpha-300": "rgba(249, 201, 125, 0.70)", + "c-primary-light-200-alpha-400": "rgba(249, 201, 125, 0.60)", + "c-primary-light-200-alpha-500": "rgba(249, 201, 125, 0.50)", + "c-primary-light-200-alpha-600": "rgba(249, 201, 125, 0.40)", + "c-primary-light-200-alpha-700": "rgba(249, 201, 125, 0.30)", + "c-primary-light-200-alpha-800": "rgba(249, 201, 125, 0.20)", + "c-primary-light-200-alpha-900": "rgba(249, 201, 125, 0.10)", + "c-primary-light-300": "rgb(250,212,151)", + "c-primary-light-300-alpha-100": "rgba(250, 212, 151, 0.90)", + "c-primary-light-300-alpha-200": "rgba(250, 212, 151, 0.80)", + "c-primary-light-300-alpha-300": "rgba(250, 212, 151, 0.70)", + "c-primary-light-300-alpha-400": "rgba(250, 212, 151, 0.60)", + "c-primary-light-300-alpha-500": "rgba(250, 212, 151, 0.50)", + "c-primary-light-300-alpha-600": "rgba(250, 212, 151, 0.40)", + "c-primary-light-300-alpha-700": "rgba(250, 212, 151, 0.30)", + "c-primary-light-300-alpha-800": "rgba(250, 212, 151, 0.20)", + "c-primary-light-300-alpha-900": "rgba(250, 212, 151, 0.10)", + "c-primary-light-400": "rgb(251,221,172)", + "c-primary-light-400-alpha-100": "rgba(251, 221, 172, 0.90)", + "c-primary-light-400-alpha-200": "rgba(251, 221, 172, 0.80)", + "c-primary-light-400-alpha-300": "rgba(251, 221, 172, 0.70)", + "c-primary-light-400-alpha-400": "rgba(251, 221, 172, 0.60)", + "c-primary-light-400-alpha-500": "rgba(251, 221, 172, 0.50)", + "c-primary-light-400-alpha-600": "rgba(251, 221, 172, 0.40)", + "c-primary-light-400-alpha-700": "rgba(251, 221, 172, 0.30)", + "c-primary-light-400-alpha-800": "rgba(251, 221, 172, 0.20)", + "c-primary-light-400-alpha-900": "rgba(251, 221, 172, 0.10)", + "c-primary-light-500": "rgb(252,228,189)", + "c-primary-light-500-alpha-100": "rgba(252, 228, 189, 0.90)", + "c-primary-light-500-alpha-200": "rgba(252, 228, 189, 0.80)", + "c-primary-light-500-alpha-300": "rgba(252, 228, 189, 0.70)", + "c-primary-light-500-alpha-400": "rgba(252, 228, 189, 0.60)", + "c-primary-light-500-alpha-500": "rgba(252, 228, 189, 0.50)", + "c-primary-light-500-alpha-600": "rgba(252, 228, 189, 0.40)", + "c-primary-light-500-alpha-700": "rgba(252, 228, 189, 0.30)", + "c-primary-light-500-alpha-800": "rgba(252, 228, 189, 0.20)", + "c-primary-light-500-alpha-900": "rgba(252, 228, 189, 0.10)", + "c-primary-light-600": "rgb(253,233,202)", + "c-primary-light-600-alpha-100": "rgba(253, 233, 202, 0.90)", + "c-primary-light-600-alpha-200": "rgba(253, 233, 202, 0.80)", + "c-primary-light-600-alpha-300": "rgba(253, 233, 202, 0.70)", + "c-primary-light-600-alpha-400": "rgba(253, 233, 202, 0.60)", + "c-primary-light-600-alpha-500": "rgba(253, 233, 202, 0.50)", + "c-primary-light-600-alpha-600": "rgba(253, 233, 202, 0.40)", + "c-primary-light-600-alpha-700": "rgba(253, 233, 202, 0.30)", + "c-primary-light-600-alpha-800": "rgba(253, 233, 202, 0.20)", + "c-primary-light-600-alpha-900": "rgba(253, 233, 202, 0.10)", + "c-primary-light-700": "rgb(253,237,213)", + "c-primary-light-700-alpha-100": "rgba(253, 237, 213, 0.90)", + "c-primary-light-700-alpha-200": "rgba(253, 237, 213, 0.80)", + "c-primary-light-700-alpha-300": "rgba(253, 237, 213, 0.70)", + "c-primary-light-700-alpha-400": "rgba(253, 237, 213, 0.60)", + "c-primary-light-700-alpha-500": "rgba(253, 237, 213, 0.50)", + "c-primary-light-700-alpha-600": "rgba(253, 237, 213, 0.40)", + "c-primary-light-700-alpha-700": "rgba(253, 237, 213, 0.30)", + "c-primary-light-700-alpha-800": "rgba(253, 237, 213, 0.20)", + "c-primary-light-700-alpha-900": "rgba(253, 237, 213, 0.10)", + "c-primary-light-800": "rgb(253,241,221)", + "c-primary-light-800-alpha-100": "rgba(253, 241, 221, 0.90)", + "c-primary-light-800-alpha-200": "rgba(253, 241, 221, 0.80)", + "c-primary-light-800-alpha-300": "rgba(253, 241, 221, 0.70)", + "c-primary-light-800-alpha-400": "rgba(253, 241, 221, 0.60)", + "c-primary-light-800-alpha-500": "rgba(253, 241, 221, 0.50)", + "c-primary-light-800-alpha-600": "rgba(253, 241, 221, 0.40)", + "c-primary-light-800-alpha-700": "rgba(253, 241, 221, 0.30)", + "c-primary-light-800-alpha-800": "rgba(253, 241, 221, 0.20)", + "c-primary-light-800-alpha-900": "rgba(253, 241, 221, 0.10)", + "c-primary-light-900": "rgb(253,244,228)", + "c-primary-light-900-alpha-100": "rgba(253, 244, 228, 0.90)", + "c-primary-light-900-alpha-200": "rgba(253, 244, 228, 0.80)", + "c-primary-light-900-alpha-300": "rgba(253, 244, 228, 0.70)", + "c-primary-light-900-alpha-400": "rgba(253, 244, 228, 0.60)", + "c-primary-light-900-alpha-500": "rgba(253, 244, 228, 0.50)", + "c-primary-light-900-alpha-600": "rgba(253, 244, 228, 0.40)", + "c-primary-light-900-alpha-700": "rgba(253, 244, 228, 0.30)", + "c-primary-light-900-alpha-800": "rgba(253, 244, 228, 0.20)", + "c-primary-light-900-alpha-900": "rgba(253, 244, 228, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(245, 171, 53)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "var(c-primary-light-600-alpha-700)", + "c-main-background": "rgba(255, 255, 255, 1)", + "bg-image": "", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "#9ed458", + "c-badge-tertiary": "#9ed458" + } + } + }, + { + "id": "red", + "name": "热情似火", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(214, 69, 65)", + "c-primary-dark-100": "rgb(193,62,59)", + "c-primary-dark-100-alpha-100": "rgba(193, 62, 59, 0.90)", + "c-primary-alpha-100": "rgba(214, 69, 65, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(193, 62, 59, 0.80)", + "c-primary-alpha-200": "rgba(214, 69, 65, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(193, 62, 59, 0.70)", + "c-primary-alpha-300": "rgba(214, 69, 65, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(193, 62, 59, 0.60)", + "c-primary-alpha-400": "rgba(214, 69, 65, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(193, 62, 59, 0.50)", + "c-primary-alpha-500": "rgba(214, 69, 65, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(193, 62, 59, 0.40)", + "c-primary-alpha-600": "rgba(214, 69, 65, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(193, 62, 59, 0.30)", + "c-primary-alpha-700": "rgba(214, 69, 65, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(193, 62, 59, 0.20)", + "c-primary-alpha-800": "rgba(214, 69, 65, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(193, 62, 59, 0.10)", + "c-primary-alpha-900": "rgba(214, 69, 65, 0.10)", + "c-primary-dark-200": "rgb(174,56,53)", + "c-primary-dark-200-alpha-100": "rgba(174, 56, 53, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(174, 56, 53, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(174, 56, 53, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(174, 56, 53, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(174, 56, 53, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(174, 56, 53, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(174, 56, 53, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(174, 56, 53, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(174, 56, 53, 0.10)", + "c-primary-dark-300": "rgb(157,50,48)", + "c-primary-dark-300-alpha-100": "rgba(157, 50, 48, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(157, 50, 48, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(157, 50, 48, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(157, 50, 48, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(157, 50, 48, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(157, 50, 48, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(157, 50, 48, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(157, 50, 48, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(157, 50, 48, 0.10)", + "c-primary-dark-400": "rgb(141,45,43)", + "c-primary-dark-400-alpha-100": "rgba(141, 45, 43, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(141, 45, 43, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(141, 45, 43, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(141, 45, 43, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(141, 45, 43, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(141, 45, 43, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(141, 45, 43, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(141, 45, 43, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(141, 45, 43, 0.10)", + "c-primary-dark-500": "rgb(127,41,39)", + "c-primary-dark-500-alpha-100": "rgba(127, 41, 39, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(127, 41, 39, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(127, 41, 39, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(127, 41, 39, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(127, 41, 39, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(127, 41, 39, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(127, 41, 39, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(127, 41, 39, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(127, 41, 39, 0.10)", + "c-primary-dark-600": "rgb(114,37,35)", + "c-primary-dark-600-alpha-100": "rgba(114, 37, 35, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(114, 37, 35, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(114, 37, 35, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(114, 37, 35, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(114, 37, 35, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(114, 37, 35, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(114, 37, 35, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(114, 37, 35, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(114, 37, 35, 0.10)", + "c-primary-dark-700": "rgb(103,33,32)", + "c-primary-dark-700-alpha-100": "rgba(103, 33, 32, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(103, 33, 32, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(103, 33, 32, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(103, 33, 32, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(103, 33, 32, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(103, 33, 32, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(103, 33, 32, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(103, 33, 32, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(103, 33, 32, 0.10)", + "c-primary-dark-800": "rgb(93,30,29)", + "c-primary-dark-800-alpha-100": "rgba(93, 30, 29, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(93, 30, 29, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(93, 30, 29, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(93, 30, 29, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(93, 30, 29, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(93, 30, 29, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(93, 30, 29, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(93, 30, 29, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(93, 30, 29, 0.10)", + "c-primary-dark-900": "rgb(84,27,26)", + "c-primary-dark-900-alpha-100": "rgba(84, 27, 26, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(84, 27, 26, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(84, 27, 26, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(84, 27, 26, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(84, 27, 26, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(84, 27, 26, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(84, 27, 26, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(84, 27, 26, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(84, 27, 26, 0.10)", + "c-primary-dark-1000": "rgb(76,24,23)", + "c-primary-dark-1000-alpha-100": "rgba(76, 24, 23, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(76, 24, 23, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(76, 24, 23, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(76, 24, 23, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(76, 24, 23, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(76, 24, 23, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(76, 24, 23, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(76, 24, 23, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(76, 24, 23, 0.10)", + "c-primary-light-100": "rgb(222,106,103)", + "c-primary-light-100-alpha-100": "rgba(222, 106, 103, 0.90)", + "c-primary-light-100-alpha-200": "rgba(222, 106, 103, 0.80)", + "c-primary-light-100-alpha-300": "rgba(222, 106, 103, 0.70)", + "c-primary-light-100-alpha-400": "rgba(222, 106, 103, 0.60)", + "c-primary-light-100-alpha-500": "rgba(222, 106, 103, 0.50)", + "c-primary-light-100-alpha-600": "rgba(222, 106, 103, 0.40)", + "c-primary-light-100-alpha-700": "rgba(222, 106, 103, 0.30)", + "c-primary-light-100-alpha-800": "rgba(222, 106, 103, 0.20)", + "c-primary-light-100-alpha-900": "rgba(222, 106, 103, 0.10)", + "c-primary-light-200": "rgb(229,136,133)", + "c-primary-light-200-alpha-100": "rgba(229, 136, 133, 0.90)", + "c-primary-light-200-alpha-200": "rgba(229, 136, 133, 0.80)", + "c-primary-light-200-alpha-300": "rgba(229, 136, 133, 0.70)", + "c-primary-light-200-alpha-400": "rgba(229, 136, 133, 0.60)", + "c-primary-light-200-alpha-500": "rgba(229, 136, 133, 0.50)", + "c-primary-light-200-alpha-600": "rgba(229, 136, 133, 0.40)", + "c-primary-light-200-alpha-700": "rgba(229, 136, 133, 0.30)", + "c-primary-light-200-alpha-800": "rgba(229, 136, 133, 0.20)", + "c-primary-light-200-alpha-900": "rgba(229, 136, 133, 0.10)", + "c-primary-light-300": "rgb(234,160,157)", + "c-primary-light-300-alpha-100": "rgba(234, 160, 157, 0.90)", + "c-primary-light-300-alpha-200": "rgba(234, 160, 157, 0.80)", + "c-primary-light-300-alpha-300": "rgba(234, 160, 157, 0.70)", + "c-primary-light-300-alpha-400": "rgba(234, 160, 157, 0.60)", + "c-primary-light-300-alpha-500": "rgba(234, 160, 157, 0.50)", + "c-primary-light-300-alpha-600": "rgba(234, 160, 157, 0.40)", + "c-primary-light-300-alpha-700": "rgba(234, 160, 157, 0.30)", + "c-primary-light-300-alpha-800": "rgba(234, 160, 157, 0.20)", + "c-primary-light-300-alpha-900": "rgba(234, 160, 157, 0.10)", + "c-primary-light-400": "rgb(238,179,177)", + "c-primary-light-400-alpha-100": "rgba(238, 179, 177, 0.90)", + "c-primary-light-400-alpha-200": "rgba(238, 179, 177, 0.80)", + "c-primary-light-400-alpha-300": "rgba(238, 179, 177, 0.70)", + "c-primary-light-400-alpha-400": "rgba(238, 179, 177, 0.60)", + "c-primary-light-400-alpha-500": "rgba(238, 179, 177, 0.50)", + "c-primary-light-400-alpha-600": "rgba(238, 179, 177, 0.40)", + "c-primary-light-400-alpha-700": "rgba(238, 179, 177, 0.30)", + "c-primary-light-400-alpha-800": "rgba(238, 179, 177, 0.20)", + "c-primary-light-400-alpha-900": "rgba(238, 179, 177, 0.10)", + "c-primary-light-500": "rgb(241,194,193)", + "c-primary-light-500-alpha-100": "rgba(241, 194, 193, 0.90)", + "c-primary-light-500-alpha-200": "rgba(241, 194, 193, 0.80)", + "c-primary-light-500-alpha-300": "rgba(241, 194, 193, 0.70)", + "c-primary-light-500-alpha-400": "rgba(241, 194, 193, 0.60)", + "c-primary-light-500-alpha-500": "rgba(241, 194, 193, 0.50)", + "c-primary-light-500-alpha-600": "rgba(241, 194, 193, 0.40)", + "c-primary-light-500-alpha-700": "rgba(241, 194, 193, 0.30)", + "c-primary-light-500-alpha-800": "rgba(241, 194, 193, 0.20)", + "c-primary-light-500-alpha-900": "rgba(241, 194, 193, 0.10)", + "c-primary-light-600": "rgb(244,206,205)", + "c-primary-light-600-alpha-100": "rgba(244, 206, 205, 0.90)", + "c-primary-light-600-alpha-200": "rgba(244, 206, 205, 0.80)", + "c-primary-light-600-alpha-300": "rgba(244, 206, 205, 0.70)", + "c-primary-light-600-alpha-400": "rgba(244, 206, 205, 0.60)", + "c-primary-light-600-alpha-500": "rgba(244, 206, 205, 0.50)", + "c-primary-light-600-alpha-600": "rgba(244, 206, 205, 0.40)", + "c-primary-light-600-alpha-700": "rgba(244, 206, 205, 0.30)", + "c-primary-light-600-alpha-800": "rgba(244, 206, 205, 0.20)", + "c-primary-light-600-alpha-900": "rgba(244, 206, 205, 0.10)", + "c-primary-light-700": "rgb(246,216,215)", + "c-primary-light-700-alpha-100": "rgba(246, 216, 215, 0.90)", + "c-primary-light-700-alpha-200": "rgba(246, 216, 215, 0.80)", + "c-primary-light-700-alpha-300": "rgba(246, 216, 215, 0.70)", + "c-primary-light-700-alpha-400": "rgba(246, 216, 215, 0.60)", + "c-primary-light-700-alpha-500": "rgba(246, 216, 215, 0.50)", + "c-primary-light-700-alpha-600": "rgba(246, 216, 215, 0.40)", + "c-primary-light-700-alpha-700": "rgba(246, 216, 215, 0.30)", + "c-primary-light-700-alpha-800": "rgba(246, 216, 215, 0.20)", + "c-primary-light-700-alpha-900": "rgba(246, 216, 215, 0.10)", + "c-primary-light-800": "rgb(248,224,223)", + "c-primary-light-800-alpha-100": "rgba(248, 224, 223, 0.90)", + "c-primary-light-800-alpha-200": "rgba(248, 224, 223, 0.80)", + "c-primary-light-800-alpha-300": "rgba(248, 224, 223, 0.70)", + "c-primary-light-800-alpha-400": "rgba(248, 224, 223, 0.60)", + "c-primary-light-800-alpha-500": "rgba(248, 224, 223, 0.50)", + "c-primary-light-800-alpha-600": "rgba(248, 224, 223, 0.40)", + "c-primary-light-800-alpha-700": "rgba(248, 224, 223, 0.30)", + "c-primary-light-800-alpha-800": "rgba(248, 224, 223, 0.20)", + "c-primary-light-800-alpha-900": "rgba(248, 224, 223, 0.10)", + "c-primary-light-900": "rgb(249,230,229)", + "c-primary-light-900-alpha-100": "rgba(249, 230, 229, 0.90)", + "c-primary-light-900-alpha-200": "rgba(249, 230, 229, 0.80)", + "c-primary-light-900-alpha-300": "rgba(249, 230, 229, 0.70)", + "c-primary-light-900-alpha-400": "rgba(249, 230, 229, 0.60)", + "c-primary-light-900-alpha-500": "rgba(249, 230, 229, 0.50)", + "c-primary-light-900-alpha-600": "rgba(249, 230, 229, 0.40)", + "c-primary-light-900-alpha-700": "rgba(249, 230, 229, 0.30)", + "c-primary-light-900-alpha-800": "rgba(249, 230, 229, 0.20)", + "c-primary-light-900-alpha-900": "rgba(249, 230, 229, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(214, 69, 65)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "var(c-primary-light-600-alpha-700)", + "c-main-background": "rgba(255, 255, 255, 1)", + "bg-image": "", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "#dfbb6b", + "c-badge-tertiary": "#dfbb6b" + } + } + }, + { + "id": "pink", + "name": "粉装玉琢", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(241, 130, 141)", + "c-primary-dark-100": "rgb(217,117,127)", + "c-primary-dark-100-alpha-100": "rgba(217, 117, 127, 0.90)", + "c-primary-alpha-100": "rgba(241, 130, 141, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(217, 117, 127, 0.80)", + "c-primary-alpha-200": "rgba(241, 130, 141, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(217, 117, 127, 0.70)", + "c-primary-alpha-300": "rgba(241, 130, 141, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(217, 117, 127, 0.60)", + "c-primary-alpha-400": "rgba(241, 130, 141, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(217, 117, 127, 0.50)", + "c-primary-alpha-500": "rgba(241, 130, 141, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(217, 117, 127, 0.40)", + "c-primary-alpha-600": "rgba(241, 130, 141, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(217, 117, 127, 0.30)", + "c-primary-alpha-700": "rgba(241, 130, 141, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(217, 117, 127, 0.20)", + "c-primary-alpha-800": "rgba(241, 130, 141, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(217, 117, 127, 0.10)", + "c-primary-alpha-900": "rgba(241, 130, 141, 0.10)", + "c-primary-dark-200": "rgb(195,105,114)", + "c-primary-dark-200-alpha-100": "rgba(195, 105, 114, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(195, 105, 114, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(195, 105, 114, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(195, 105, 114, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(195, 105, 114, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(195, 105, 114, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(195, 105, 114, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(195, 105, 114, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(195, 105, 114, 0.10)", + "c-primary-dark-300": "rgb(176,95,103)", + "c-primary-dark-300-alpha-100": "rgba(176, 95, 103, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(176, 95, 103, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(176, 95, 103, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(176, 95, 103, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(176, 95, 103, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(176, 95, 103, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(176, 95, 103, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(176, 95, 103, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(176, 95, 103, 0.10)", + "c-primary-dark-400": "rgb(158,86,93)", + "c-primary-dark-400-alpha-100": "rgba(158, 86, 93, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(158, 86, 93, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(158, 86, 93, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(158, 86, 93, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(158, 86, 93, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(158, 86, 93, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(158, 86, 93, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(158, 86, 93, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(158, 86, 93, 0.10)", + "c-primary-dark-500": "rgb(142,77,84)", + "c-primary-dark-500-alpha-100": "rgba(142, 77, 84, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(142, 77, 84, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(142, 77, 84, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(142, 77, 84, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(142, 77, 84, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(142, 77, 84, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(142, 77, 84, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(142, 77, 84, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(142, 77, 84, 0.10)", + "c-primary-dark-600": "rgb(128,69,76)", + "c-primary-dark-600-alpha-100": "rgba(128, 69, 76, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(128, 69, 76, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(128, 69, 76, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(128, 69, 76, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(128, 69, 76, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(128, 69, 76, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(128, 69, 76, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(128, 69, 76, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(128, 69, 76, 0.10)", + "c-primary-dark-700": "rgb(115,62,68)", + "c-primary-dark-700-alpha-100": "rgba(115, 62, 68, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(115, 62, 68, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(115, 62, 68, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(115, 62, 68, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(115, 62, 68, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(115, 62, 68, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(115, 62, 68, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(115, 62, 68, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(115, 62, 68, 0.10)", + "c-primary-dark-800": "rgb(104,56,61)", + "c-primary-dark-800-alpha-100": "rgba(104, 56, 61, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(104, 56, 61, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(104, 56, 61, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(104, 56, 61, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(104, 56, 61, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(104, 56, 61, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(104, 56, 61, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(104, 56, 61, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(104, 56, 61, 0.10)", + "c-primary-dark-900": "rgb(94,50,55)", + "c-primary-dark-900-alpha-100": "rgba(94, 50, 55, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(94, 50, 55, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(94, 50, 55, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(94, 50, 55, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(94, 50, 55, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(94, 50, 55, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(94, 50, 55, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(94, 50, 55, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(94, 50, 55, 0.10)", + "c-primary-dark-1000": "rgb(85,45,50)", + "c-primary-dark-1000-alpha-100": "rgba(85, 45, 50, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(85, 45, 50, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(85, 45, 50, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(85, 45, 50, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(85, 45, 50, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(85, 45, 50, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(85, 45, 50, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(85, 45, 50, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(85, 45, 50, 0.10)", + "c-primary-light-100": "rgb(244,155,164)", + "c-primary-light-100-alpha-100": "rgba(244, 155, 164, 0.90)", + "c-primary-light-100-alpha-200": "rgba(244, 155, 164, 0.80)", + "c-primary-light-100-alpha-300": "rgba(244, 155, 164, 0.70)", + "c-primary-light-100-alpha-400": "rgba(244, 155, 164, 0.60)", + "c-primary-light-100-alpha-500": "rgba(244, 155, 164, 0.50)", + "c-primary-light-100-alpha-600": "rgba(244, 155, 164, 0.40)", + "c-primary-light-100-alpha-700": "rgba(244, 155, 164, 0.30)", + "c-primary-light-100-alpha-800": "rgba(244, 155, 164, 0.20)", + "c-primary-light-100-alpha-900": "rgba(244, 155, 164, 0.10)", + "c-primary-light-200": "rgb(246,175,182)", + "c-primary-light-200-alpha-100": "rgba(246, 175, 182, 0.90)", + "c-primary-light-200-alpha-200": "rgba(246, 175, 182, 0.80)", + "c-primary-light-200-alpha-300": "rgba(246, 175, 182, 0.70)", + "c-primary-light-200-alpha-400": "rgba(246, 175, 182, 0.60)", + "c-primary-light-200-alpha-500": "rgba(246, 175, 182, 0.50)", + "c-primary-light-200-alpha-600": "rgba(246, 175, 182, 0.40)", + "c-primary-light-200-alpha-700": "rgba(246, 175, 182, 0.30)", + "c-primary-light-200-alpha-800": "rgba(246, 175, 182, 0.20)", + "c-primary-light-200-alpha-900": "rgba(246, 175, 182, 0.10)", + "c-primary-light-300": "rgb(248,191,197)", + "c-primary-light-300-alpha-100": "rgba(248, 191, 197, 0.90)", + "c-primary-light-300-alpha-200": "rgba(248, 191, 197, 0.80)", + "c-primary-light-300-alpha-300": "rgba(248, 191, 197, 0.70)", + "c-primary-light-300-alpha-400": "rgba(248, 191, 197, 0.60)", + "c-primary-light-300-alpha-500": "rgba(248, 191, 197, 0.50)", + "c-primary-light-300-alpha-600": "rgba(248, 191, 197, 0.40)", + "c-primary-light-300-alpha-700": "rgba(248, 191, 197, 0.30)", + "c-primary-light-300-alpha-800": "rgba(248, 191, 197, 0.20)", + "c-primary-light-300-alpha-900": "rgba(248, 191, 197, 0.10)", + "c-primary-light-400": "rgb(249,204,209)", + "c-primary-light-400-alpha-100": "rgba(249, 204, 209, 0.90)", + "c-primary-light-400-alpha-200": "rgba(249, 204, 209, 0.80)", + "c-primary-light-400-alpha-300": "rgba(249, 204, 209, 0.70)", + "c-primary-light-400-alpha-400": "rgba(249, 204, 209, 0.60)", + "c-primary-light-400-alpha-500": "rgba(249, 204, 209, 0.50)", + "c-primary-light-400-alpha-600": "rgba(249, 204, 209, 0.40)", + "c-primary-light-400-alpha-700": "rgba(249, 204, 209, 0.30)", + "c-primary-light-400-alpha-800": "rgba(249, 204, 209, 0.20)", + "c-primary-light-400-alpha-900": "rgba(249, 204, 209, 0.10)", + "c-primary-light-500": "rgb(250,214,218)", + "c-primary-light-500-alpha-100": "rgba(250, 214, 218, 0.90)", + "c-primary-light-500-alpha-200": "rgba(250, 214, 218, 0.80)", + "c-primary-light-500-alpha-300": "rgba(250, 214, 218, 0.70)", + "c-primary-light-500-alpha-400": "rgba(250, 214, 218, 0.60)", + "c-primary-light-500-alpha-500": "rgba(250, 214, 218, 0.50)", + "c-primary-light-500-alpha-600": "rgba(250, 214, 218, 0.40)", + "c-primary-light-500-alpha-700": "rgba(250, 214, 218, 0.30)", + "c-primary-light-500-alpha-800": "rgba(250, 214, 218, 0.20)", + "c-primary-light-500-alpha-900": "rgba(250, 214, 218, 0.10)", + "c-primary-light-600": "rgb(251,222,225)", + "c-primary-light-600-alpha-100": "rgba(251, 222, 225, 0.90)", + "c-primary-light-600-alpha-200": "rgba(251, 222, 225, 0.80)", + "c-primary-light-600-alpha-300": "rgba(251, 222, 225, 0.70)", + "c-primary-light-600-alpha-400": "rgba(251, 222, 225, 0.60)", + "c-primary-light-600-alpha-500": "rgba(251, 222, 225, 0.50)", + "c-primary-light-600-alpha-600": "rgba(251, 222, 225, 0.40)", + "c-primary-light-600-alpha-700": "rgba(251, 222, 225, 0.30)", + "c-primary-light-600-alpha-800": "rgba(251, 222, 225, 0.20)", + "c-primary-light-600-alpha-900": "rgba(251, 222, 225, 0.10)", + "c-primary-light-700": "rgb(252,229,231)", + "c-primary-light-700-alpha-100": "rgba(252, 229, 231, 0.90)", + "c-primary-light-700-alpha-200": "rgba(252, 229, 231, 0.80)", + "c-primary-light-700-alpha-300": "rgba(252, 229, 231, 0.70)", + "c-primary-light-700-alpha-400": "rgba(252, 229, 231, 0.60)", + "c-primary-light-700-alpha-500": "rgba(252, 229, 231, 0.50)", + "c-primary-light-700-alpha-600": "rgba(252, 229, 231, 0.40)", + "c-primary-light-700-alpha-700": "rgba(252, 229, 231, 0.30)", + "c-primary-light-700-alpha-800": "rgba(252, 229, 231, 0.20)", + "c-primary-light-700-alpha-900": "rgba(252, 229, 231, 0.10)", + "c-primary-light-800": "rgb(253,234,236)", + "c-primary-light-800-alpha-100": "rgba(253, 234, 236, 0.90)", + "c-primary-light-800-alpha-200": "rgba(253, 234, 236, 0.80)", + "c-primary-light-800-alpha-300": "rgba(253, 234, 236, 0.70)", + "c-primary-light-800-alpha-400": "rgba(253, 234, 236, 0.60)", + "c-primary-light-800-alpha-500": "rgba(253, 234, 236, 0.50)", + "c-primary-light-800-alpha-600": "rgba(253, 234, 236, 0.40)", + "c-primary-light-800-alpha-700": "rgba(253, 234, 236, 0.30)", + "c-primary-light-800-alpha-800": "rgba(253, 234, 236, 0.20)", + "c-primary-light-800-alpha-900": "rgba(253, 234, 236, 0.10)", + "c-primary-light-900": "rgb(253,238,240)", + "c-primary-light-900-alpha-100": "rgba(253, 238, 240, 0.90)", + "c-primary-light-900-alpha-200": "rgba(253, 238, 240, 0.80)", + "c-primary-light-900-alpha-300": "rgba(253, 238, 240, 0.70)", + "c-primary-light-900-alpha-400": "rgba(253, 238, 240, 0.60)", + "c-primary-light-900-alpha-500": "rgba(253, 238, 240, 0.50)", + "c-primary-light-900-alpha-600": "rgba(253, 238, 240, 0.40)", + "c-primary-light-900-alpha-700": "rgba(253, 238, 240, 0.30)", + "c-primary-light-900-alpha-800": "rgba(253, 238, 240, 0.20)", + "c-primary-light-900-alpha-900": "rgba(253, 238, 240, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(241, 130, 141)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "var(c-primary-light-600-alpha-700)", + "c-main-background": "rgba(255, 255, 255, 1)", + "bg-image": "", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "#f5b684", + "c-badge-tertiary": "#f5b684" + } + } + }, + { + "id": "purple", + "name": "重斤球紫", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(155, 89, 182)", + "c-primary-dark-100": "rgb(140,80,164)", + "c-primary-dark-100-alpha-100": "rgba(140, 80, 164, 0.90)", + "c-primary-alpha-100": "rgba(155, 89, 182, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(140, 80, 164, 0.80)", + "c-primary-alpha-200": "rgba(155, 89, 182, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(140, 80, 164, 0.70)", + "c-primary-alpha-300": "rgba(155, 89, 182, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(140, 80, 164, 0.60)", + "c-primary-alpha-400": "rgba(155, 89, 182, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(140, 80, 164, 0.50)", + "c-primary-alpha-500": "rgba(155, 89, 182, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(140, 80, 164, 0.40)", + "c-primary-alpha-600": "rgba(155, 89, 182, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(140, 80, 164, 0.30)", + "c-primary-alpha-700": "rgba(155, 89, 182, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(140, 80, 164, 0.20)", + "c-primary-alpha-800": "rgba(155, 89, 182, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(140, 80, 164, 0.10)", + "c-primary-alpha-900": "rgba(155, 89, 182, 0.10)", + "c-primary-dark-200": "rgb(126,72,148)", + "c-primary-dark-200-alpha-100": "rgba(126, 72, 148, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(126, 72, 148, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(126, 72, 148, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(126, 72, 148, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(126, 72, 148, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(126, 72, 148, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(126, 72, 148, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(126, 72, 148, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(126, 72, 148, 0.10)", + "c-primary-dark-300": "rgb(113,65,133)", + "c-primary-dark-300-alpha-100": "rgba(113, 65, 133, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(113, 65, 133, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(113, 65, 133, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(113, 65, 133, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(113, 65, 133, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(113, 65, 133, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(113, 65, 133, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(113, 65, 133, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(113, 65, 133, 0.10)", + "c-primary-dark-400": "rgb(102,59,120)", + "c-primary-dark-400-alpha-100": "rgba(102, 59, 120, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(102, 59, 120, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(102, 59, 120, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(102, 59, 120, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(102, 59, 120, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(102, 59, 120, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(102, 59, 120, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(102, 59, 120, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(102, 59, 120, 0.10)", + "c-primary-dark-500": "rgb(92,53,108)", + "c-primary-dark-500-alpha-100": "rgba(92, 53, 108, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(92, 53, 108, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(92, 53, 108, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(92, 53, 108, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(92, 53, 108, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(92, 53, 108, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(92, 53, 108, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(92, 53, 108, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(92, 53, 108, 0.10)", + "c-primary-dark-600": "rgb(83,48,97)", + "c-primary-dark-600-alpha-100": "rgba(83, 48, 97, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(83, 48, 97, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(83, 48, 97, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(83, 48, 97, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(83, 48, 97, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(83, 48, 97, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(83, 48, 97, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(83, 48, 97, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(83, 48, 97, 0.10)", + "c-primary-dark-700": "rgb(75,43,87)", + "c-primary-dark-700-alpha-100": "rgba(75, 43, 87, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(75, 43, 87, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(75, 43, 87, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(75, 43, 87, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(75, 43, 87, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(75, 43, 87, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(75, 43, 87, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(75, 43, 87, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(75, 43, 87, 0.10)", + "c-primary-dark-800": "rgb(68,39,78)", + "c-primary-dark-800-alpha-100": "rgba(68, 39, 78, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(68, 39, 78, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(68, 39, 78, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(68, 39, 78, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(68, 39, 78, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(68, 39, 78, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(68, 39, 78, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(68, 39, 78, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(68, 39, 78, 0.10)", + "c-primary-dark-900": "rgb(61,35,70)", + "c-primary-dark-900-alpha-100": "rgba(61, 35, 70, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(61, 35, 70, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(61, 35, 70, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(61, 35, 70, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(61, 35, 70, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(61, 35, 70, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(61, 35, 70, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(61, 35, 70, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(61, 35, 70, 0.10)", + "c-primary-dark-1000": "rgb(55,32,63)", + "c-primary-dark-1000-alpha-100": "rgba(55, 32, 63, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(55, 32, 63, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(55, 32, 63, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(55, 32, 63, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(55, 32, 63, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(55, 32, 63, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(55, 32, 63, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(55, 32, 63, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(55, 32, 63, 0.10)", + "c-primary-light-100": "rgb(175,122,197)", + "c-primary-light-100-alpha-100": "rgba(175, 122, 197, 0.90)", + "c-primary-light-100-alpha-200": "rgba(175, 122, 197, 0.80)", + "c-primary-light-100-alpha-300": "rgba(175, 122, 197, 0.70)", + "c-primary-light-100-alpha-400": "rgba(175, 122, 197, 0.60)", + "c-primary-light-100-alpha-500": "rgba(175, 122, 197, 0.50)", + "c-primary-light-100-alpha-600": "rgba(175, 122, 197, 0.40)", + "c-primary-light-100-alpha-700": "rgba(175, 122, 197, 0.30)", + "c-primary-light-100-alpha-800": "rgba(175, 122, 197, 0.20)", + "c-primary-light-100-alpha-900": "rgba(175, 122, 197, 0.10)", + "c-primary-light-200": "rgb(191,149,209)", + "c-primary-light-200-alpha-100": "rgba(191, 149, 209, 0.90)", + "c-primary-light-200-alpha-200": "rgba(191, 149, 209, 0.80)", + "c-primary-light-200-alpha-300": "rgba(191, 149, 209, 0.70)", + "c-primary-light-200-alpha-400": "rgba(191, 149, 209, 0.60)", + "c-primary-light-200-alpha-500": "rgba(191, 149, 209, 0.50)", + "c-primary-light-200-alpha-600": "rgba(191, 149, 209, 0.40)", + "c-primary-light-200-alpha-700": "rgba(191, 149, 209, 0.30)", + "c-primary-light-200-alpha-800": "rgba(191, 149, 209, 0.20)", + "c-primary-light-200-alpha-900": "rgba(191, 149, 209, 0.10)", + "c-primary-light-300": "rgb(204,170,218)", + "c-primary-light-300-alpha-100": "rgba(204, 170, 218, 0.90)", + "c-primary-light-300-alpha-200": "rgba(204, 170, 218, 0.80)", + "c-primary-light-300-alpha-300": "rgba(204, 170, 218, 0.70)", + "c-primary-light-300-alpha-400": "rgba(204, 170, 218, 0.60)", + "c-primary-light-300-alpha-500": "rgba(204, 170, 218, 0.50)", + "c-primary-light-300-alpha-600": "rgba(204, 170, 218, 0.40)", + "c-primary-light-300-alpha-700": "rgba(204, 170, 218, 0.30)", + "c-primary-light-300-alpha-800": "rgba(204, 170, 218, 0.20)", + "c-primary-light-300-alpha-900": "rgba(204, 170, 218, 0.10)", + "c-primary-light-400": "rgb(214,187,225)", + "c-primary-light-400-alpha-100": "rgba(214, 187, 225, 0.90)", + "c-primary-light-400-alpha-200": "rgba(214, 187, 225, 0.80)", + "c-primary-light-400-alpha-300": "rgba(214, 187, 225, 0.70)", + "c-primary-light-400-alpha-400": "rgba(214, 187, 225, 0.60)", + "c-primary-light-400-alpha-500": "rgba(214, 187, 225, 0.50)", + "c-primary-light-400-alpha-600": "rgba(214, 187, 225, 0.40)", + "c-primary-light-400-alpha-700": "rgba(214, 187, 225, 0.30)", + "c-primary-light-400-alpha-800": "rgba(214, 187, 225, 0.20)", + "c-primary-light-400-alpha-900": "rgba(214, 187, 225, 0.10)", + "c-primary-light-500": "rgb(222,201,231)", + "c-primary-light-500-alpha-100": "rgba(222, 201, 231, 0.90)", + "c-primary-light-500-alpha-200": "rgba(222, 201, 231, 0.80)", + "c-primary-light-500-alpha-300": "rgba(222, 201, 231, 0.70)", + "c-primary-light-500-alpha-400": "rgba(222, 201, 231, 0.60)", + "c-primary-light-500-alpha-500": "rgba(222, 201, 231, 0.50)", + "c-primary-light-500-alpha-600": "rgba(222, 201, 231, 0.40)", + "c-primary-light-500-alpha-700": "rgba(222, 201, 231, 0.30)", + "c-primary-light-500-alpha-800": "rgba(222, 201, 231, 0.20)", + "c-primary-light-500-alpha-900": "rgba(222, 201, 231, 0.10)", + "c-primary-light-600": "rgb(229,212,236)", + "c-primary-light-600-alpha-100": "rgba(229, 212, 236, 0.90)", + "c-primary-light-600-alpha-200": "rgba(229, 212, 236, 0.80)", + "c-primary-light-600-alpha-300": "rgba(229, 212, 236, 0.70)", + "c-primary-light-600-alpha-400": "rgba(229, 212, 236, 0.60)", + "c-primary-light-600-alpha-500": "rgba(229, 212, 236, 0.50)", + "c-primary-light-600-alpha-600": "rgba(229, 212, 236, 0.40)", + "c-primary-light-600-alpha-700": "rgba(229, 212, 236, 0.30)", + "c-primary-light-600-alpha-800": "rgba(229, 212, 236, 0.20)", + "c-primary-light-600-alpha-900": "rgba(229, 212, 236, 0.10)", + "c-primary-light-700": "rgb(234,221,240)", + "c-primary-light-700-alpha-100": "rgba(234, 221, 240, 0.90)", + "c-primary-light-700-alpha-200": "rgba(234, 221, 240, 0.80)", + "c-primary-light-700-alpha-300": "rgba(234, 221, 240, 0.70)", + "c-primary-light-700-alpha-400": "rgba(234, 221, 240, 0.60)", + "c-primary-light-700-alpha-500": "rgba(234, 221, 240, 0.50)", + "c-primary-light-700-alpha-600": "rgba(234, 221, 240, 0.40)", + "c-primary-light-700-alpha-700": "rgba(234, 221, 240, 0.30)", + "c-primary-light-700-alpha-800": "rgba(234, 221, 240, 0.20)", + "c-primary-light-700-alpha-900": "rgba(234, 221, 240, 0.10)", + "c-primary-light-800": "rgb(238,228,243)", + "c-primary-light-800-alpha-100": "rgba(238, 228, 243, 0.90)", + "c-primary-light-800-alpha-200": "rgba(238, 228, 243, 0.80)", + "c-primary-light-800-alpha-300": "rgba(238, 228, 243, 0.70)", + "c-primary-light-800-alpha-400": "rgba(238, 228, 243, 0.60)", + "c-primary-light-800-alpha-500": "rgba(238, 228, 243, 0.50)", + "c-primary-light-800-alpha-600": "rgba(238, 228, 243, 0.40)", + "c-primary-light-800-alpha-700": "rgba(238, 228, 243, 0.30)", + "c-primary-light-800-alpha-800": "rgba(238, 228, 243, 0.20)", + "c-primary-light-800-alpha-900": "rgba(238, 228, 243, 0.10)", + "c-primary-light-900": "rgb(241,233,245)", + "c-primary-light-900-alpha-100": "rgba(241, 233, 245, 0.90)", + "c-primary-light-900-alpha-200": "rgba(241, 233, 245, 0.80)", + "c-primary-light-900-alpha-300": "rgba(241, 233, 245, 0.70)", + "c-primary-light-900-alpha-400": "rgba(241, 233, 245, 0.60)", + "c-primary-light-900-alpha-500": "rgba(241, 233, 245, 0.50)", + "c-primary-light-900-alpha-600": "rgba(241, 233, 245, 0.40)", + "c-primary-light-900-alpha-700": "rgba(241, 233, 245, 0.30)", + "c-primary-light-900-alpha-800": "rgba(241, 233, 245, 0.20)", + "c-primary-light-900-alpha-900": "rgba(241, 233, 245, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(155, 89, 182)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "var(c-primary-light-600-alpha-700)", + "c-main-background": "rgba(255, 255, 255, 1)", + "bg-image": "", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "#e5a39f", + "c-badge-tertiary": "#e5a39f" + } + } + }, + { + "id": "grey", + "name": "灰常美丽", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(108, 122, 137)", + "c-primary-dark-100": "rgb(97,110,123)", + "c-primary-dark-100-alpha-100": "rgba(97, 110, 123, 0.90)", + "c-primary-alpha-100": "rgba(108, 122, 137, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(97, 110, 123, 0.80)", + "c-primary-alpha-200": "rgba(108, 122, 137, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(97, 110, 123, 0.70)", + "c-primary-alpha-300": "rgba(108, 122, 137, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(97, 110, 123, 0.60)", + "c-primary-alpha-400": "rgba(108, 122, 137, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(97, 110, 123, 0.50)", + "c-primary-alpha-500": "rgba(108, 122, 137, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(97, 110, 123, 0.40)", + "c-primary-alpha-600": "rgba(108, 122, 137, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(97, 110, 123, 0.30)", + "c-primary-alpha-700": "rgba(108, 122, 137, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(97, 110, 123, 0.20)", + "c-primary-alpha-800": "rgba(108, 122, 137, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(97, 110, 123, 0.10)", + "c-primary-alpha-900": "rgba(108, 122, 137, 0.10)", + "c-primary-dark-200": "rgb(87,99,111)", + "c-primary-dark-200-alpha-100": "rgba(87, 99, 111, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(87, 99, 111, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(87, 99, 111, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(87, 99, 111, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(87, 99, 111, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(87, 99, 111, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(87, 99, 111, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(87, 99, 111, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(87, 99, 111, 0.10)", + "c-primary-dark-300": "rgb(78,89,100)", + "c-primary-dark-300-alpha-100": "rgba(78, 89, 100, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(78, 89, 100, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(78, 89, 100, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(78, 89, 100, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(78, 89, 100, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(78, 89, 100, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(78, 89, 100, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(78, 89, 100, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(78, 89, 100, 0.10)", + "c-primary-dark-400": "rgb(70,80,90)", + "c-primary-dark-400-alpha-100": "rgba(70, 80, 90, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(70, 80, 90, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(70, 80, 90, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(70, 80, 90, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(70, 80, 90, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(70, 80, 90, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(70, 80, 90, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(70, 80, 90, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(70, 80, 90, 0.10)", + "c-primary-dark-500": "rgb(63,72,81)", + "c-primary-dark-500-alpha-100": "rgba(63, 72, 81, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(63, 72, 81, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(63, 72, 81, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(63, 72, 81, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(63, 72, 81, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(63, 72, 81, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(63, 72, 81, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(63, 72, 81, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(63, 72, 81, 0.10)", + "c-primary-dark-600": "rgb(57,65,73)", + "c-primary-dark-600-alpha-100": "rgba(57, 65, 73, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(57, 65, 73, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(57, 65, 73, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(57, 65, 73, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(57, 65, 73, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(57, 65, 73, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(57, 65, 73, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(57, 65, 73, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(57, 65, 73, 0.10)", + "c-primary-dark-700": "rgb(51,59,66)", + "c-primary-dark-700-alpha-100": "rgba(51, 59, 66, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(51, 59, 66, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(51, 59, 66, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(51, 59, 66, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(51, 59, 66, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(51, 59, 66, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(51, 59, 66, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(51, 59, 66, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(51, 59, 66, 0.10)", + "c-primary-dark-800": "rgb(46,53,59)", + "c-primary-dark-800-alpha-100": "rgba(46, 53, 59, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(46, 53, 59, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(46, 53, 59, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(46, 53, 59, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(46, 53, 59, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(46, 53, 59, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(46, 53, 59, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(46, 53, 59, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(46, 53, 59, 0.10)", + "c-primary-dark-900": "rgb(41,48,53)", + "c-primary-dark-900-alpha-100": "rgba(41, 48, 53, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(41, 48, 53, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(41, 48, 53, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(41, 48, 53, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(41, 48, 53, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(41, 48, 53, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(41, 48, 53, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(41, 48, 53, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(41, 48, 53, 0.10)", + "c-primary-dark-1000": "rgb(37,43,48)", + "c-primary-dark-1000-alpha-100": "rgba(37, 43, 48, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(37, 43, 48, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(37, 43, 48, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(37, 43, 48, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(37, 43, 48, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(37, 43, 48, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(37, 43, 48, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(37, 43, 48, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(37, 43, 48, 0.10)", + "c-primary-light-100": "rgb(137,149,161)", + "c-primary-light-100-alpha-100": "rgba(137, 149, 161, 0.90)", + "c-primary-light-100-alpha-200": "rgba(137, 149, 161, 0.80)", + "c-primary-light-100-alpha-300": "rgba(137, 149, 161, 0.70)", + "c-primary-light-100-alpha-400": "rgba(137, 149, 161, 0.60)", + "c-primary-light-100-alpha-500": "rgba(137, 149, 161, 0.50)", + "c-primary-light-100-alpha-600": "rgba(137, 149, 161, 0.40)", + "c-primary-light-100-alpha-700": "rgba(137, 149, 161, 0.30)", + "c-primary-light-100-alpha-800": "rgba(137, 149, 161, 0.20)", + "c-primary-light-100-alpha-900": "rgba(137, 149, 161, 0.10)", + "c-primary-light-200": "rgb(161,170,180)", + "c-primary-light-200-alpha-100": "rgba(161, 170, 180, 0.90)", + "c-primary-light-200-alpha-200": "rgba(161, 170, 180, 0.80)", + "c-primary-light-200-alpha-300": "rgba(161, 170, 180, 0.70)", + "c-primary-light-200-alpha-400": "rgba(161, 170, 180, 0.60)", + "c-primary-light-200-alpha-500": "rgba(161, 170, 180, 0.50)", + "c-primary-light-200-alpha-600": "rgba(161, 170, 180, 0.40)", + "c-primary-light-200-alpha-700": "rgba(161, 170, 180, 0.30)", + "c-primary-light-200-alpha-800": "rgba(161, 170, 180, 0.20)", + "c-primary-light-200-alpha-900": "rgba(161, 170, 180, 0.10)", + "c-primary-light-300": "rgb(180,187,195)", + "c-primary-light-300-alpha-100": "rgba(180, 187, 195, 0.90)", + "c-primary-light-300-alpha-200": "rgba(180, 187, 195, 0.80)", + "c-primary-light-300-alpha-300": "rgba(180, 187, 195, 0.70)", + "c-primary-light-300-alpha-400": "rgba(180, 187, 195, 0.60)", + "c-primary-light-300-alpha-500": "rgba(180, 187, 195, 0.50)", + "c-primary-light-300-alpha-600": "rgba(180, 187, 195, 0.40)", + "c-primary-light-300-alpha-700": "rgba(180, 187, 195, 0.30)", + "c-primary-light-300-alpha-800": "rgba(180, 187, 195, 0.20)", + "c-primary-light-300-alpha-900": "rgba(180, 187, 195, 0.10)", + "c-primary-light-400": "rgb(195,201,207)", + "c-primary-light-400-alpha-100": "rgba(195, 201, 207, 0.90)", + "c-primary-light-400-alpha-200": "rgba(195, 201, 207, 0.80)", + "c-primary-light-400-alpha-300": "rgba(195, 201, 207, 0.70)", + "c-primary-light-400-alpha-400": "rgba(195, 201, 207, 0.60)", + "c-primary-light-400-alpha-500": "rgba(195, 201, 207, 0.50)", + "c-primary-light-400-alpha-600": "rgba(195, 201, 207, 0.40)", + "c-primary-light-400-alpha-700": "rgba(195, 201, 207, 0.30)", + "c-primary-light-400-alpha-800": "rgba(195, 201, 207, 0.20)", + "c-primary-light-400-alpha-900": "rgba(195, 201, 207, 0.10)", + "c-primary-light-500": "rgb(207,212,217)", + "c-primary-light-500-alpha-100": "rgba(207, 212, 217, 0.90)", + "c-primary-light-500-alpha-200": "rgba(207, 212, 217, 0.80)", + "c-primary-light-500-alpha-300": "rgba(207, 212, 217, 0.70)", + "c-primary-light-500-alpha-400": "rgba(207, 212, 217, 0.60)", + "c-primary-light-500-alpha-500": "rgba(207, 212, 217, 0.50)", + "c-primary-light-500-alpha-600": "rgba(207, 212, 217, 0.40)", + "c-primary-light-500-alpha-700": "rgba(207, 212, 217, 0.30)", + "c-primary-light-500-alpha-800": "rgba(207, 212, 217, 0.20)", + "c-primary-light-500-alpha-900": "rgba(207, 212, 217, 0.10)", + "c-primary-light-600": "rgb(217,221,225)", + "c-primary-light-600-alpha-100": "rgba(217, 221, 225, 0.90)", + "c-primary-light-600-alpha-200": "rgba(217, 221, 225, 0.80)", + "c-primary-light-600-alpha-300": "rgba(217, 221, 225, 0.70)", + "c-primary-light-600-alpha-400": "rgba(217, 221, 225, 0.60)", + "c-primary-light-600-alpha-500": "rgba(217, 221, 225, 0.50)", + "c-primary-light-600-alpha-600": "rgba(217, 221, 225, 0.40)", + "c-primary-light-600-alpha-700": "rgba(217, 221, 225, 0.30)", + "c-primary-light-600-alpha-800": "rgba(217, 221, 225, 0.20)", + "c-primary-light-600-alpha-900": "rgba(217, 221, 225, 0.10)", + "c-primary-light-700": "rgb(225,228,231)", + "c-primary-light-700-alpha-100": "rgba(225, 228, 231, 0.90)", + "c-primary-light-700-alpha-200": "rgba(225, 228, 231, 0.80)", + "c-primary-light-700-alpha-300": "rgba(225, 228, 231, 0.70)", + "c-primary-light-700-alpha-400": "rgba(225, 228, 231, 0.60)", + "c-primary-light-700-alpha-500": "rgba(225, 228, 231, 0.50)", + "c-primary-light-700-alpha-600": "rgba(225, 228, 231, 0.40)", + "c-primary-light-700-alpha-700": "rgba(225, 228, 231, 0.30)", + "c-primary-light-700-alpha-800": "rgba(225, 228, 231, 0.20)", + "c-primary-light-700-alpha-900": "rgba(225, 228, 231, 0.10)", + "c-primary-light-800": "rgb(231,233,236)", + "c-primary-light-800-alpha-100": "rgba(231, 233, 236, 0.90)", + "c-primary-light-800-alpha-200": "rgba(231, 233, 236, 0.80)", + "c-primary-light-800-alpha-300": "rgba(231, 233, 236, 0.70)", + "c-primary-light-800-alpha-400": "rgba(231, 233, 236, 0.60)", + "c-primary-light-800-alpha-500": "rgba(231, 233, 236, 0.50)", + "c-primary-light-800-alpha-600": "rgba(231, 233, 236, 0.40)", + "c-primary-light-800-alpha-700": "rgba(231, 233, 236, 0.30)", + "c-primary-light-800-alpha-800": "rgba(231, 233, 236, 0.20)", + "c-primary-light-800-alpha-900": "rgba(231, 233, 236, 0.10)", + "c-primary-light-900": "rgb(236,237,240)", + "c-primary-light-900-alpha-100": "rgba(236, 237, 240, 0.90)", + "c-primary-light-900-alpha-200": "rgba(236, 237, 240, 0.80)", + "c-primary-light-900-alpha-300": "rgba(236, 237, 240, 0.70)", + "c-primary-light-900-alpha-400": "rgba(236, 237, 240, 0.60)", + "c-primary-light-900-alpha-500": "rgba(236, 237, 240, 0.50)", + "c-primary-light-900-alpha-600": "rgba(236, 237, 240, 0.40)", + "c-primary-light-900-alpha-700": "rgba(236, 237, 240, 0.30)", + "c-primary-light-900-alpha-800": "rgba(236, 237, 240, 0.20)", + "c-primary-light-900-alpha-900": "rgba(236, 237, 240, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(108, 122, 137)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "var(c-primary-light-600-alpha-700)", + "c-main-background": "rgba(255, 255, 255, 1)", + "bg-image": "", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "#b19b9f", + "c-badge-tertiary": "#b19b9f" + } + } + }, + { + "id": "ming", + "name": "青出于黑", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(51, 110, 123)", + "c-primary-dark-100": "rgb(46,99,111)", + "c-primary-dark-100-alpha-100": "rgba(46, 99, 111, 0.90)", + "c-primary-alpha-100": "rgba(51, 110, 123, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(46, 99, 111, 0.80)", + "c-primary-alpha-200": "rgba(51, 110, 123, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(46, 99, 111, 0.70)", + "c-primary-alpha-300": "rgba(51, 110, 123, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(46, 99, 111, 0.60)", + "c-primary-alpha-400": "rgba(51, 110, 123, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(46, 99, 111, 0.50)", + "c-primary-alpha-500": "rgba(51, 110, 123, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(46, 99, 111, 0.40)", + "c-primary-alpha-600": "rgba(51, 110, 123, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(46, 99, 111, 0.30)", + "c-primary-alpha-700": "rgba(51, 110, 123, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(46, 99, 111, 0.20)", + "c-primary-alpha-800": "rgba(51, 110, 123, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(46, 99, 111, 0.10)", + "c-primary-alpha-900": "rgba(51, 110, 123, 0.10)", + "c-primary-dark-200": "rgb(41,89,100)", + "c-primary-dark-200-alpha-100": "rgba(41, 89, 100, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(41, 89, 100, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(41, 89, 100, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(41, 89, 100, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(41, 89, 100, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(41, 89, 100, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(41, 89, 100, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(41, 89, 100, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(41, 89, 100, 0.10)", + "c-primary-dark-300": "rgb(37,80,90)", + "c-primary-dark-300-alpha-100": "rgba(37, 80, 90, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(37, 80, 90, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(37, 80, 90, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(37, 80, 90, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(37, 80, 90, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(37, 80, 90, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(37, 80, 90, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(37, 80, 90, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(37, 80, 90, 0.10)", + "c-primary-dark-400": "rgb(33,72,81)", + "c-primary-dark-400-alpha-100": "rgba(33, 72, 81, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(33, 72, 81, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(33, 72, 81, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(33, 72, 81, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(33, 72, 81, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(33, 72, 81, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(33, 72, 81, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(33, 72, 81, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(33, 72, 81, 0.10)", + "c-primary-dark-500": "rgb(30,65,73)", + "c-primary-dark-500-alpha-100": "rgba(30, 65, 73, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(30, 65, 73, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(30, 65, 73, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(30, 65, 73, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(30, 65, 73, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(30, 65, 73, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(30, 65, 73, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(30, 65, 73, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(30, 65, 73, 0.10)", + "c-primary-dark-600": "rgb(27,59,66)", + "c-primary-dark-600-alpha-100": "rgba(27, 59, 66, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(27, 59, 66, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(27, 59, 66, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(27, 59, 66, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(27, 59, 66, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(27, 59, 66, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(27, 59, 66, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(27, 59, 66, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(27, 59, 66, 0.10)", + "c-primary-dark-700": "rgb(24,53,59)", + "c-primary-dark-700-alpha-100": "rgba(24, 53, 59, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(24, 53, 59, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(24, 53, 59, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(24, 53, 59, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(24, 53, 59, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(24, 53, 59, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(24, 53, 59, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(24, 53, 59, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(24, 53, 59, 0.10)", + "c-primary-dark-800": "rgb(22,48,53)", + "c-primary-dark-800-alpha-100": "rgba(22, 48, 53, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(22, 48, 53, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(22, 48, 53, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(22, 48, 53, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(22, 48, 53, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(22, 48, 53, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(22, 48, 53, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(22, 48, 53, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(22, 48, 53, 0.10)", + "c-primary-dark-900": "rgb(20,43,48)", + "c-primary-dark-900-alpha-100": "rgba(20, 43, 48, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(20, 43, 48, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(20, 43, 48, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(20, 43, 48, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(20, 43, 48, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(20, 43, 48, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(20, 43, 48, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(20, 43, 48, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(20, 43, 48, 0.10)", + "c-primary-dark-1000": "rgb(18,39,43)", + "c-primary-dark-1000-alpha-100": "rgba(18, 39, 43, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(18, 39, 43, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(18, 39, 43, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(18, 39, 43, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(18, 39, 43, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(18, 39, 43, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(18, 39, 43, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(18, 39, 43, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(18, 39, 43, 0.10)", + "c-primary-light-100": "rgb(92,139,149)", + "c-primary-light-100-alpha-100": "rgba(92, 139, 149, 0.90)", + "c-primary-light-100-alpha-200": "rgba(92, 139, 149, 0.80)", + "c-primary-light-100-alpha-300": "rgba(92, 139, 149, 0.70)", + "c-primary-light-100-alpha-400": "rgba(92, 139, 149, 0.60)", + "c-primary-light-100-alpha-500": "rgba(92, 139, 149, 0.50)", + "c-primary-light-100-alpha-600": "rgba(92, 139, 149, 0.40)", + "c-primary-light-100-alpha-700": "rgba(92, 139, 149, 0.30)", + "c-primary-light-100-alpha-800": "rgba(92, 139, 149, 0.20)", + "c-primary-light-100-alpha-900": "rgba(92, 139, 149, 0.10)", + "c-primary-light-200": "rgb(125,162,170)", + "c-primary-light-200-alpha-100": "rgba(125, 162, 170, 0.90)", + "c-primary-light-200-alpha-200": "rgba(125, 162, 170, 0.80)", + "c-primary-light-200-alpha-300": "rgba(125, 162, 170, 0.70)", + "c-primary-light-200-alpha-400": "rgba(125, 162, 170, 0.60)", + "c-primary-light-200-alpha-500": "rgba(125, 162, 170, 0.50)", + "c-primary-light-200-alpha-600": "rgba(125, 162, 170, 0.40)", + "c-primary-light-200-alpha-700": "rgba(125, 162, 170, 0.30)", + "c-primary-light-200-alpha-800": "rgba(125, 162, 170, 0.20)", + "c-primary-light-200-alpha-900": "rgba(125, 162, 170, 0.10)", + "c-primary-light-300": "rgb(151,181,187)", + "c-primary-light-300-alpha-100": "rgba(151, 181, 187, 0.90)", + "c-primary-light-300-alpha-200": "rgba(151, 181, 187, 0.80)", + "c-primary-light-300-alpha-300": "rgba(151, 181, 187, 0.70)", + "c-primary-light-300-alpha-400": "rgba(151, 181, 187, 0.60)", + "c-primary-light-300-alpha-500": "rgba(151, 181, 187, 0.50)", + "c-primary-light-300-alpha-600": "rgba(151, 181, 187, 0.40)", + "c-primary-light-300-alpha-700": "rgba(151, 181, 187, 0.30)", + "c-primary-light-300-alpha-800": "rgba(151, 181, 187, 0.20)", + "c-primary-light-300-alpha-900": "rgba(151, 181, 187, 0.10)", + "c-primary-light-400": "rgb(172,196,201)", + "c-primary-light-400-alpha-100": "rgba(172, 196, 201, 0.90)", + "c-primary-light-400-alpha-200": "rgba(172, 196, 201, 0.80)", + "c-primary-light-400-alpha-300": "rgba(172, 196, 201, 0.70)", + "c-primary-light-400-alpha-400": "rgba(172, 196, 201, 0.60)", + "c-primary-light-400-alpha-500": "rgba(172, 196, 201, 0.50)", + "c-primary-light-400-alpha-600": "rgba(172, 196, 201, 0.40)", + "c-primary-light-400-alpha-700": "rgba(172, 196, 201, 0.30)", + "c-primary-light-400-alpha-800": "rgba(172, 196, 201, 0.20)", + "c-primary-light-400-alpha-900": "rgba(172, 196, 201, 0.10)", + "c-primary-light-500": "rgb(189,208,212)", + "c-primary-light-500-alpha-100": "rgba(189, 208, 212, 0.90)", + "c-primary-light-500-alpha-200": "rgba(189, 208, 212, 0.80)", + "c-primary-light-500-alpha-300": "rgba(189, 208, 212, 0.70)", + "c-primary-light-500-alpha-400": "rgba(189, 208, 212, 0.60)", + "c-primary-light-500-alpha-500": "rgba(189, 208, 212, 0.50)", + "c-primary-light-500-alpha-600": "rgba(189, 208, 212, 0.40)", + "c-primary-light-500-alpha-700": "rgba(189, 208, 212, 0.30)", + "c-primary-light-500-alpha-800": "rgba(189, 208, 212, 0.20)", + "c-primary-light-500-alpha-900": "rgba(189, 208, 212, 0.10)", + "c-primary-light-600": "rgb(202,217,221)", + "c-primary-light-600-alpha-100": "rgba(202, 217, 221, 0.90)", + "c-primary-light-600-alpha-200": "rgba(202, 217, 221, 0.80)", + "c-primary-light-600-alpha-300": "rgba(202, 217, 221, 0.70)", + "c-primary-light-600-alpha-400": "rgba(202, 217, 221, 0.60)", + "c-primary-light-600-alpha-500": "rgba(202, 217, 221, 0.50)", + "c-primary-light-600-alpha-600": "rgba(202, 217, 221, 0.40)", + "c-primary-light-600-alpha-700": "rgba(202, 217, 221, 0.30)", + "c-primary-light-600-alpha-800": "rgba(202, 217, 221, 0.20)", + "c-primary-light-600-alpha-900": "rgba(202, 217, 221, 0.10)", + "c-primary-light-700": "rgb(213,225,228)", + "c-primary-light-700-alpha-100": "rgba(213, 225, 228, 0.90)", + "c-primary-light-700-alpha-200": "rgba(213, 225, 228, 0.80)", + "c-primary-light-700-alpha-300": "rgba(213, 225, 228, 0.70)", + "c-primary-light-700-alpha-400": "rgba(213, 225, 228, 0.60)", + "c-primary-light-700-alpha-500": "rgba(213, 225, 228, 0.50)", + "c-primary-light-700-alpha-600": "rgba(213, 225, 228, 0.40)", + "c-primary-light-700-alpha-700": "rgba(213, 225, 228, 0.30)", + "c-primary-light-700-alpha-800": "rgba(213, 225, 228, 0.20)", + "c-primary-light-700-alpha-900": "rgba(213, 225, 228, 0.10)", + "c-primary-light-800": "rgb(221,231,233)", + "c-primary-light-800-alpha-100": "rgba(221, 231, 233, 0.90)", + "c-primary-light-800-alpha-200": "rgba(221, 231, 233, 0.80)", + "c-primary-light-800-alpha-300": "rgba(221, 231, 233, 0.70)", + "c-primary-light-800-alpha-400": "rgba(221, 231, 233, 0.60)", + "c-primary-light-800-alpha-500": "rgba(221, 231, 233, 0.50)", + "c-primary-light-800-alpha-600": "rgba(221, 231, 233, 0.40)", + "c-primary-light-800-alpha-700": "rgba(221, 231, 233, 0.30)", + "c-primary-light-800-alpha-800": "rgba(221, 231, 233, 0.20)", + "c-primary-light-800-alpha-900": "rgba(221, 231, 233, 0.10)", + "c-primary-light-900": "rgb(228,236,237)", + "c-primary-light-900-alpha-100": "rgba(228, 236, 237, 0.90)", + "c-primary-light-900-alpha-200": "rgba(228, 236, 237, 0.80)", + "c-primary-light-900-alpha-300": "rgba(228, 236, 237, 0.70)", + "c-primary-light-900-alpha-400": "rgba(228, 236, 237, 0.60)", + "c-primary-light-900-alpha-500": "rgba(228, 236, 237, 0.50)", + "c-primary-light-900-alpha-600": "rgba(228, 236, 237, 0.40)", + "c-primary-light-900-alpha-700": "rgba(228, 236, 237, 0.30)", + "c-primary-light-900-alpha-800": "rgba(228, 236, 237, 0.20)", + "c-primary-light-900-alpha-900": "rgba(228, 236, 237, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(51, 110, 123)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "var(c-primary-light-600-alpha-700)", + "c-main-background": "rgba(255, 255, 255, 1)", + "bg-image": "", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "#6376a2", + "c-badge-tertiary": "#6376a2" + } + } + }, + { + "id": "blue2", + "name": "清热板蓝", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(79, 98, 208)", + "c-primary-dark-100": "rgb(71,88,187)", + "c-primary-dark-100-alpha-100": "rgba(71, 88, 187, 0.90)", + "c-primary-alpha-100": "rgba(79, 98, 208, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(71, 88, 187, 0.80)", + "c-primary-alpha-200": "rgba(79, 98, 208, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(71, 88, 187, 0.70)", + "c-primary-alpha-300": "rgba(79, 98, 208, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(71, 88, 187, 0.60)", + "c-primary-alpha-400": "rgba(79, 98, 208, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(71, 88, 187, 0.50)", + "c-primary-alpha-500": "rgba(79, 98, 208, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(71, 88, 187, 0.40)", + "c-primary-alpha-600": "rgba(79, 98, 208, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(71, 88, 187, 0.30)", + "c-primary-alpha-700": "rgba(79, 98, 208, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(71, 88, 187, 0.20)", + "c-primary-alpha-800": "rgba(79, 98, 208, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(71, 88, 187, 0.10)", + "c-primary-alpha-900": "rgba(79, 98, 208, 0.10)", + "c-primary-dark-200": "rgb(64,79,168)", + "c-primary-dark-200-alpha-100": "rgba(64, 79, 168, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(64, 79, 168, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(64, 79, 168, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(64, 79, 168, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(64, 79, 168, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(64, 79, 168, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(64, 79, 168, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(64, 79, 168, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(64, 79, 168, 0.10)", + "c-primary-dark-300": "rgb(58,71,151)", + "c-primary-dark-300-alpha-100": "rgba(58, 71, 151, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(58, 71, 151, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(58, 71, 151, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(58, 71, 151, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(58, 71, 151, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(58, 71, 151, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(58, 71, 151, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(58, 71, 151, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(58, 71, 151, 0.10)", + "c-primary-dark-400": "rgb(52,64,136)", + "c-primary-dark-400-alpha-100": "rgba(52, 64, 136, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(52, 64, 136, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(52, 64, 136, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(52, 64, 136, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(52, 64, 136, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(52, 64, 136, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(52, 64, 136, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(52, 64, 136, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(52, 64, 136, 0.10)", + "c-primary-dark-500": "rgb(47,58,122)", + "c-primary-dark-500-alpha-100": "rgba(47, 58, 122, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(47, 58, 122, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(47, 58, 122, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(47, 58, 122, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(47, 58, 122, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(47, 58, 122, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(47, 58, 122, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(47, 58, 122, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(47, 58, 122, 0.10)", + "c-primary-dark-600": "rgb(42,52,110)", + "c-primary-dark-600-alpha-100": "rgba(42, 52, 110, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(42, 52, 110, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(42, 52, 110, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(42, 52, 110, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(42, 52, 110, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(42, 52, 110, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(42, 52, 110, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(42, 52, 110, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(42, 52, 110, 0.10)", + "c-primary-dark-700": "rgb(38,47,99)", + "c-primary-dark-700-alpha-100": "rgba(38, 47, 99, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(38, 47, 99, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(38, 47, 99, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(38, 47, 99, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(38, 47, 99, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(38, 47, 99, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(38, 47, 99, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(38, 47, 99, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(38, 47, 99, 0.10)", + "c-primary-dark-800": "rgb(34,42,89)", + "c-primary-dark-800-alpha-100": "rgba(34, 42, 89, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(34, 42, 89, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(34, 42, 89, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(34, 42, 89, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(34, 42, 89, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(34, 42, 89, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(34, 42, 89, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(34, 42, 89, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(34, 42, 89, 0.10)", + "c-primary-dark-900": "rgb(31,38,80)", + "c-primary-dark-900-alpha-100": "rgba(31, 38, 80, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(31, 38, 80, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(31, 38, 80, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(31, 38, 80, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(31, 38, 80, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(31, 38, 80, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(31, 38, 80, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(31, 38, 80, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(31, 38, 80, 0.10)", + "c-primary-dark-1000": "rgb(28,34,72)", + "c-primary-dark-1000-alpha-100": "rgba(28, 34, 72, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(28, 34, 72, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(28, 34, 72, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(28, 34, 72, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(28, 34, 72, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(28, 34, 72, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(28, 34, 72, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(28, 34, 72, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(28, 34, 72, 0.10)", + "c-primary-light-100": "rgb(114,129,217)", + "c-primary-light-100-alpha-100": "rgba(114, 129, 217, 0.90)", + "c-primary-light-100-alpha-200": "rgba(114, 129, 217, 0.80)", + "c-primary-light-100-alpha-300": "rgba(114, 129, 217, 0.70)", + "c-primary-light-100-alpha-400": "rgba(114, 129, 217, 0.60)", + "c-primary-light-100-alpha-500": "rgba(114, 129, 217, 0.50)", + "c-primary-light-100-alpha-600": "rgba(114, 129, 217, 0.40)", + "c-primary-light-100-alpha-700": "rgba(114, 129, 217, 0.30)", + "c-primary-light-100-alpha-800": "rgba(114, 129, 217, 0.20)", + "c-primary-light-100-alpha-900": "rgba(114, 129, 217, 0.10)", + "c-primary-light-200": "rgb(142,154,225)", + "c-primary-light-200-alpha-100": "rgba(142, 154, 225, 0.90)", + "c-primary-light-200-alpha-200": "rgba(142, 154, 225, 0.80)", + "c-primary-light-200-alpha-300": "rgba(142, 154, 225, 0.70)", + "c-primary-light-200-alpha-400": "rgba(142, 154, 225, 0.60)", + "c-primary-light-200-alpha-500": "rgba(142, 154, 225, 0.50)", + "c-primary-light-200-alpha-600": "rgba(142, 154, 225, 0.40)", + "c-primary-light-200-alpha-700": "rgba(142, 154, 225, 0.30)", + "c-primary-light-200-alpha-800": "rgba(142, 154, 225, 0.20)", + "c-primary-light-200-alpha-900": "rgba(142, 154, 225, 0.10)", + "c-primary-light-300": "rgb(165,174,231)", + "c-primary-light-300-alpha-100": "rgba(165, 174, 231, 0.90)", + "c-primary-light-300-alpha-200": "rgba(165, 174, 231, 0.80)", + "c-primary-light-300-alpha-300": "rgba(165, 174, 231, 0.70)", + "c-primary-light-300-alpha-400": "rgba(165, 174, 231, 0.60)", + "c-primary-light-300-alpha-500": "rgba(165, 174, 231, 0.50)", + "c-primary-light-300-alpha-600": "rgba(165, 174, 231, 0.40)", + "c-primary-light-300-alpha-700": "rgba(165, 174, 231, 0.30)", + "c-primary-light-300-alpha-800": "rgba(165, 174, 231, 0.20)", + "c-primary-light-300-alpha-900": "rgba(165, 174, 231, 0.10)", + "c-primary-light-400": "rgb(183,190,236)", + "c-primary-light-400-alpha-100": "rgba(183, 190, 236, 0.90)", + "c-primary-light-400-alpha-200": "rgba(183, 190, 236, 0.80)", + "c-primary-light-400-alpha-300": "rgba(183, 190, 236, 0.70)", + "c-primary-light-400-alpha-400": "rgba(183, 190, 236, 0.60)", + "c-primary-light-400-alpha-500": "rgba(183, 190, 236, 0.50)", + "c-primary-light-400-alpha-600": "rgba(183, 190, 236, 0.40)", + "c-primary-light-400-alpha-700": "rgba(183, 190, 236, 0.30)", + "c-primary-light-400-alpha-800": "rgba(183, 190, 236, 0.20)", + "c-primary-light-400-alpha-900": "rgba(183, 190, 236, 0.10)", + "c-primary-light-500": "rgb(197,203,240)", + "c-primary-light-500-alpha-100": "rgba(197, 203, 240, 0.90)", + "c-primary-light-500-alpha-200": "rgba(197, 203, 240, 0.80)", + "c-primary-light-500-alpha-300": "rgba(197, 203, 240, 0.70)", + "c-primary-light-500-alpha-400": "rgba(197, 203, 240, 0.60)", + "c-primary-light-500-alpha-500": "rgba(197, 203, 240, 0.50)", + "c-primary-light-500-alpha-600": "rgba(197, 203, 240, 0.40)", + "c-primary-light-500-alpha-700": "rgba(197, 203, 240, 0.30)", + "c-primary-light-500-alpha-800": "rgba(197, 203, 240, 0.20)", + "c-primary-light-500-alpha-900": "rgba(197, 203, 240, 0.10)", + "c-primary-light-600": "rgb(209,213,243)", + "c-primary-light-600-alpha-100": "rgba(209, 213, 243, 0.90)", + "c-primary-light-600-alpha-200": "rgba(209, 213, 243, 0.80)", + "c-primary-light-600-alpha-300": "rgba(209, 213, 243, 0.70)", + "c-primary-light-600-alpha-400": "rgba(209, 213, 243, 0.60)", + "c-primary-light-600-alpha-500": "rgba(209, 213, 243, 0.50)", + "c-primary-light-600-alpha-600": "rgba(209, 213, 243, 0.40)", + "c-primary-light-600-alpha-700": "rgba(209, 213, 243, 0.30)", + "c-primary-light-600-alpha-800": "rgba(209, 213, 243, 0.20)", + "c-primary-light-600-alpha-900": "rgba(209, 213, 243, 0.10)", + "c-primary-light-700": "rgb(218,221,245)", + "c-primary-light-700-alpha-100": "rgba(218, 221, 245, 0.90)", + "c-primary-light-700-alpha-200": "rgba(218, 221, 245, 0.80)", + "c-primary-light-700-alpha-300": "rgba(218, 221, 245, 0.70)", + "c-primary-light-700-alpha-400": "rgba(218, 221, 245, 0.60)", + "c-primary-light-700-alpha-500": "rgba(218, 221, 245, 0.50)", + "c-primary-light-700-alpha-600": "rgba(218, 221, 245, 0.40)", + "c-primary-light-700-alpha-700": "rgba(218, 221, 245, 0.30)", + "c-primary-light-700-alpha-800": "rgba(218, 221, 245, 0.20)", + "c-primary-light-700-alpha-900": "rgba(218, 221, 245, 0.10)", + "c-primary-light-800": "rgb(225,228,247)", + "c-primary-light-800-alpha-100": "rgba(225, 228, 247, 0.90)", + "c-primary-light-800-alpha-200": "rgba(225, 228, 247, 0.80)", + "c-primary-light-800-alpha-300": "rgba(225, 228, 247, 0.70)", + "c-primary-light-800-alpha-400": "rgba(225, 228, 247, 0.60)", + "c-primary-light-800-alpha-500": "rgba(225, 228, 247, 0.50)", + "c-primary-light-800-alpha-600": "rgba(225, 228, 247, 0.40)", + "c-primary-light-800-alpha-700": "rgba(225, 228, 247, 0.30)", + "c-primary-light-800-alpha-800": "rgba(225, 228, 247, 0.20)", + "c-primary-light-800-alpha-900": "rgba(225, 228, 247, 0.10)", + "c-primary-light-900": "rgb(231,233,249)", + "c-primary-light-900-alpha-100": "rgba(231, 233, 249, 0.90)", + "c-primary-light-900-alpha-200": "rgba(231, 233, 249, 0.80)", + "c-primary-light-900-alpha-300": "rgba(231, 233, 249, 0.70)", + "c-primary-light-900-alpha-400": "rgba(231, 233, 249, 0.60)", + "c-primary-light-900-alpha-500": "rgba(231, 233, 249, 0.50)", + "c-primary-light-900-alpha-600": "rgba(231, 233, 249, 0.40)", + "c-primary-light-900-alpha-700": "rgba(231, 233, 249, 0.30)", + "c-primary-light-900-alpha-800": "rgba(231, 233, 249, 0.20)", + "c-primary-light-900-alpha-900": "rgba(231, 233, 249, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(79, 98, 208)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "var(c-primary-light-600-alpha-700)", + "c-main-background": "rgba(255, 255, 255, 1)", + "bg-image": "", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "#b080db", + "c-badge-tertiary": "#b080db" + } + } + }, + { + "id": "black", + "name": "黑灯瞎火", + "isDark": true, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(150, 150, 150)", + "c-primary-dark-100": "rgb(171,171,171)", + "c-primary-dark-100-alpha-100": "rgba(171, 171, 171, 0.90)", + "c-primary-alpha-100": "rgba(150, 150, 150, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(171, 171, 171, 0.80)", + "c-primary-alpha-200": "rgba(150, 150, 150, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(171, 171, 171, 0.70)", + "c-primary-alpha-300": "rgba(150, 150, 150, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(171, 171, 171, 0.60)", + "c-primary-alpha-400": "rgba(150, 150, 150, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(171, 171, 171, 0.50)", + "c-primary-alpha-500": "rgba(150, 150, 150, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(171, 171, 171, 0.40)", + "c-primary-alpha-600": "rgba(150, 150, 150, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(171, 171, 171, 0.30)", + "c-primary-alpha-700": "rgba(150, 150, 150, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(171, 171, 171, 0.20)", + "c-primary-alpha-800": "rgba(150, 150, 150, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(171, 171, 171, 0.10)", + "c-primary-alpha-900": "rgba(150, 150, 150, 0.10)", + "c-primary-dark-200": "rgb(188,188,188)", + "c-primary-dark-200-alpha-100": "rgba(188, 188, 188, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(188, 188, 188, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(188, 188, 188, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(188, 188, 188, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(188, 188, 188, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(188, 188, 188, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(188, 188, 188, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(188, 188, 188, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(188, 188, 188, 0.10)", + "c-primary-dark-300": "rgb(201,201,201)", + "c-primary-dark-300-alpha-100": "rgba(201, 201, 201, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(201, 201, 201, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(201, 201, 201, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(201, 201, 201, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(201, 201, 201, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(201, 201, 201, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(201, 201, 201, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(201, 201, 201, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(201, 201, 201, 0.10)", + "c-primary-dark-400": "rgb(212,212,212)", + "c-primary-dark-400-alpha-100": "rgba(212, 212, 212, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(212, 212, 212, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(212, 212, 212, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(212, 212, 212, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(212, 212, 212, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(212, 212, 212, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(212, 212, 212, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(212, 212, 212, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(212, 212, 212, 0.10)", + "c-primary-dark-500": "rgb(221,221,221)", + "c-primary-dark-500-alpha-100": "rgba(221, 221, 221, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(221, 221, 221, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(221, 221, 221, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(221, 221, 221, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(221, 221, 221, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(221, 221, 221, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(221, 221, 221, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(221, 221, 221, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(221, 221, 221, 0.10)", + "c-primary-dark-600": "rgb(228,228,228)", + "c-primary-dark-600-alpha-100": "rgba(228, 228, 228, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(228, 228, 228, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(228, 228, 228, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(228, 228, 228, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(228, 228, 228, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(228, 228, 228, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(228, 228, 228, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(228, 228, 228, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(228, 228, 228, 0.10)", + "c-primary-dark-700": "rgb(233,233,233)", + "c-primary-dark-700-alpha-100": "rgba(233, 233, 233, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(233, 233, 233, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(233, 233, 233, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(233, 233, 233, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(233, 233, 233, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(233, 233, 233, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(233, 233, 233, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(233, 233, 233, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(233, 233, 233, 0.10)", + "c-primary-dark-800": "rgb(237,237,237)", + "c-primary-dark-800-alpha-100": "rgba(237, 237, 237, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(237, 237, 237, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(237, 237, 237, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(237, 237, 237, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(237, 237, 237, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(237, 237, 237, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(237, 237, 237, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(237, 237, 237, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(237, 237, 237, 0.10)", + "c-primary-dark-900": "rgb(241,241,241)", + "c-primary-dark-900-alpha-100": "rgba(241, 241, 241, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(241, 241, 241, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(241, 241, 241, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(241, 241, 241, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(241, 241, 241, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(241, 241, 241, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(241, 241, 241, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(241, 241, 241, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(241, 241, 241, 0.10)", + "c-primary-dark-1000": "rgb(244,244,244)", + "c-primary-dark-1000-alpha-100": "rgba(244, 244, 244, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(244, 244, 244, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(244, 244, 244, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(244, 244, 244, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(244, 244, 244, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(244, 244, 244, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(244, 244, 244, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(244, 244, 244, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(244, 244, 244, 0.10)", + "c-primary-light-100": "rgb(135,135,135)", + "c-primary-light-100-alpha-100": "rgba(135, 135, 135, 0.90)", + "c-primary-light-100-alpha-200": "rgba(135, 135, 135, 0.80)", + "c-primary-light-100-alpha-300": "rgba(135, 135, 135, 0.70)", + "c-primary-light-100-alpha-400": "rgba(135, 135, 135, 0.60)", + "c-primary-light-100-alpha-500": "rgba(135, 135, 135, 0.50)", + "c-primary-light-100-alpha-600": "rgba(135, 135, 135, 0.40)", + "c-primary-light-100-alpha-700": "rgba(135, 135, 135, 0.30)", + "c-primary-light-100-alpha-800": "rgba(135, 135, 135, 0.20)", + "c-primary-light-100-alpha-900": "rgba(135, 135, 135, 0.10)", + "c-primary-light-200": "rgb(122,122,122)", + "c-primary-light-200-alpha-100": "rgba(122, 122, 122, 0.90)", + "c-primary-light-200-alpha-200": "rgba(122, 122, 122, 0.80)", + "c-primary-light-200-alpha-300": "rgba(122, 122, 122, 0.70)", + "c-primary-light-200-alpha-400": "rgba(122, 122, 122, 0.60)", + "c-primary-light-200-alpha-500": "rgba(122, 122, 122, 0.50)", + "c-primary-light-200-alpha-600": "rgba(122, 122, 122, 0.40)", + "c-primary-light-200-alpha-700": "rgba(122, 122, 122, 0.30)", + "c-primary-light-200-alpha-800": "rgba(122, 122, 122, 0.20)", + "c-primary-light-200-alpha-900": "rgba(122, 122, 122, 0.10)", + "c-primary-light-300": "rgb(110,110,110)", + "c-primary-light-300-alpha-100": "rgba(110, 110, 110, 0.90)", + "c-primary-light-300-alpha-200": "rgba(110, 110, 110, 0.80)", + "c-primary-light-300-alpha-300": "rgba(110, 110, 110, 0.70)", + "c-primary-light-300-alpha-400": "rgba(110, 110, 110, 0.60)", + "c-primary-light-300-alpha-500": "rgba(110, 110, 110, 0.50)", + "c-primary-light-300-alpha-600": "rgba(110, 110, 110, 0.40)", + "c-primary-light-300-alpha-700": "rgba(110, 110, 110, 0.30)", + "c-primary-light-300-alpha-800": "rgba(110, 110, 110, 0.20)", + "c-primary-light-300-alpha-900": "rgba(110, 110, 110, 0.10)", + "c-primary-light-400": "rgb(99,99,99)", + "c-primary-light-400-alpha-100": "rgba(99, 99, 99, 0.90)", + "c-primary-light-400-alpha-200": "rgba(99, 99, 99, 0.80)", + "c-primary-light-400-alpha-300": "rgba(99, 99, 99, 0.70)", + "c-primary-light-400-alpha-400": "rgba(99, 99, 99, 0.60)", + "c-primary-light-400-alpha-500": "rgba(99, 99, 99, 0.50)", + "c-primary-light-400-alpha-600": "rgba(99, 99, 99, 0.40)", + "c-primary-light-400-alpha-700": "rgba(99, 99, 99, 0.30)", + "c-primary-light-400-alpha-800": "rgba(99, 99, 99, 0.20)", + "c-primary-light-400-alpha-900": "rgba(99, 99, 99, 0.10)", + "c-primary-light-500": "rgb(89,89,89)", + "c-primary-light-500-alpha-100": "rgba(89, 89, 89, 0.90)", + "c-primary-light-500-alpha-200": "rgba(89, 89, 89, 0.80)", + "c-primary-light-500-alpha-300": "rgba(89, 89, 89, 0.70)", + "c-primary-light-500-alpha-400": "rgba(89, 89, 89, 0.60)", + "c-primary-light-500-alpha-500": "rgba(89, 89, 89, 0.50)", + "c-primary-light-500-alpha-600": "rgba(89, 89, 89, 0.40)", + "c-primary-light-500-alpha-700": "rgba(89, 89, 89, 0.30)", + "c-primary-light-500-alpha-800": "rgba(89, 89, 89, 0.20)", + "c-primary-light-500-alpha-900": "rgba(89, 89, 89, 0.10)", + "c-primary-light-600": "rgb(80,80,80)", + "c-primary-light-600-alpha-100": "rgba(80, 80, 80, 0.90)", + "c-primary-light-600-alpha-200": "rgba(80, 80, 80, 0.80)", + "c-primary-light-600-alpha-300": "rgba(80, 80, 80, 0.70)", + "c-primary-light-600-alpha-400": "rgba(80, 80, 80, 0.60)", + "c-primary-light-600-alpha-500": "rgba(80, 80, 80, 0.50)", + "c-primary-light-600-alpha-600": "rgba(80, 80, 80, 0.40)", + "c-primary-light-600-alpha-700": "rgba(80, 80, 80, 0.30)", + "c-primary-light-600-alpha-800": "rgba(80, 80, 80, 0.20)", + "c-primary-light-600-alpha-900": "rgba(80, 80, 80, 0.10)", + "c-primary-light-700": "rgb(72,72,72)", + "c-primary-light-700-alpha-100": "rgba(72, 72, 72, 0.90)", + "c-primary-light-700-alpha-200": "rgba(72, 72, 72, 0.80)", + "c-primary-light-700-alpha-300": "rgba(72, 72, 72, 0.70)", + "c-primary-light-700-alpha-400": "rgba(72, 72, 72, 0.60)", + "c-primary-light-700-alpha-500": "rgba(72, 72, 72, 0.50)", + "c-primary-light-700-alpha-600": "rgba(72, 72, 72, 0.40)", + "c-primary-light-700-alpha-700": "rgba(72, 72, 72, 0.30)", + "c-primary-light-700-alpha-800": "rgba(72, 72, 72, 0.20)", + "c-primary-light-700-alpha-900": "rgba(72, 72, 72, 0.10)", + "c-primary-light-800": "rgb(65,65,65)", + "c-primary-light-800-alpha-100": "rgba(65, 65, 65, 0.90)", + "c-primary-light-800-alpha-200": "rgba(65, 65, 65, 0.80)", + "c-primary-light-800-alpha-300": "rgba(65, 65, 65, 0.70)", + "c-primary-light-800-alpha-400": "rgba(65, 65, 65, 0.60)", + "c-primary-light-800-alpha-500": "rgba(65, 65, 65, 0.50)", + "c-primary-light-800-alpha-600": "rgba(65, 65, 65, 0.40)", + "c-primary-light-800-alpha-700": "rgba(65, 65, 65, 0.30)", + "c-primary-light-800-alpha-800": "rgba(65, 65, 65, 0.20)", + "c-primary-light-800-alpha-900": "rgba(65, 65, 65, 0.10)", + "c-primary-light-900": "rgb(59,59,59)", + "c-primary-light-900-alpha-100": "rgba(59, 59, 59, 0.90)", + "c-primary-light-900-alpha-200": "rgba(59, 59, 59, 0.80)", + "c-primary-light-900-alpha-300": "rgba(59, 59, 59, 0.70)", + "c-primary-light-900-alpha-400": "rgba(59, 59, 59, 0.60)", + "c-primary-light-900-alpha-500": "rgba(59, 59, 59, 0.50)", + "c-primary-light-900-alpha-600": "rgba(59, 59, 59, 0.40)", + "c-primary-light-900-alpha-700": "rgba(59, 59, 59, 0.30)", + "c-primary-light-900-alpha-800": "rgba(59, 59, 59, 0.20)", + "c-primary-light-900-alpha-900": "rgba(59, 59, 59, 0.10)", + "c-primary-light-1000": "rgb(47,47,47)", + "c-primary-light-1000-alpha-100": "rgba(47, 47, 47, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(47, 47, 47, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(47, 47, 47, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(47, 47, 47, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(47, 47, 47, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(47, 47, 47, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(47, 47, 47, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(47, 47, 47, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(47, 47, 47, 0.10)", + "c-theme": "rgb(59,59,59)", + "c-1000": "rgb(229, 229, 229)", + "c-950": "rgb(218,218,218)", + "c-900": "rgb(207,207,207)", + "c-850": "rgb(197,197,197)", + "c-800": "rgb(187,187,187)", + "c-750": "rgb(178,178,178)", + "c-700": "rgb(169,169,169)", + "c-650": "rgb(161,161,161)", + "c-600": "rgb(153,153,153)", + "c-550": "rgb(145,145,145)", + "c-500": "rgb(138,138,138)", + "c-450": "rgb(131,131,131)", + "c-400": "rgb(124,124,124)", + "c-350": "rgb(118,118,118)", + "c-300": "rgb(112,112,112)", + "c-250": "rgb(106,106,106)", + "c-200": "rgb(101,101,101)", + "c-150": "rgb(96,96,96)", + "c-100": "rgb(91,91,91)", + "c-050": "rgb(86,86,86)", + "c-000": "rgb(82,82,82)" + }, + "extInfo": { + "c-app-background": "rgba(0, 0, 0, 0)", + "c-main-background": "rgba(19, 19, 19, 0.95)", + "bg-image": "landingMoon.png", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary-dark-200)", + "c-badge-secondary": "var(c-primary)", + "c-badge-tertiary": "var(c-primary-dark-300)" + } + } + }, + { + "id": "mid_autumn", + "name": "月里嫦娥", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(74, 55, 82)", + "c-primary-dark-100": "rgb(67,50,74)", + "c-primary-dark-100-alpha-100": "rgba(67, 50, 74, 0.90)", + "c-primary-alpha-100": "rgba(74, 55, 82, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(67, 50, 74, 0.80)", + "c-primary-alpha-200": "rgba(74, 55, 82, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(67, 50, 74, 0.70)", + "c-primary-alpha-300": "rgba(74, 55, 82, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(67, 50, 74, 0.60)", + "c-primary-alpha-400": "rgba(74, 55, 82, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(67, 50, 74, 0.50)", + "c-primary-alpha-500": "rgba(74, 55, 82, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(67, 50, 74, 0.40)", + "c-primary-alpha-600": "rgba(74, 55, 82, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(67, 50, 74, 0.30)", + "c-primary-alpha-700": "rgba(74, 55, 82, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(67, 50, 74, 0.20)", + "c-primary-alpha-800": "rgba(74, 55, 82, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(67, 50, 74, 0.10)", + "c-primary-alpha-900": "rgba(74, 55, 82, 0.10)", + "c-primary-dark-200": "rgb(60,45,67)", + "c-primary-dark-200-alpha-100": "rgba(60, 45, 67, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(60, 45, 67, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(60, 45, 67, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(60, 45, 67, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(60, 45, 67, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(60, 45, 67, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(60, 45, 67, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(60, 45, 67, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(60, 45, 67, 0.10)", + "c-primary-dark-300": "rgb(54,41,60)", + "c-primary-dark-300-alpha-100": "rgba(54, 41, 60, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(54, 41, 60, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(54, 41, 60, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(54, 41, 60, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(54, 41, 60, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(54, 41, 60, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(54, 41, 60, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(54, 41, 60, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(54, 41, 60, 0.10)", + "c-primary-dark-400": "rgb(49,37,54)", + "c-primary-dark-400-alpha-100": "rgba(49, 37, 54, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(49, 37, 54, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(49, 37, 54, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(49, 37, 54, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(49, 37, 54, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(49, 37, 54, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(49, 37, 54, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(49, 37, 54, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(49, 37, 54, 0.10)", + "c-primary-dark-500": "rgb(44,33,49)", + "c-primary-dark-500-alpha-100": "rgba(44, 33, 49, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(44, 33, 49, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(44, 33, 49, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(44, 33, 49, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(44, 33, 49, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(44, 33, 49, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(44, 33, 49, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(44, 33, 49, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(44, 33, 49, 0.10)", + "c-primary-dark-600": "rgb(40,30,44)", + "c-primary-dark-600-alpha-100": "rgba(40, 30, 44, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(40, 30, 44, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(40, 30, 44, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(40, 30, 44, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(40, 30, 44, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(40, 30, 44, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(40, 30, 44, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(40, 30, 44, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(40, 30, 44, 0.10)", + "c-primary-dark-700": "rgb(36,27,40)", + "c-primary-dark-700-alpha-100": "rgba(36, 27, 40, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(36, 27, 40, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(36, 27, 40, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(36, 27, 40, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(36, 27, 40, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(36, 27, 40, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(36, 27, 40, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(36, 27, 40, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(36, 27, 40, 0.10)", + "c-primary-dark-800": "rgb(32,24,36)", + "c-primary-dark-800-alpha-100": "rgba(32, 24, 36, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(32, 24, 36, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(32, 24, 36, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(32, 24, 36, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(32, 24, 36, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(32, 24, 36, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(32, 24, 36, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(32, 24, 36, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(32, 24, 36, 0.10)", + "c-primary-dark-900": "rgb(29,22,32)", + "c-primary-dark-900-alpha-100": "rgba(29, 22, 32, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(29, 22, 32, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(29, 22, 32, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(29, 22, 32, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(29, 22, 32, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(29, 22, 32, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(29, 22, 32, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(29, 22, 32, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(29, 22, 32, 0.10)", + "c-primary-dark-1000": "rgb(26,20,29)", + "c-primary-dark-1000-alpha-100": "rgba(26, 20, 29, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(26, 20, 29, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(26, 20, 29, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(26, 20, 29, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(26, 20, 29, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(26, 20, 29, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(26, 20, 29, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(26, 20, 29, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(26, 20, 29, 0.10)", + "c-primary-light-100": "rgb(110,95,117)", + "c-primary-light-100-alpha-100": "rgba(110, 95, 117, 0.90)", + "c-primary-light-100-alpha-200": "rgba(110, 95, 117, 0.80)", + "c-primary-light-100-alpha-300": "rgba(110, 95, 117, 0.70)", + "c-primary-light-100-alpha-400": "rgba(110, 95, 117, 0.60)", + "c-primary-light-100-alpha-500": "rgba(110, 95, 117, 0.50)", + "c-primary-light-100-alpha-600": "rgba(110, 95, 117, 0.40)", + "c-primary-light-100-alpha-700": "rgba(110, 95, 117, 0.30)", + "c-primary-light-100-alpha-800": "rgba(110, 95, 117, 0.20)", + "c-primary-light-100-alpha-900": "rgba(110, 95, 117, 0.10)", + "c-primary-light-200": "rgb(139,127,145)", + "c-primary-light-200-alpha-100": "rgba(139, 127, 145, 0.90)", + "c-primary-light-200-alpha-200": "rgba(139, 127, 145, 0.80)", + "c-primary-light-200-alpha-300": "rgba(139, 127, 145, 0.70)", + "c-primary-light-200-alpha-400": "rgba(139, 127, 145, 0.60)", + "c-primary-light-200-alpha-500": "rgba(139, 127, 145, 0.50)", + "c-primary-light-200-alpha-600": "rgba(139, 127, 145, 0.40)", + "c-primary-light-200-alpha-700": "rgba(139, 127, 145, 0.30)", + "c-primary-light-200-alpha-800": "rgba(139, 127, 145, 0.20)", + "c-primary-light-200-alpha-900": "rgba(139, 127, 145, 0.10)", + "c-primary-light-300": "rgb(162,153,167)", + "c-primary-light-300-alpha-100": "rgba(162, 153, 167, 0.90)", + "c-primary-light-300-alpha-200": "rgba(162, 153, 167, 0.80)", + "c-primary-light-300-alpha-300": "rgba(162, 153, 167, 0.70)", + "c-primary-light-300-alpha-400": "rgba(162, 153, 167, 0.60)", + "c-primary-light-300-alpha-500": "rgba(162, 153, 167, 0.50)", + "c-primary-light-300-alpha-600": "rgba(162, 153, 167, 0.40)", + "c-primary-light-300-alpha-700": "rgba(162, 153, 167, 0.30)", + "c-primary-light-300-alpha-800": "rgba(162, 153, 167, 0.20)", + "c-primary-light-300-alpha-900": "rgba(162, 153, 167, 0.10)", + "c-primary-light-400": "rgb(181,173,185)", + "c-primary-light-400-alpha-100": "rgba(181, 173, 185, 0.90)", + "c-primary-light-400-alpha-200": "rgba(181, 173, 185, 0.80)", + "c-primary-light-400-alpha-300": "rgba(181, 173, 185, 0.70)", + "c-primary-light-400-alpha-400": "rgba(181, 173, 185, 0.60)", + "c-primary-light-400-alpha-500": "rgba(181, 173, 185, 0.50)", + "c-primary-light-400-alpha-600": "rgba(181, 173, 185, 0.40)", + "c-primary-light-400-alpha-700": "rgba(181, 173, 185, 0.30)", + "c-primary-light-400-alpha-800": "rgba(181, 173, 185, 0.20)", + "c-primary-light-400-alpha-900": "rgba(181, 173, 185, 0.10)", + "c-primary-light-500": "rgb(196,189,199)", + "c-primary-light-500-alpha-100": "rgba(196, 189, 199, 0.90)", + "c-primary-light-500-alpha-200": "rgba(196, 189, 199, 0.80)", + "c-primary-light-500-alpha-300": "rgba(196, 189, 199, 0.70)", + "c-primary-light-500-alpha-400": "rgba(196, 189, 199, 0.60)", + "c-primary-light-500-alpha-500": "rgba(196, 189, 199, 0.50)", + "c-primary-light-500-alpha-600": "rgba(196, 189, 199, 0.40)", + "c-primary-light-500-alpha-700": "rgba(196, 189, 199, 0.30)", + "c-primary-light-500-alpha-800": "rgba(196, 189, 199, 0.20)", + "c-primary-light-500-alpha-900": "rgba(196, 189, 199, 0.10)", + "c-primary-light-600": "rgb(208,202,210)", + "c-primary-light-600-alpha-100": "rgba(208, 202, 210, 0.90)", + "c-primary-light-600-alpha-200": "rgba(208, 202, 210, 0.80)", + "c-primary-light-600-alpha-300": "rgba(208, 202, 210, 0.70)", + "c-primary-light-600-alpha-400": "rgba(208, 202, 210, 0.60)", + "c-primary-light-600-alpha-500": "rgba(208, 202, 210, 0.50)", + "c-primary-light-600-alpha-600": "rgba(208, 202, 210, 0.40)", + "c-primary-light-600-alpha-700": "rgba(208, 202, 210, 0.30)", + "c-primary-light-600-alpha-800": "rgba(208, 202, 210, 0.20)", + "c-primary-light-600-alpha-900": "rgba(208, 202, 210, 0.10)", + "c-primary-light-700": "rgb(217,213,219)", + "c-primary-light-700-alpha-100": "rgba(217, 213, 219, 0.90)", + "c-primary-light-700-alpha-200": "rgba(217, 213, 219, 0.80)", + "c-primary-light-700-alpha-300": "rgba(217, 213, 219, 0.70)", + "c-primary-light-700-alpha-400": "rgba(217, 213, 219, 0.60)", + "c-primary-light-700-alpha-500": "rgba(217, 213, 219, 0.50)", + "c-primary-light-700-alpha-600": "rgba(217, 213, 219, 0.40)", + "c-primary-light-700-alpha-700": "rgba(217, 213, 219, 0.30)", + "c-primary-light-700-alpha-800": "rgba(217, 213, 219, 0.20)", + "c-primary-light-700-alpha-900": "rgba(217, 213, 219, 0.10)", + "c-primary-light-800": "rgb(225,221,226)", + "c-primary-light-800-alpha-100": "rgba(225, 221, 226, 0.90)", + "c-primary-light-800-alpha-200": "rgba(225, 221, 226, 0.80)", + "c-primary-light-800-alpha-300": "rgba(225, 221, 226, 0.70)", + "c-primary-light-800-alpha-400": "rgba(225, 221, 226, 0.60)", + "c-primary-light-800-alpha-500": "rgba(225, 221, 226, 0.50)", + "c-primary-light-800-alpha-600": "rgba(225, 221, 226, 0.40)", + "c-primary-light-800-alpha-700": "rgba(225, 221, 226, 0.30)", + "c-primary-light-800-alpha-800": "rgba(225, 221, 226, 0.20)", + "c-primary-light-800-alpha-900": "rgba(225, 221, 226, 0.10)", + "c-primary-light-900": "rgb(231,228,232)", + "c-primary-light-900-alpha-100": "rgba(231, 228, 232, 0.90)", + "c-primary-light-900-alpha-200": "rgba(231, 228, 232, 0.80)", + "c-primary-light-900-alpha-300": "rgba(231, 228, 232, 0.70)", + "c-primary-light-900-alpha-400": "rgba(231, 228, 232, 0.60)", + "c-primary-light-900-alpha-500": "rgba(231, 228, 232, 0.50)", + "c-primary-light-900-alpha-600": "rgba(231, 228, 232, 0.40)", + "c-primary-light-900-alpha-700": "rgba(231, 228, 232, 0.30)", + "c-primary-light-900-alpha-800": "rgba(231, 228, 232, 0.20)", + "c-primary-light-900-alpha-900": "rgba(231, 228, 232, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(74, 55, 82)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "rgba(255, 255, 255, 0)", + "c-main-background": "rgba(255, 255, 255, 0.9)", + "bg-image": "jqbg.jpg", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "#af9479", + "c-badge-tertiary": "#af9479" + } + } + }, + { + "id": "naruto", + "name": "木叶之村", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(87, 144, 167)", + "c-primary-dark-100": "rgb(78,130,150)", + "c-primary-dark-100-alpha-100": "rgba(78, 130, 150, 0.90)", + "c-primary-alpha-100": "rgba(87, 144, 167, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(78, 130, 150, 0.80)", + "c-primary-alpha-200": "rgba(87, 144, 167, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(78, 130, 150, 0.70)", + "c-primary-alpha-300": "rgba(87, 144, 167, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(78, 130, 150, 0.60)", + "c-primary-alpha-400": "rgba(87, 144, 167, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(78, 130, 150, 0.50)", + "c-primary-alpha-500": "rgba(87, 144, 167, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(78, 130, 150, 0.40)", + "c-primary-alpha-600": "rgba(87, 144, 167, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(78, 130, 150, 0.30)", + "c-primary-alpha-700": "rgba(87, 144, 167, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(78, 130, 150, 0.20)", + "c-primary-alpha-800": "rgba(87, 144, 167, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(78, 130, 150, 0.10)", + "c-primary-alpha-900": "rgba(87, 144, 167, 0.10)", + "c-primary-dark-200": "rgb(70,117,135)", + "c-primary-dark-200-alpha-100": "rgba(70, 117, 135, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(70, 117, 135, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(70, 117, 135, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(70, 117, 135, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(70, 117, 135, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(70, 117, 135, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(70, 117, 135, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(70, 117, 135, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(70, 117, 135, 0.10)", + "c-primary-dark-300": "rgb(63,105,122)", + "c-primary-dark-300-alpha-100": "rgba(63, 105, 122, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(63, 105, 122, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(63, 105, 122, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(63, 105, 122, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(63, 105, 122, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(63, 105, 122, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(63, 105, 122, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(63, 105, 122, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(63, 105, 122, 0.10)", + "c-primary-dark-400": "rgb(57,95,110)", + "c-primary-dark-400-alpha-100": "rgba(57, 95, 110, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(57, 95, 110, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(57, 95, 110, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(57, 95, 110, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(57, 95, 110, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(57, 95, 110, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(57, 95, 110, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(57, 95, 110, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(57, 95, 110, 0.10)", + "c-primary-dark-500": "rgb(51,86,99)", + "c-primary-dark-500-alpha-100": "rgba(51, 86, 99, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(51, 86, 99, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(51, 86, 99, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(51, 86, 99, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(51, 86, 99, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(51, 86, 99, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(51, 86, 99, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(51, 86, 99, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(51, 86, 99, 0.10)", + "c-primary-dark-600": "rgb(46,77,89)", + "c-primary-dark-600-alpha-100": "rgba(46, 77, 89, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(46, 77, 89, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(46, 77, 89, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(46, 77, 89, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(46, 77, 89, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(46, 77, 89, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(46, 77, 89, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(46, 77, 89, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(46, 77, 89, 0.10)", + "c-primary-dark-700": "rgb(41,69,80)", + "c-primary-dark-700-alpha-100": "rgba(41, 69, 80, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(41, 69, 80, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(41, 69, 80, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(41, 69, 80, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(41, 69, 80, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(41, 69, 80, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(41, 69, 80, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(41, 69, 80, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(41, 69, 80, 0.10)", + "c-primary-dark-800": "rgb(37,62,72)", + "c-primary-dark-800-alpha-100": "rgba(37, 62, 72, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(37, 62, 72, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(37, 62, 72, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(37, 62, 72, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(37, 62, 72, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(37, 62, 72, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(37, 62, 72, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(37, 62, 72, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(37, 62, 72, 0.10)", + "c-primary-dark-900": "rgb(33,56,65)", + "c-primary-dark-900-alpha-100": "rgba(33, 56, 65, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(33, 56, 65, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(33, 56, 65, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(33, 56, 65, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(33, 56, 65, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(33, 56, 65, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(33, 56, 65, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(33, 56, 65, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(33, 56, 65, 0.10)", + "c-primary-dark-1000": "rgb(30,50,59)", + "c-primary-dark-1000-alpha-100": "rgba(30, 50, 59, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(30, 50, 59, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(30, 50, 59, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(30, 50, 59, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(30, 50, 59, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(30, 50, 59, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(30, 50, 59, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(30, 50, 59, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(30, 50, 59, 0.10)", + "c-primary-light-100": "rgb(121,166,185)", + "c-primary-light-100-alpha-100": "rgba(121, 166, 185, 0.90)", + "c-primary-light-100-alpha-200": "rgba(121, 166, 185, 0.80)", + "c-primary-light-100-alpha-300": "rgba(121, 166, 185, 0.70)", + "c-primary-light-100-alpha-400": "rgba(121, 166, 185, 0.60)", + "c-primary-light-100-alpha-500": "rgba(121, 166, 185, 0.50)", + "c-primary-light-100-alpha-600": "rgba(121, 166, 185, 0.40)", + "c-primary-light-100-alpha-700": "rgba(121, 166, 185, 0.30)", + "c-primary-light-100-alpha-800": "rgba(121, 166, 185, 0.20)", + "c-primary-light-100-alpha-900": "rgba(121, 166, 185, 0.10)", + "c-primary-light-200": "rgb(148,184,199)", + "c-primary-light-200-alpha-100": "rgba(148, 184, 199, 0.90)", + "c-primary-light-200-alpha-200": "rgba(148, 184, 199, 0.80)", + "c-primary-light-200-alpha-300": "rgba(148, 184, 199, 0.70)", + "c-primary-light-200-alpha-400": "rgba(148, 184, 199, 0.60)", + "c-primary-light-200-alpha-500": "rgba(148, 184, 199, 0.50)", + "c-primary-light-200-alpha-600": "rgba(148, 184, 199, 0.40)", + "c-primary-light-200-alpha-700": "rgba(148, 184, 199, 0.30)", + "c-primary-light-200-alpha-800": "rgba(148, 184, 199, 0.20)", + "c-primary-light-200-alpha-900": "rgba(148, 184, 199, 0.10)", + "c-primary-light-300": "rgb(169,198,210)", + "c-primary-light-300-alpha-100": "rgba(169, 198, 210, 0.90)", + "c-primary-light-300-alpha-200": "rgba(169, 198, 210, 0.80)", + "c-primary-light-300-alpha-300": "rgba(169, 198, 210, 0.70)", + "c-primary-light-300-alpha-400": "rgba(169, 198, 210, 0.60)", + "c-primary-light-300-alpha-500": "rgba(169, 198, 210, 0.50)", + "c-primary-light-300-alpha-600": "rgba(169, 198, 210, 0.40)", + "c-primary-light-300-alpha-700": "rgba(169, 198, 210, 0.30)", + "c-primary-light-300-alpha-800": "rgba(169, 198, 210, 0.20)", + "c-primary-light-300-alpha-900": "rgba(169, 198, 210, 0.10)", + "c-primary-light-400": "rgb(186,209,219)", + "c-primary-light-400-alpha-100": "rgba(186, 209, 219, 0.90)", + "c-primary-light-400-alpha-200": "rgba(186, 209, 219, 0.80)", + "c-primary-light-400-alpha-300": "rgba(186, 209, 219, 0.70)", + "c-primary-light-400-alpha-400": "rgba(186, 209, 219, 0.60)", + "c-primary-light-400-alpha-500": "rgba(186, 209, 219, 0.50)", + "c-primary-light-400-alpha-600": "rgba(186, 209, 219, 0.40)", + "c-primary-light-400-alpha-700": "rgba(186, 209, 219, 0.30)", + "c-primary-light-400-alpha-800": "rgba(186, 209, 219, 0.20)", + "c-primary-light-400-alpha-900": "rgba(186, 209, 219, 0.10)", + "c-primary-light-500": "rgb(200,218,226)", + "c-primary-light-500-alpha-100": "rgba(200, 218, 226, 0.90)", + "c-primary-light-500-alpha-200": "rgba(200, 218, 226, 0.80)", + "c-primary-light-500-alpha-300": "rgba(200, 218, 226, 0.70)", + "c-primary-light-500-alpha-400": "rgba(200, 218, 226, 0.60)", + "c-primary-light-500-alpha-500": "rgba(200, 218, 226, 0.50)", + "c-primary-light-500-alpha-600": "rgba(200, 218, 226, 0.40)", + "c-primary-light-500-alpha-700": "rgba(200, 218, 226, 0.30)", + "c-primary-light-500-alpha-800": "rgba(200, 218, 226, 0.20)", + "c-primary-light-500-alpha-900": "rgba(200, 218, 226, 0.10)", + "c-primary-light-600": "rgb(211,225,232)", + "c-primary-light-600-alpha-100": "rgba(211, 225, 232, 0.90)", + "c-primary-light-600-alpha-200": "rgba(211, 225, 232, 0.80)", + "c-primary-light-600-alpha-300": "rgba(211, 225, 232, 0.70)", + "c-primary-light-600-alpha-400": "rgba(211, 225, 232, 0.60)", + "c-primary-light-600-alpha-500": "rgba(211, 225, 232, 0.50)", + "c-primary-light-600-alpha-600": "rgba(211, 225, 232, 0.40)", + "c-primary-light-600-alpha-700": "rgba(211, 225, 232, 0.30)", + "c-primary-light-600-alpha-800": "rgba(211, 225, 232, 0.20)", + "c-primary-light-600-alpha-900": "rgba(211, 225, 232, 0.10)", + "c-primary-light-700": "rgb(220,231,237)", + "c-primary-light-700-alpha-100": "rgba(220, 231, 237, 0.90)", + "c-primary-light-700-alpha-200": "rgba(220, 231, 237, 0.80)", + "c-primary-light-700-alpha-300": "rgba(220, 231, 237, 0.70)", + "c-primary-light-700-alpha-400": "rgba(220, 231, 237, 0.60)", + "c-primary-light-700-alpha-500": "rgba(220, 231, 237, 0.50)", + "c-primary-light-700-alpha-600": "rgba(220, 231, 237, 0.40)", + "c-primary-light-700-alpha-700": "rgba(220, 231, 237, 0.30)", + "c-primary-light-700-alpha-800": "rgba(220, 231, 237, 0.20)", + "c-primary-light-700-alpha-900": "rgba(220, 231, 237, 0.10)", + "c-primary-light-800": "rgb(227,236,241)", + "c-primary-light-800-alpha-100": "rgba(227, 236, 241, 0.90)", + "c-primary-light-800-alpha-200": "rgba(227, 236, 241, 0.80)", + "c-primary-light-800-alpha-300": "rgba(227, 236, 241, 0.70)", + "c-primary-light-800-alpha-400": "rgba(227, 236, 241, 0.60)", + "c-primary-light-800-alpha-500": "rgba(227, 236, 241, 0.50)", + "c-primary-light-800-alpha-600": "rgba(227, 236, 241, 0.40)", + "c-primary-light-800-alpha-700": "rgba(227, 236, 241, 0.30)", + "c-primary-light-800-alpha-800": "rgba(227, 236, 241, 0.20)", + "c-primary-light-800-alpha-900": "rgba(227, 236, 241, 0.10)", + "c-primary-light-900": "rgb(233,240,244)", + "c-primary-light-900-alpha-100": "rgba(233, 240, 244, 0.90)", + "c-primary-light-900-alpha-200": "rgba(233, 240, 244, 0.80)", + "c-primary-light-900-alpha-300": "rgba(233, 240, 244, 0.70)", + "c-primary-light-900-alpha-400": "rgba(233, 240, 244, 0.60)", + "c-primary-light-900-alpha-500": "rgba(233, 240, 244, 0.50)", + "c-primary-light-900-alpha-600": "rgba(233, 240, 244, 0.40)", + "c-primary-light-900-alpha-700": "rgba(233, 240, 244, 0.30)", + "c-primary-light-900-alpha-800": "rgba(233, 240, 244, 0.20)", + "c-primary-light-900-alpha-900": "rgba(233, 240, 244, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(87, 144, 167)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "rgba(255, 255, 255, 0.15)", + "c-main-background": "rgba(255, 255, 255, 0.8)", + "bg-image": "myzcbg.jpg", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "var(c-primary)", + "c-badge-secondary": "var(c-primary-light-100)", + "c-badge-tertiary": "var(c-primary-light-100)" + } + } + }, + { + "id": "china_ink", + "name": "近墨者黑", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgba(47, 47, 47, 1)", + "c-primary-dark-100": "rgba(42,42,42, 1)", + "c-primary-dark-100-alpha-100": "rgba(42, 42, 42, 0.90)", + "c-primary-alpha-100": "rgba(47, 47, 47, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(42, 42, 42, 0.80)", + "c-primary-alpha-200": "rgba(47, 47, 47, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(42, 42, 42, 0.70)", + "c-primary-alpha-300": "rgba(47, 47, 47, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(42, 42, 42, 0.60)", + "c-primary-alpha-400": "rgba(47, 47, 47, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(42, 42, 42, 0.50)", + "c-primary-alpha-500": "rgba(47, 47, 47, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(42, 42, 42, 0.40)", + "c-primary-alpha-600": "rgba(47, 47, 47, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(42, 42, 42, 0.30)", + "c-primary-alpha-700": "rgba(47, 47, 47, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(42, 42, 42, 0.20)", + "c-primary-alpha-800": "rgba(47, 47, 47, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(42, 42, 42, 0.10)", + "c-primary-alpha-900": "rgba(47, 47, 47, 0.10)", + "c-primary-dark-200": "rgba(38,38,38, 1)", + "c-primary-dark-200-alpha-100": "rgba(38, 38, 38, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(38, 38, 38, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(38, 38, 38, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(38, 38, 38, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(38, 38, 38, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(38, 38, 38, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(38, 38, 38, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(38, 38, 38, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(38, 38, 38, 0.10)", + "c-primary-dark-300": "rgba(34,34,34, 1)", + "c-primary-dark-300-alpha-100": "rgba(34, 34, 34, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(34, 34, 34, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(34, 34, 34, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(34, 34, 34, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(34, 34, 34, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(34, 34, 34, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(34, 34, 34, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(34, 34, 34, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(34, 34, 34, 0.10)", + "c-primary-dark-400": "rgba(31,31,31, 1)", + "c-primary-dark-400-alpha-100": "rgba(31, 31, 31, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(31, 31, 31, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(31, 31, 31, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(31, 31, 31, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(31, 31, 31, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(31, 31, 31, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(31, 31, 31, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(31, 31, 31, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(31, 31, 31, 0.10)", + "c-primary-dark-500": "rgba(28,28,28, 1)", + "c-primary-dark-500-alpha-100": "rgba(28, 28, 28, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(28, 28, 28, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(28, 28, 28, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(28, 28, 28, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(28, 28, 28, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(28, 28, 28, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(28, 28, 28, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(28, 28, 28, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(28, 28, 28, 0.10)", + "c-primary-dark-600": "rgba(25,25,25, 1)", + "c-primary-dark-600-alpha-100": "rgba(25, 25, 25, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(25, 25, 25, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(25, 25, 25, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(25, 25, 25, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(25, 25, 25, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(25, 25, 25, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(25, 25, 25, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(25, 25, 25, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(25, 25, 25, 0.10)", + "c-primary-dark-700": "rgba(23,23,23, 1)", + "c-primary-dark-700-alpha-100": "rgba(23, 23, 23, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(23, 23, 23, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(23, 23, 23, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(23, 23, 23, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(23, 23, 23, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(23, 23, 23, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(23, 23, 23, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(23, 23, 23, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(23, 23, 23, 0.10)", + "c-primary-dark-800": "rgba(21,21,21, 1)", + "c-primary-dark-800-alpha-100": "rgba(21, 21, 21, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(21, 21, 21, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(21, 21, 21, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(21, 21, 21, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(21, 21, 21, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(21, 21, 21, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(21, 21, 21, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(21, 21, 21, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(21, 21, 21, 0.10)", + "c-primary-dark-900": "rgba(19,19,19, 1)", + "c-primary-dark-900-alpha-100": "rgba(19, 19, 19, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(19, 19, 19, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(19, 19, 19, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(19, 19, 19, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(19, 19, 19, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(19, 19, 19, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(19, 19, 19, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(19, 19, 19, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(19, 19, 19, 0.10)", + "c-primary-dark-1000": "rgba(17,17,17, 1)", + "c-primary-dark-1000-alpha-100": "rgba(17, 17, 17, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(17, 17, 17, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(17, 17, 17, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(17, 17, 17, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(17, 17, 17, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(17, 17, 17, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(17, 17, 17, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(17, 17, 17, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(17, 17, 17, 0.10)", + "c-primary-light-100": "rgba(89,89,89, 1)", + "c-primary-light-100-alpha-100": "rgba(89, 89, 89, 0.90)", + "c-primary-light-100-alpha-200": "rgba(89, 89, 89, 0.80)", + "c-primary-light-100-alpha-300": "rgba(89, 89, 89, 0.70)", + "c-primary-light-100-alpha-400": "rgba(89, 89, 89, 0.60)", + "c-primary-light-100-alpha-500": "rgba(89, 89, 89, 0.50)", + "c-primary-light-100-alpha-600": "rgba(89, 89, 89, 0.40)", + "c-primary-light-100-alpha-700": "rgba(89, 89, 89, 0.30)", + "c-primary-light-100-alpha-800": "rgba(89, 89, 89, 0.20)", + "c-primary-light-100-alpha-900": "rgba(89, 89, 89, 0.10)", + "c-primary-light-200": "rgba(122,122,122, 1)", + "c-primary-light-200-alpha-100": "rgba(122, 122, 122, 0.90)", + "c-primary-light-200-alpha-200": "rgba(122, 122, 122, 0.80)", + "c-primary-light-200-alpha-300": "rgba(122, 122, 122, 0.70)", + "c-primary-light-200-alpha-400": "rgba(122, 122, 122, 0.60)", + "c-primary-light-200-alpha-500": "rgba(122, 122, 122, 0.50)", + "c-primary-light-200-alpha-600": "rgba(122, 122, 122, 0.40)", + "c-primary-light-200-alpha-700": "rgba(122, 122, 122, 0.30)", + "c-primary-light-200-alpha-800": "rgba(122, 122, 122, 0.20)", + "c-primary-light-200-alpha-900": "rgba(122, 122, 122, 0.10)", + "c-primary-light-300": "rgba(149,149,149, 1)", + "c-primary-light-300-alpha-100": "rgba(149, 149, 149, 0.90)", + "c-primary-light-300-alpha-200": "rgba(149, 149, 149, 0.80)", + "c-primary-light-300-alpha-300": "rgba(149, 149, 149, 0.70)", + "c-primary-light-300-alpha-400": "rgba(149, 149, 149, 0.60)", + "c-primary-light-300-alpha-500": "rgba(149, 149, 149, 0.50)", + "c-primary-light-300-alpha-600": "rgba(149, 149, 149, 0.40)", + "c-primary-light-300-alpha-700": "rgba(149, 149, 149, 0.30)", + "c-primary-light-300-alpha-800": "rgba(149, 149, 149, 0.20)", + "c-primary-light-300-alpha-900": "rgba(149, 149, 149, 0.10)", + "c-primary-light-400": "rgba(170,170,170, 1)", + "c-primary-light-400-alpha-100": "rgba(170, 170, 170, 0.90)", + "c-primary-light-400-alpha-200": "rgba(170, 170, 170, 0.80)", + "c-primary-light-400-alpha-300": "rgba(170, 170, 170, 0.70)", + "c-primary-light-400-alpha-400": "rgba(170, 170, 170, 0.60)", + "c-primary-light-400-alpha-500": "rgba(170, 170, 170, 0.50)", + "c-primary-light-400-alpha-600": "rgba(170, 170, 170, 0.40)", + "c-primary-light-400-alpha-700": "rgba(170, 170, 170, 0.30)", + "c-primary-light-400-alpha-800": "rgba(170, 170, 170, 0.20)", + "c-primary-light-400-alpha-900": "rgba(170, 170, 170, 0.10)", + "c-primary-light-500": "rgba(187,187,187, 1)", + "c-primary-light-500-alpha-100": "rgba(187, 187, 187, 0.90)", + "c-primary-light-500-alpha-200": "rgba(187, 187, 187, 0.80)", + "c-primary-light-500-alpha-300": "rgba(187, 187, 187, 0.70)", + "c-primary-light-500-alpha-400": "rgba(187, 187, 187, 0.60)", + "c-primary-light-500-alpha-500": "rgba(187, 187, 187, 0.50)", + "c-primary-light-500-alpha-600": "rgba(187, 187, 187, 0.40)", + "c-primary-light-500-alpha-700": "rgba(187, 187, 187, 0.30)", + "c-primary-light-500-alpha-800": "rgba(187, 187, 187, 0.20)", + "c-primary-light-500-alpha-900": "rgba(187, 187, 187, 0.10)", + "c-primary-light-600": "rgba(201,201,201, 1)", + "c-primary-light-600-alpha-100": "rgba(201, 201, 201, 0.90)", + "c-primary-light-600-alpha-200": "rgba(201, 201, 201, 0.80)", + "c-primary-light-600-alpha-300": "rgba(201, 201, 201, 0.70)", + "c-primary-light-600-alpha-400": "rgba(201, 201, 201, 0.60)", + "c-primary-light-600-alpha-500": "rgba(201, 201, 201, 0.50)", + "c-primary-light-600-alpha-600": "rgba(201, 201, 201, 0.40)", + "c-primary-light-600-alpha-700": "rgba(201, 201, 201, 0.30)", + "c-primary-light-600-alpha-800": "rgba(201, 201, 201, 0.20)", + "c-primary-light-600-alpha-900": "rgba(201, 201, 201, 0.10)", + "c-primary-light-700": "rgba(212,212,212, 1)", + "c-primary-light-700-alpha-100": "rgba(212, 212, 212, 0.90)", + "c-primary-light-700-alpha-200": "rgba(212, 212, 212, 0.80)", + "c-primary-light-700-alpha-300": "rgba(212, 212, 212, 0.70)", + "c-primary-light-700-alpha-400": "rgba(212, 212, 212, 0.60)", + "c-primary-light-700-alpha-500": "rgba(212, 212, 212, 0.50)", + "c-primary-light-700-alpha-600": "rgba(212, 212, 212, 0.40)", + "c-primary-light-700-alpha-700": "rgba(212, 212, 212, 0.30)", + "c-primary-light-700-alpha-800": "rgba(212, 212, 212, 0.20)", + "c-primary-light-700-alpha-900": "rgba(212, 212, 212, 0.10)", + "c-primary-light-800": "rgba(221,221,221, 1)", + "c-primary-light-800-alpha-100": "rgba(221, 221, 221, 0.90)", + "c-primary-light-800-alpha-200": "rgba(221, 221, 221, 0.80)", + "c-primary-light-800-alpha-300": "rgba(221, 221, 221, 0.70)", + "c-primary-light-800-alpha-400": "rgba(221, 221, 221, 0.60)", + "c-primary-light-800-alpha-500": "rgba(221, 221, 221, 0.50)", + "c-primary-light-800-alpha-600": "rgba(221, 221, 221, 0.40)", + "c-primary-light-800-alpha-700": "rgba(221, 221, 221, 0.30)", + "c-primary-light-800-alpha-800": "rgba(221, 221, 221, 0.20)", + "c-primary-light-800-alpha-900": "rgba(221, 221, 221, 0.10)", + "c-primary-light-900": "rgba(228,228,228, 1)", + "c-primary-light-900-alpha-100": "rgba(228, 228, 228, 0.90)", + "c-primary-light-900-alpha-200": "rgba(228, 228, 228, 0.80)", + "c-primary-light-900-alpha-300": "rgba(228, 228, 228, 0.70)", + "c-primary-light-900-alpha-400": "rgba(228, 228, 228, 0.60)", + "c-primary-light-900-alpha-500": "rgba(228, 228, 228, 0.50)", + "c-primary-light-900-alpha-600": "rgba(228, 228, 228, 0.40)", + "c-primary-light-900-alpha-700": "rgba(228, 228, 228, 0.30)", + "c-primary-light-900-alpha-800": "rgba(228, 228, 228, 0.20)", + "c-primary-light-900-alpha-900": "rgba(228, 228, 228, 0.10)", + "c-primary-light-1000": "rgba(255,255,255, 1)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgba(47, 47, 47, 1)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "rgba(255, 255, 255, 0)", + "c-main-background": "rgba(255, 255, 255, 0.8)", + "bg-image": "china_ink.jpg", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "rgba(137, 70, 70, 1)", + "c-badge-secondary": "rgba(67, 139, 65, 1)", + "c-badge-tertiary": "rgba(132, 135, 65, 1)" + } + } + }, + { + "id": "happy_new_year", + "name": "新年快乐", + "isDark": false, + "isCustom": false, + "config": { + "themeColors": { + "c-primary": "rgb(192, 57, 43)", + "c-primary-dark-100": "rgb(173,51,39)", + "c-primary-dark-100-alpha-100": "rgba(173, 51, 39, 0.90)", + "c-primary-alpha-100": "rgba(192, 57, 43, 0.90)", + "c-primary-dark-100-alpha-200": "rgba(173, 51, 39, 0.80)", + "c-primary-alpha-200": "rgba(192, 57, 43, 0.80)", + "c-primary-dark-100-alpha-300": "rgba(173, 51, 39, 0.70)", + "c-primary-alpha-300": "rgba(192, 57, 43, 0.70)", + "c-primary-dark-100-alpha-400": "rgba(173, 51, 39, 0.60)", + "c-primary-alpha-400": "rgba(192, 57, 43, 0.60)", + "c-primary-dark-100-alpha-500": "rgba(173, 51, 39, 0.50)", + "c-primary-alpha-500": "rgba(192, 57, 43, 0.50)", + "c-primary-dark-100-alpha-600": "rgba(173, 51, 39, 0.40)", + "c-primary-alpha-600": "rgba(192, 57, 43, 0.40)", + "c-primary-dark-100-alpha-700": "rgba(173, 51, 39, 0.30)", + "c-primary-alpha-700": "rgba(192, 57, 43, 0.30)", + "c-primary-dark-100-alpha-800": "rgba(173, 51, 39, 0.20)", + "c-primary-alpha-800": "rgba(192, 57, 43, 0.20)", + "c-primary-dark-100-alpha-900": "rgba(173, 51, 39, 0.10)", + "c-primary-alpha-900": "rgba(192, 57, 43, 0.10)", + "c-primary-dark-200": "rgb(156,46,35)", + "c-primary-dark-200-alpha-100": "rgba(156, 46, 35, 0.90)", + "c-primary-dark-200-alpha-200": "rgba(156, 46, 35, 0.80)", + "c-primary-dark-200-alpha-300": "rgba(156, 46, 35, 0.70)", + "c-primary-dark-200-alpha-400": "rgba(156, 46, 35, 0.60)", + "c-primary-dark-200-alpha-500": "rgba(156, 46, 35, 0.50)", + "c-primary-dark-200-alpha-600": "rgba(156, 46, 35, 0.40)", + "c-primary-dark-200-alpha-700": "rgba(156, 46, 35, 0.30)", + "c-primary-dark-200-alpha-800": "rgba(156, 46, 35, 0.20)", + "c-primary-dark-200-alpha-900": "rgba(156, 46, 35, 0.10)", + "c-primary-dark-300": "rgb(140,41,32)", + "c-primary-dark-300-alpha-100": "rgba(140, 41, 32, 0.90)", + "c-primary-dark-300-alpha-200": "rgba(140, 41, 32, 0.80)", + "c-primary-dark-300-alpha-300": "rgba(140, 41, 32, 0.70)", + "c-primary-dark-300-alpha-400": "rgba(140, 41, 32, 0.60)", + "c-primary-dark-300-alpha-500": "rgba(140, 41, 32, 0.50)", + "c-primary-dark-300-alpha-600": "rgba(140, 41, 32, 0.40)", + "c-primary-dark-300-alpha-700": "rgba(140, 41, 32, 0.30)", + "c-primary-dark-300-alpha-800": "rgba(140, 41, 32, 0.20)", + "c-primary-dark-300-alpha-900": "rgba(140, 41, 32, 0.10)", + "c-primary-dark-400": "rgb(126,37,29)", + "c-primary-dark-400-alpha-100": "rgba(126, 37, 29, 0.90)", + "c-primary-dark-400-alpha-200": "rgba(126, 37, 29, 0.80)", + "c-primary-dark-400-alpha-300": "rgba(126, 37, 29, 0.70)", + "c-primary-dark-400-alpha-400": "rgba(126, 37, 29, 0.60)", + "c-primary-dark-400-alpha-500": "rgba(126, 37, 29, 0.50)", + "c-primary-dark-400-alpha-600": "rgba(126, 37, 29, 0.40)", + "c-primary-dark-400-alpha-700": "rgba(126, 37, 29, 0.30)", + "c-primary-dark-400-alpha-800": "rgba(126, 37, 29, 0.20)", + "c-primary-dark-400-alpha-900": "rgba(126, 37, 29, 0.10)", + "c-primary-dark-500": "rgb(113,33,26)", + "c-primary-dark-500-alpha-100": "rgba(113, 33, 26, 0.90)", + "c-primary-dark-500-alpha-200": "rgba(113, 33, 26, 0.80)", + "c-primary-dark-500-alpha-300": "rgba(113, 33, 26, 0.70)", + "c-primary-dark-500-alpha-400": "rgba(113, 33, 26, 0.60)", + "c-primary-dark-500-alpha-500": "rgba(113, 33, 26, 0.50)", + "c-primary-dark-500-alpha-600": "rgba(113, 33, 26, 0.40)", + "c-primary-dark-500-alpha-700": "rgba(113, 33, 26, 0.30)", + "c-primary-dark-500-alpha-800": "rgba(113, 33, 26, 0.20)", + "c-primary-dark-500-alpha-900": "rgba(113, 33, 26, 0.10)", + "c-primary-dark-600": "rgb(102,30,23)", + "c-primary-dark-600-alpha-100": "rgba(102, 30, 23, 0.90)", + "c-primary-dark-600-alpha-200": "rgba(102, 30, 23, 0.80)", + "c-primary-dark-600-alpha-300": "rgba(102, 30, 23, 0.70)", + "c-primary-dark-600-alpha-400": "rgba(102, 30, 23, 0.60)", + "c-primary-dark-600-alpha-500": "rgba(102, 30, 23, 0.50)", + "c-primary-dark-600-alpha-600": "rgba(102, 30, 23, 0.40)", + "c-primary-dark-600-alpha-700": "rgba(102, 30, 23, 0.30)", + "c-primary-dark-600-alpha-800": "rgba(102, 30, 23, 0.20)", + "c-primary-dark-600-alpha-900": "rgba(102, 30, 23, 0.10)", + "c-primary-dark-700": "rgb(92,27,21)", + "c-primary-dark-700-alpha-100": "rgba(92, 27, 21, 0.90)", + "c-primary-dark-700-alpha-200": "rgba(92, 27, 21, 0.80)", + "c-primary-dark-700-alpha-300": "rgba(92, 27, 21, 0.70)", + "c-primary-dark-700-alpha-400": "rgba(92, 27, 21, 0.60)", + "c-primary-dark-700-alpha-500": "rgba(92, 27, 21, 0.50)", + "c-primary-dark-700-alpha-600": "rgba(92, 27, 21, 0.40)", + "c-primary-dark-700-alpha-700": "rgba(92, 27, 21, 0.30)", + "c-primary-dark-700-alpha-800": "rgba(92, 27, 21, 0.20)", + "c-primary-dark-700-alpha-900": "rgba(92, 27, 21, 0.10)", + "c-primary-dark-800": "rgb(83,24,19)", + "c-primary-dark-800-alpha-100": "rgba(83, 24, 19, 0.90)", + "c-primary-dark-800-alpha-200": "rgba(83, 24, 19, 0.80)", + "c-primary-dark-800-alpha-300": "rgba(83, 24, 19, 0.70)", + "c-primary-dark-800-alpha-400": "rgba(83, 24, 19, 0.60)", + "c-primary-dark-800-alpha-500": "rgba(83, 24, 19, 0.50)", + "c-primary-dark-800-alpha-600": "rgba(83, 24, 19, 0.40)", + "c-primary-dark-800-alpha-700": "rgba(83, 24, 19, 0.30)", + "c-primary-dark-800-alpha-800": "rgba(83, 24, 19, 0.20)", + "c-primary-dark-800-alpha-900": "rgba(83, 24, 19, 0.10)", + "c-primary-dark-900": "rgb(75,22,17)", + "c-primary-dark-900-alpha-100": "rgba(75, 22, 17, 0.90)", + "c-primary-dark-900-alpha-200": "rgba(75, 22, 17, 0.80)", + "c-primary-dark-900-alpha-300": "rgba(75, 22, 17, 0.70)", + "c-primary-dark-900-alpha-400": "rgba(75, 22, 17, 0.60)", + "c-primary-dark-900-alpha-500": "rgba(75, 22, 17, 0.50)", + "c-primary-dark-900-alpha-600": "rgba(75, 22, 17, 0.40)", + "c-primary-dark-900-alpha-700": "rgba(75, 22, 17, 0.30)", + "c-primary-dark-900-alpha-800": "rgba(75, 22, 17, 0.20)", + "c-primary-dark-900-alpha-900": "rgba(75, 22, 17, 0.10)", + "c-primary-dark-1000": "rgb(68,20,15)", + "c-primary-dark-1000-alpha-100": "rgba(68, 20, 15, 0.90)", + "c-primary-dark-1000-alpha-200": "rgba(68, 20, 15, 0.80)", + "c-primary-dark-1000-alpha-300": "rgba(68, 20, 15, 0.70)", + "c-primary-dark-1000-alpha-400": "rgba(68, 20, 15, 0.60)", + "c-primary-dark-1000-alpha-500": "rgba(68, 20, 15, 0.50)", + "c-primary-dark-1000-alpha-600": "rgba(68, 20, 15, 0.40)", + "c-primary-dark-1000-alpha-700": "rgba(68, 20, 15, 0.30)", + "c-primary-dark-1000-alpha-800": "rgba(68, 20, 15, 0.20)", + "c-primary-dark-1000-alpha-900": "rgba(68, 20, 15, 0.10)", + "c-primary-light-100": "rgb(205,97,85)", + "c-primary-light-100-alpha-100": "rgba(205, 97, 85, 0.90)", + "c-primary-light-100-alpha-200": "rgba(205, 97, 85, 0.80)", + "c-primary-light-100-alpha-300": "rgba(205, 97, 85, 0.70)", + "c-primary-light-100-alpha-400": "rgba(205, 97, 85, 0.60)", + "c-primary-light-100-alpha-500": "rgba(205, 97, 85, 0.50)", + "c-primary-light-100-alpha-600": "rgba(205, 97, 85, 0.40)", + "c-primary-light-100-alpha-700": "rgba(205, 97, 85, 0.30)", + "c-primary-light-100-alpha-800": "rgba(205, 97, 85, 0.20)", + "c-primary-light-100-alpha-900": "rgba(205, 97, 85, 0.10)", + "c-primary-light-200": "rgb(215,129,119)", + "c-primary-light-200-alpha-100": "rgba(215, 129, 119, 0.90)", + "c-primary-light-200-alpha-200": "rgba(215, 129, 119, 0.80)", + "c-primary-light-200-alpha-300": "rgba(215, 129, 119, 0.70)", + "c-primary-light-200-alpha-400": "rgba(215, 129, 119, 0.60)", + "c-primary-light-200-alpha-500": "rgba(215, 129, 119, 0.50)", + "c-primary-light-200-alpha-600": "rgba(215, 129, 119, 0.40)", + "c-primary-light-200-alpha-700": "rgba(215, 129, 119, 0.30)", + "c-primary-light-200-alpha-800": "rgba(215, 129, 119, 0.20)", + "c-primary-light-200-alpha-900": "rgba(215, 129, 119, 0.10)", + "c-primary-light-300": "rgb(223,154,146)", + "c-primary-light-300-alpha-100": "rgba(223, 154, 146, 0.90)", + "c-primary-light-300-alpha-200": "rgba(223, 154, 146, 0.80)", + "c-primary-light-300-alpha-300": "rgba(223, 154, 146, 0.70)", + "c-primary-light-300-alpha-400": "rgba(223, 154, 146, 0.60)", + "c-primary-light-300-alpha-500": "rgba(223, 154, 146, 0.50)", + "c-primary-light-300-alpha-600": "rgba(223, 154, 146, 0.40)", + "c-primary-light-300-alpha-700": "rgba(223, 154, 146, 0.30)", + "c-primary-light-300-alpha-800": "rgba(223, 154, 146, 0.20)", + "c-primary-light-300-alpha-900": "rgba(223, 154, 146, 0.10)", + "c-primary-light-400": "rgb(229,174,168)", + "c-primary-light-400-alpha-100": "rgba(229, 174, 168, 0.90)", + "c-primary-light-400-alpha-200": "rgba(229, 174, 168, 0.80)", + "c-primary-light-400-alpha-300": "rgba(229, 174, 168, 0.70)", + "c-primary-light-400-alpha-400": "rgba(229, 174, 168, 0.60)", + "c-primary-light-400-alpha-500": "rgba(229, 174, 168, 0.50)", + "c-primary-light-400-alpha-600": "rgba(229, 174, 168, 0.40)", + "c-primary-light-400-alpha-700": "rgba(229, 174, 168, 0.30)", + "c-primary-light-400-alpha-800": "rgba(229, 174, 168, 0.20)", + "c-primary-light-400-alpha-900": "rgba(229, 174, 168, 0.10)", + "c-primary-light-500": "rgb(234,190,185)", + "c-primary-light-500-alpha-100": "rgba(234, 190, 185, 0.90)", + "c-primary-light-500-alpha-200": "rgba(234, 190, 185, 0.80)", + "c-primary-light-500-alpha-300": "rgba(234, 190, 185, 0.70)", + "c-primary-light-500-alpha-400": "rgba(234, 190, 185, 0.60)", + "c-primary-light-500-alpha-500": "rgba(234, 190, 185, 0.50)", + "c-primary-light-500-alpha-600": "rgba(234, 190, 185, 0.40)", + "c-primary-light-500-alpha-700": "rgba(234, 190, 185, 0.30)", + "c-primary-light-500-alpha-800": "rgba(234, 190, 185, 0.20)", + "c-primary-light-500-alpha-900": "rgba(234, 190, 185, 0.10)", + "c-primary-light-600": "rgb(238,203,199)", + "c-primary-light-600-alpha-100": "rgba(238, 203, 199, 0.90)", + "c-primary-light-600-alpha-200": "rgba(238, 203, 199, 0.80)", + "c-primary-light-600-alpha-300": "rgba(238, 203, 199, 0.70)", + "c-primary-light-600-alpha-400": "rgba(238, 203, 199, 0.60)", + "c-primary-light-600-alpha-500": "rgba(238, 203, 199, 0.50)", + "c-primary-light-600-alpha-600": "rgba(238, 203, 199, 0.40)", + "c-primary-light-600-alpha-700": "rgba(238, 203, 199, 0.30)", + "c-primary-light-600-alpha-800": "rgba(238, 203, 199, 0.20)", + "c-primary-light-600-alpha-900": "rgba(238, 203, 199, 0.10)", + "c-primary-light-700": "rgb(241,213,210)", + "c-primary-light-700-alpha-100": "rgba(241, 213, 210, 0.90)", + "c-primary-light-700-alpha-200": "rgba(241, 213, 210, 0.80)", + "c-primary-light-700-alpha-300": "rgba(241, 213, 210, 0.70)", + "c-primary-light-700-alpha-400": "rgba(241, 213, 210, 0.60)", + "c-primary-light-700-alpha-500": "rgba(241, 213, 210, 0.50)", + "c-primary-light-700-alpha-600": "rgba(241, 213, 210, 0.40)", + "c-primary-light-700-alpha-700": "rgba(241, 213, 210, 0.30)", + "c-primary-light-700-alpha-800": "rgba(241, 213, 210, 0.20)", + "c-primary-light-700-alpha-900": "rgba(241, 213, 210, 0.10)", + "c-primary-light-800": "rgb(244,221,219)", + "c-primary-light-800-alpha-100": "rgba(244, 221, 219, 0.90)", + "c-primary-light-800-alpha-200": "rgba(244, 221, 219, 0.80)", + "c-primary-light-800-alpha-300": "rgba(244, 221, 219, 0.70)", + "c-primary-light-800-alpha-400": "rgba(244, 221, 219, 0.60)", + "c-primary-light-800-alpha-500": "rgba(244, 221, 219, 0.50)", + "c-primary-light-800-alpha-600": "rgba(244, 221, 219, 0.40)", + "c-primary-light-800-alpha-700": "rgba(244, 221, 219, 0.30)", + "c-primary-light-800-alpha-800": "rgba(244, 221, 219, 0.20)", + "c-primary-light-800-alpha-900": "rgba(244, 221, 219, 0.10)", + "c-primary-light-900": "rgb(246,228,226)", + "c-primary-light-900-alpha-100": "rgba(246, 228, 226, 0.90)", + "c-primary-light-900-alpha-200": "rgba(246, 228, 226, 0.80)", + "c-primary-light-900-alpha-300": "rgba(246, 228, 226, 0.70)", + "c-primary-light-900-alpha-400": "rgba(246, 228, 226, 0.60)", + "c-primary-light-900-alpha-500": "rgba(246, 228, 226, 0.50)", + "c-primary-light-900-alpha-600": "rgba(246, 228, 226, 0.40)", + "c-primary-light-900-alpha-700": "rgba(246, 228, 226, 0.30)", + "c-primary-light-900-alpha-800": "rgba(246, 228, 226, 0.20)", + "c-primary-light-900-alpha-900": "rgba(246, 228, 226, 0.10)", + "c-primary-light-1000": "rgb(255,255,255)", + "c-primary-light-1000-alpha-100": "rgba(255, 255, 255, 0.90)", + "c-primary-light-1000-alpha-200": "rgba(255, 255, 255, 0.80)", + "c-primary-light-1000-alpha-300": "rgba(255, 255, 255, 0.70)", + "c-primary-light-1000-alpha-400": "rgba(255, 255, 255, 0.60)", + "c-primary-light-1000-alpha-500": "rgba(255, 255, 255, 0.50)", + "c-primary-light-1000-alpha-600": "rgba(255, 255, 255, 0.40)", + "c-primary-light-1000-alpha-700": "rgba(255, 255, 255, 0.30)", + "c-primary-light-1000-alpha-800": "rgba(255, 255, 255, 0.20)", + "c-primary-light-1000-alpha-900": "rgba(255, 255, 255, 0.10)", + "c-theme": "rgb(192, 57, 43)", + "c-1000": "rgb(33, 33, 33)", + "c-950": "rgb(44,44,44)", + "c-900": "rgb(55,55,55)", + "c-850": "rgb(66,66,66)", + "c-800": "rgb(77,77,77)", + "c-750": "rgb(89,89,89)", + "c-700": "rgb(100,100,100)", + "c-650": "rgb(111,111,111)", + "c-600": "rgb(122,122,122)", + "c-550": "rgb(133,133,133)", + "c-500": "rgb(144,144,144)", + "c-450": "rgb(155,155,155)", + "c-400": "rgb(166,166,166)", + "c-350": "rgb(177,177,177)", + "c-300": "rgb(188,188,188)", + "c-250": "rgb(200,200,200)", + "c-200": "rgb(211,211,211)", + "c-150": "rgb(222,222,222)", + "c-100": "rgb(233,233,233)", + "c-050": "rgb(244,244,244)", + "c-000": "rgb(255,255,255)" + }, + "extInfo": { + "c-app-background": "rgba(255, 255, 255, 0.15)", + "c-main-background": "rgba(255, 255, 255, 0.8)", + "bg-image": "xnkl.png", + "bg-image-position": "center", + "bg-image-size": "cover", + "c-badge-primary": "#7fb575", + "c-badge-secondary": "#dfbb6b", + "c-badge-tertiary": "var(c-primary-light-100)" + } + } + } +] as const \ No newline at end of file diff --git a/src/theme/themes/utils.js b/src/theme/themes/utils.js new file mode 100644 index 000000000..93a4a63c2 --- /dev/null +++ b/src/theme/themes/utils.js @@ -0,0 +1,75 @@ +const { RGB_Linear_Shade, RGB_Alpha_Shade } = require('./colorUtils') + +exports.createThemeColors = (rgbaColor, fontRgbaColor, isDark) => { + const colors = { + 'c-primary': rgbaColor, + } + + let preColor = rgbaColor + for (let i = 1; i < 11; i += 1) { + preColor = RGB_Linear_Shade(isDark ? 0.2 : -0.1, preColor) + colors[`c-primary-dark-${i * 100}`] = preColor + for (let j = 1; j < 10; j += 1) { + colors[`c-primary-dark-${i * 100}-alpha-${j * 100}`] = RGB_Alpha_Shade(0.1 * j, preColor) + colors[`c-primary-alpha-${j * 100}`] = RGB_Alpha_Shade(0.1 * j, rgbaColor) + } + } + preColor = rgbaColor + for (let i = 1; i < 10; i += 1) { + preColor = RGB_Linear_Shade(isDark ? -0.1 : 0.2, preColor) + colors[`c-primary-light-${i * 100}`] = preColor + for (let j = 1; j < 10; j += 1) { + colors[`c-primary-light-${i * 100}-alpha-${j * 100}`] = RGB_Alpha_Shade(0.1 * j, preColor) + } + } + preColor = RGB_Linear_Shade(isDark ? -0.2 : 1, preColor) + colors[`c-primary-light-${1000}`] = preColor + for (let j = 1; j < 10; j += 1) { + colors[`c-primary-light-${1000}-alpha-${j * 100}`] = RGB_Alpha_Shade(0.1 * j, preColor) + } + + colors['c-theme'] = isDark ? colors['c-primary-light-900'] : rgbaColor + + return { ...colors, ...createFontColors(fontRgbaColor, isDark) } +} + +const createFontColors = (rgbaColor, isDark) => { + // rgb(238, 238, 238) + // let prec = 'rgb(255, 255, 255)' + if (rgbaColor == null) rgbaColor = isDark ? 'rgb(229, 229, 229)' : 'rgb(33, 33, 33)' + if (isDark) return createFontDarkColors(rgbaColor) + + let colors = { + 'c-1000': rgbaColor, + } + let step = isDark ? -0.05 : 0.05 + for (let i = 1; i < 21; i += 1) { + colors[`c-${String(1000 - 50 * i).padStart(3, '0')}`] = RGB_Linear_Shade(step * i, rgbaColor) + } + // console.log(colors) + return colors +} + +const createFontDarkColors = (rgbaColor) => { + // rgb(238, 238, 238) + // let prec = 'rgb(255, 255, 255)' + + let colors = { + 'c-1000': rgbaColor, + } + const step = -0.05 + let preColor = rgbaColor + for (let i = 1; i < 21; i += 1) { + preColor = RGB_Linear_Shade(step, preColor) + colors[`c-${String(1000 - 50 * i).padStart(3, '0')}`] = preColor + } + + // console.log(colors) + return colors +} + +// console.log(createFontColors('rgb(33, 33, 33)', false)) +// console.log(createFontColors('rgb(255, 255, 255)', true)) + +// console.log(createFontDarkColors('rgb(255, 255, 255)')) + diff --git a/src/types/app.d.ts b/src/types/app.d.ts new file mode 100644 index 000000000..48d6010dc --- /dev/null +++ b/src/types/app.d.ts @@ -0,0 +1,70 @@ +/* eslint-disable no-var */ +import type { AppEventTypes } from '@/event/appEvent' +import type { ListEventTypes } from '@/event/listEvent' +import type { StateEventTypes } from '@/event/stateEvent' +import type { I18n } from '@/lang/i18n' +import type { Buffer as _Buffer } from 'buffer' + +// interface Process { +// env: { +// NODE_ENV: 'development' | 'production' +// } +// versions: { +// app: string +// } +// } +interface Lx { + fontSize: number + gettingUrlId: string + + // event_app: AppType + // event_list: ListType + + playerStatus: { + isInitialized: boolean + isRegisteredService: boolean + isIniting: boolean + } + restorePlayInfo: LX.Player.SavedPlayInfo | null + isScreenKeepAwake: boolean + isPlayedStop: boolean + isSyncEnableing: boolean + isEnableSyncLog: boolean + playerTrackId: string + + qualityList: LX.QualityList + + jumpMyListPosition: boolean + + // windowInfo: { + // screenW: number + // screenH: number + // fontScale: number + // pixelRatio: number + // screenPxW: number + // screenPxH: number + // } + + // syncKeyInfo: LX.Sync.KeyInfo +} + + +declare global { + var isDev: boolean + var lx: Lx + var i18n: I18n + var app_event: AppEventTypes + var list_event: ListEventTypes + var state_event: StateEventTypes + + var Buffer: typeof _Buffer + + module NodeJS { + interface ProcessVersions { + app: string + } + } + // var process: Process +} + +export {} diff --git a/src/types/app_setting.d.ts b/src/types/app_setting.d.ts new file mode 100644 index 000000000..7809ed342 --- /dev/null +++ b/src/types/app_setting.d.ts @@ -0,0 +1,251 @@ +import type { I18n } from '@/lang/i18n' + +declare global { + namespace LX { + type AddMusicLocationType = 'top' | 'bottom' + + interface AppSetting { + version: string + /** + * 是否跟随系统切换亮暗主题 + */ + 'common.isAutoTheme': boolean + + /** + * 语言id + */ + 'common.langId': I18n['locale'] | null + + /** + * api id + */ + 'common.apiSource': string + + /** + * 音源名称类型,原名、别名 + */ + 'common.sourceNameType': 'alias' | 'real' + + /** + * 歌曲分享方式 + */ + 'common.shareType': 'system' | 'clipboard' + + /** + * 是否同意软件协议 + */ + 'common.isAgreePact': boolean + + /** + * 是否在键盘弹出时隐藏播放栏 + */ + 'common.autoHidePlayBar': boolean + + /** + * 抽屉组件弹出方向 + */ + 'common.drawerLayoutPosition': 'left' | 'right' + + /** + * 主题id + */ + 'theme.id': string + + /** + * 亮色主题id + */ + 'theme.lightId': string + + /** + * 暗色主题id + */ + 'theme.darkId': string + + /** + * 启动时自动播放歌曲 + */ + 'player.startupAutoPlay': boolean + + /** + * 切歌模式 + */ + 'player.togglePlayMethod': 'listLoop' | 'random' | 'list' | 'singleLoop' | 'none' + + /** + * 是否优先播放320k音质 + */ + 'player.isPlayHighQuality': boolean + + /** + * 启动软件时是否恢复上次播放进度 + */ + 'player.isSavePlayTime': boolean + + /** + * 缓存大小设置 unit MB + */ + 'player.cacheSize': string + + /** + * 定时暂停播放-倒计时时间 + */ + 'player.timeoutExit': string + + /** + * 定时暂停播放-是否等待歌曲播放完毕再暂停 + */ + 'player.timeoutExitPlayed': boolean + + /** + * 其他应用播放声音时是否自动暂停 + */ + 'player.isHandleAudioFocus': boolean + + /** + * 是否显示歌词翻译 + */ + 'player.isShowLyricTranslation': boolean + + /** + * 是否显示歌词罗马音 + */ + 'player.isShowLyricRoma': boolean + + /** + * 是否在通知栏显示歌曲图片 + */ + 'player.isShowNotificationImage': boolean + + /** + * 是否将歌词从简体转换为繁体 + */ + 'player.isS2t': boolean + + /** + * 竖屏歌词字体大小 + */ + 'player.vertical.style.lrcFontSize': number + + /** + * 横屏歌词字体大小 + */ + 'player.horizontal.style.lrcFontSize': number + + /** + * 是否启用桌面歌词 + */ + 'desktopLyric.enable': boolean + + /** + * 是否锁定桌面歌词 + */ + 'desktopLyric.isLock': boolean + + /** + * 桌面歌词窗口宽度 + */ + 'desktopLyric.width': number + + /** + * 桌面歌词最大行数 + */ + 'desktopLyric.maxLineNum': number + + /** + * 桌面歌词是否使用单行显示 + */ + 'desktopLyric.isSingleLine': boolean + + /** + * 桌面歌词是否启用歌词切换动画 + */ + 'desktopLyric.showToggleAnima': boolean + + /** + * 桌面歌词窗口x坐标 + */ + 'desktopLyric.position.x': number + + /** + * 桌面歌词窗口y坐标 + */ + 'desktopLyric.position.y': number + + /** + * 歌词水平对齐方式 + */ + 'desktopLyric.textPosition.x': 'left' | 'center' | 'right' + + /** + * 歌词垂直对齐方式 + */ + 'desktopLyric.textPosition.y': 'top' | 'center' | 'bottom' + + /** + * 桌面歌词字体大小 + */ + 'desktopLyric.style.fontSize': number + + /** + * 桌面歌词字体透明度 + */ + 'desktopLyric.style.opacity': number + + /** + * 桌面歌词未播放字体颜色 + */ + 'desktopLyric.style.lyricUnplayColor': string + + /** + * 桌面歌词已播放字体颜色 + */ + 'desktopLyric.style.lyricPlayedColor': string + + /** + * 桌面歌词字体阴影颜色 + */ + 'desktopLyric.style.lyricShadowColor': string + + /** + * 是否显示热门搜索 + */ + 'search.isShowHotSearch': boolean + + /** + * 是否显示搜索历史 + */ + 'search.isShowHistorySearch': boolean + + /** + * 是否启用双击列表里的歌曲时自动切换到当前列表播放(仅对歌单、排行榜有效) + */ + 'list.isClickPlayList': boolean + + /** + * 是否显示歌曲来源(仅对我的列表有效) + */ + 'list.isShowSource': boolean + + /** + * 是否自动恢复列表滚动位置(仅对我的列表有效) + */ + 'list.isSaveScrollLocation': boolean + + /** + * 添加歌曲到我的列表时的方式 + */ + 'list.addMusicLocationType': AddMusicLocationType + + /** + * 文件命名方式 + */ + 'download.fileName': '歌名 - 歌手' | '歌手 - 歌名' | '歌名' + + /** + * 是否启用同步 + */ + 'sync.enable': boolean + } + } +} + diff --git a/src/types/common.d.ts b/src/types/common.d.ts new file mode 100644 index 000000000..21ecd6061 --- /dev/null +++ b/src/types/common.d.ts @@ -0,0 +1,16 @@ +// import './app_setting' + +declare namespace LX { + type OnlineSource = 'kw' | 'kg' | 'tx' | 'wy' | 'mg' + type Source = OnlineSource | 'local' + type Quality = '128k' | '320k' | 'flac' | 'flac24bit' | '192k' | 'ape' | 'wav' + type QualityList = Partial<Record<LX.Source, LX.Quality[]>> + + type ShareType = 'system' | 'clipboard' + + type UpdateStatus = 'downloaded' | 'downloading' | 'error' | 'checking' | 'idle' + interface VersionInfo { + version: string + desc: string + } +} diff --git a/src/types/config_files.d.ts b/src/types/config_files.d.ts new file mode 100644 index 000000000..b61c18806 --- /dev/null +++ b/src/types/config_files.d.ts @@ -0,0 +1,9 @@ +declare namespace LX { + namespace ConfigFile { + interface MyListInfoPart { + type: 'playListPart_v2' + data: LX.List.MyDefaultListInfoFull | LX.List.MyLoveListInfoFull | LX.List.UserListInfoFull + } + + } +} diff --git a/src/types/download_list.d.ts b/src/types/download_list.d.ts new file mode 100644 index 000000000..ed9698353 --- /dev/null +++ b/src/types/download_list.d.ts @@ -0,0 +1,66 @@ + +// interface DownloadList { + +// } + + +declare namespace LX { + namespace Download { + type DownloadTaskStatus = 'run' + | 'waiting' + | 'pause' + | 'error' + | 'completed' + + type FileExt = 'mp3' | 'flac' | 'wav' | 'ape' + + interface ProgressInfo { + progress: number + speed: string + downloaded: number + total: number + } + + interface DownloadTaskActionBase <A> { + action: A + } + interface DownloadTaskActionData<A, D> extends DownloadTaskActionBase<A> { + data: D + } + type DownloadTaskAction<A, D = undefined> = D extends undefined ? DownloadTaskActionBase<A> : DownloadTaskActionData<A, D> + + type DownloadTaskActions = DownloadTaskAction<'start'> + | DownloadTaskAction<'complete'> + | DownloadTaskAction<'refreshUrl'> + | DownloadTaskAction<'statusText', string> + | DownloadTaskAction<'progress', ProgressInfo> + | DownloadTaskAction<'error', { + error?: string + message?: string + }> + + interface ListItem { + id: string + isComplate: boolean + status: DownloadTaskStatus + statusText: string + downloaded: number + total: number + progress: number + speed: string + metadata: { + musicInfo: LX.Music.MusicInfoOnline + url: string | null + quality: LX.Quality + ext: FileExt + fileName: string + filePath: string + } + } + + interface saveDownloadMusicInfo { + list: ListItem[] + addMusicLocationType: LX.AddMusicLocationType + } + } +} diff --git a/src/types/list.d.ts b/src/types/list.d.ts new file mode 100644 index 000000000..2e4623bff --- /dev/null +++ b/src/types/list.d.ts @@ -0,0 +1,143 @@ +declare namespace LX { + namespace List { + interface UserListInfo { + id: string + name: string + // list: LX.Music.MusicInfo[] + source?: LX.OnlineSource + sourceListId?: string + // position?: number + locationUpdateTime: number | null + } + + interface MyDefaultListInfo { + id: 'default' + name: '试听列表' + // list: LX.Music.MusicInfo[] + } + + interface MyLoveListInfo { + id: 'love' + name: '我的收藏' + // list: LX.Music.MusicInfo[] + } + + interface MyTempListInfo { + id: 'temp' + name: '临时列表' + // list: LX.Music.MusicInfo[] + // TODO: save default lists info + meta: { + id?: string + } + } + + type MyListInfo = MyDefaultListInfo | MyLoveListInfo | UserListInfo + + interface MyAllList { + defaultList: MyDefaultListInfo + loveList: MyLoveListInfo + userList: UserListInfo[] + tempList: MyTempListInfo + } + + + type SearchHistoryList = string[] + type ListPositionInfo = Record<string, number> + type ListUpdateInfo = Record<string, { + updateTime: number + isAutoUpdate: boolean + }> + + type ListSaveType = 'myList' | 'downloadList' + type ListSaveInfo = { + type: 'myList' + data: Partial<MyAllList> + } | { + type: 'downloadList' + data: LX.Download.ListItem[] + } + + + type ListActionDataOverwrite = MakeOptional<LX.List.ListDataFull, 'tempList'> + interface ListActionAdd { + position: number + listInfos: UserListInfo[] + } + type ListActionRemove = string[] + type ListActionUpdate = UserListInfo[] + interface ListActionUpdatePosition { + /** + * 列表id + */ + ids: string[] + /** + * 位置 + */ + position: number + } + + interface ListActionMusicAdd { + id: string + musicInfos: LX.Music.MusicInfo[] + addMusicLocationType: LX.AddMusicLocationType + } + + interface ListActionMusicMove { + fromId: string + toId: string + musicInfos: LX.Music.MusicInfo[] + addMusicLocationType: LX.AddMusicLocationType + } + + interface ListActionCheckMusicExistList { + listId: string + musicInfoId: string + } + + interface ListActionMusicRemove { + listId: string + ids: string[] + } + + type ListActionMusicUpdate = Array<{ + id: string + musicInfo: LX.Music.MusicInfo + }> + + interface ListActionMusicUpdatePosition { + listId: string + position: number + ids: string[] + } + + interface ListActionMusicOverwrite { + listId: string + musicInfos: LX.Music.MusicInfo[] + } + + type ListActionMusicClear = string[] + + interface MyDefaultListInfoFull extends MyDefaultListInfo { + list: LX.Music.MusicInfo[] + } + interface MyLoveListInfoFull extends MyLoveListInfo { + list: LX.Music.MusicInfo[] + } + interface UserListInfoFull extends UserListInfo { + list: LX.Music.MusicInfo[] + } + interface MyTempListInfoFull extends MyTempListInfo { + list: LX.Music.MusicInfo[] + } + + interface ListDataFull { + defaultList: LX.Music.MusicInfo[] + loveList: LX.Music.MusicInfo[] + userList: UserListInfoFull[] + tempList: LX.Music.MusicInfo[] + } + + type ListMusics = LX.Music.MusicInfo[] + } +} diff --git a/src/types/music.d.ts b/src/types/music.d.ts new file mode 100644 index 000000000..12be91bf6 --- /dev/null +++ b/src/types/music.d.ts @@ -0,0 +1,122 @@ +declare namespace LX { + namespace Music { + interface MusicQualityType { // {"type": "128k", size: "3.56M"} + type: LX.Quality + size: string | null + } + interface MusicQualityTypeKg { // {"type": "128k", size: "3.56M"} + type: LX.Quality + size: string | null + hash: string + } + type _MusicQualityType = Partial<Record<Quality, { + size: string | null + }>> + type _MusicQualityTypeKg = Partial<Record<Quality, { + size: string | null + hash: string + }>> + + + interface MusicInfoMetaBase { + songId: string | number // 歌曲ID,mg源为copyrightId,local为文件路径 + albumName: string // 歌曲专辑名称 + picUrl?: string | null // 歌曲图片链接 + } + + interface MusicInfoMeta_online extends MusicInfoMetaBase { + qualitys: MusicQualityType[] + _qualitys: _MusicQualityType + albumId?: string | number // 歌曲专辑ID + } + + interface MusicInfoMeta_local extends MusicInfoMetaBase { + filePath: string + ext: string + } + + + interface MusicInfoBase<S = LX.Source> { + id: string + name: string // 歌曲名 + singer: string // 艺术家名 + source: S // 源 + interval: string | null // 格式化后的歌曲时长,例:03:55 + meta: MusicInfoMetaBase + } + + interface MusicInfoLocal extends MusicInfoBase<'local'> { + meta: MusicInfoMeta_local + } + + interface MusicInfo_online_common extends MusicInfoBase<'kw' | 'wy'> { + meta: MusicInfoMeta_online + } + + interface MusicInfoMeta_kg extends MusicInfoMeta_online { + qualitys: MusicQualityTypeKg[] + _qualitys: _MusicQualityTypeKg + hash: string // 歌曲hash + } + interface MusicInfo_kg extends MusicInfoBase<'kg'> { + meta: MusicInfoMeta_kg + } + + interface MusicInfoMeta_tx extends MusicInfoMeta_online { + strMediaMid: string // 歌曲strMediaMid + id?: number // 歌曲songId + albumMid?: string // 歌曲albumMid + } + interface MusicInfo_tx extends MusicInfoBase<'tx'> { + meta: MusicInfoMeta_tx + } + + interface MusicInfoMeta_mg extends MusicInfoMeta_online { + copyrightId: string // 歌曲copyrightId + lrcUrl?: string // 歌曲lrcUrl + mrcUrl?: string // 歌曲mrcUrl + trcUrl?: string // 歌曲trcUrl + } + interface MusicInfo_mg extends MusicInfoBase<'mg'> { + meta: MusicInfoMeta_mg + } + + type MusicInfoOnline = MusicInfo_online_common | MusicInfo_kg | MusicInfo_tx | MusicInfo_mg + type MusicInfo = MusicInfoOnline | MusicInfoLocal + + interface LyricInfo { + // 歌曲歌词 + lyric: string + // 翻译歌词 + tlyric?: string | null + // 罗马音歌词 + rlyric?: string | null + // 逐字歌词 + lxlyric?: string | null + } + + interface LyricInfoSave { + id: string + lyrics: LyricInfo + } + + interface MusicFileMeta { + title: string + artist: string | null + album: string | null + APIC: string | null + lyrics: string | null + } + + interface MusicUrlInfo { + id: string + url: string + } + + interface MusicInfoOtherSourceSave { + id: string + list: MusicInfoOnline[] + } + + } +} diff --git a/src/types/player.d.ts b/src/types/player.d.ts new file mode 100644 index 000000000..3ab0c4ca6 --- /dev/null +++ b/src/types/player.d.ts @@ -0,0 +1,86 @@ +import type { Track as RNTrack } from 'react-native-track-player' + +declare global { + namespace LX { + namespace Player { + interface MusicInfo { + id: string | null + pic: string | null | undefined + lrc: string | null + tlrc: string | null + rlrc: string | null + lxlrc: string | null + rawlrc: string | null + // url: string | null + name: string + singer: string + album: string + } + + interface LyricInfo extends LX.Music.LyricInfo { + rawlrcInfo: LX.Music.LyricInfo + } + + type PlayMusic = LX.Music.MusicInfo | LX.Download.ListItem + + type PlayMusicInfo = Readonly<{ + /** + * 当前播放歌曲的列表 id + */ + musicInfo: PlayMusic + /** + * 当前播放歌曲的列表 id + */ + listId: string + /** + * 是否属于 “稍后播放” + */ + isTempPlay: boolean + }> + + interface PlayInfo { + /** + * 当前正在播放歌曲 index + */ + playIndex: number + /** + * 播放器的播放列表 id + */ + playerListId: string | null + /** + * 播放器播放歌曲 index + */ + playerPlayIndex: number + } + + interface TempPlayListItem { + /** + * 播放列表id + */ + listId: string + /** + * 歌曲信息 + */ + musicInfo: PlayMusic + /** + * 是否添加到列表顶部 + */ + isTop?: boolean + } + + interface SavedPlayInfo { + time: number + maxTime: number + listId: string + index: number + } + + interface Track extends RNTrack { + musicId: string + original: PlayMusic + // quality: LX.Quality + } + + } + } +} diff --git a/src/types/shims.d.ts b/src/types/shims.d.ts new file mode 100644 index 000000000..3031be172 --- /dev/null +++ b/src/types/shims.d.ts @@ -0,0 +1,5 @@ + +declare module 'crypto' { + import crypto from 'react-native-quick-crypto' + export default crypto +} diff --git a/src/types/sync.d.ts b/src/types/sync.d.ts new file mode 100644 index 000000000..963c246ca --- /dev/null +++ b/src/types/sync.d.ts @@ -0,0 +1,80 @@ +import { io } from 'socket.io-client' + +declare global { + namespace LX { + namespace Sync { + + interface Enable { + enable: boolean + port: string + } + + interface SyncActionBase <A> { + action: A + } + interface SyncActionData<A, D> extends SyncActionBase<A> { + data: D + } + type SyncAction<A, D = undefined> = D extends undefined ? SyncActionBase<A> : SyncActionData<A, D> + + // type SyncMainWindowActions = SyncAction<'select_mode', KeyInfo> + // | SyncAction<'close_select_mode'> + // | SyncAction<'status', Status> + + // type SyncServiceActions = SyncAction<'select_mode', Mode> + // | SyncAction<'get_status'> + // | SyncAction<'generate_code'> + // | SyncAction<'enable', Enable> + + type ActionList = SyncAction<'list_data_overwrite', LX.List.ListActionDataOverwrite> + | SyncAction<'list_create', LX.List.ListActionAdd> + | SyncAction<'list_remove', LX.List.ListActionRemove> + | SyncAction<'list_update', LX.List.ListActionUpdate> + | SyncAction<'list_update_position', LX.List.ListActionUpdatePosition> + | SyncAction<'list_music_add', LX.List.ListActionMusicAdd> + | SyncAction<'list_music_move', LX.List.ListActionMusicMove> + | SyncAction<'list_music_remove', LX.List.ListActionMusicRemove> + | SyncAction<'list_music_update', LX.List.ListActionMusicUpdate> + | SyncAction<'list_music_update_position', LX.List.ListActionMusicUpdatePosition> + | SyncAction<'list_music_overwrite', LX.List.ListActionMusicOverwrite> + | SyncAction<'list_music_clear', LX.List.ListActionMusicClear> + + type SyncClientActionGetData = 'all' + type SyncClientAction = SyncAction<'getData', SyncClientActionGetData> + | SyncAction<'setData', ListData> + | SyncAction<'finished'> + + + interface List { + action: string + data: any + } + + interface Status { + status: boolean + message: string + } + + interface KeyInfo { + clientId: string + key: string + deviceName: string + connectionTime?: number + } + + type ListData = Omit<LX.List.ListDataFull, 'tempList'> + + type Mode = 'merge_local_remote' + | 'merge_remote_local' + | 'overwrite_local_remote' + | 'overwrite_remote_local' + | 'overwrite_local_remote_full' + | 'overwrite_remote_local_full' + | 'none' + | 'cancel' + + type Socket = ReturnType<typeof io> + + } + } +} diff --git a/src/types/theme.d.ts b/src/types/theme.d.ts new file mode 100644 index 000000000..105151e85 --- /dev/null +++ b/src/types/theme.d.ts @@ -0,0 +1,323 @@ +import type { ImageSourcePropType } from 'react-native' + +declare global { + namespace LX { + interface ThemeColors { + 'c-000': string + 'c-050': string + 'c-100': string + 'c-150': string + 'c-200': string + 'c-250': string + 'c-300': string + 'c-350': string + 'c-400': string + 'c-450': string + 'c-500': string + 'c-550': string + 'c-600': string + 'c-650': string + 'c-700': string + 'c-750': string + 'c-800': string + 'c-850': string + 'c-900': string + 'c-950': string + 'c-1000': string + + + 'c-theme': string + + 'c-primary': string + 'c-primary-alpha-100': string + 'c-primary-alpha-200': string + 'c-primary-alpha-300': string + 'c-primary-alpha-400': string + 'c-primary-alpha-500': string + 'c-primary-alpha-600': string + 'c-primary-alpha-700': string + 'c-primary-alpha-800': string + 'c-primary-alpha-900': string + + 'c-primary-dark-100': string + 'c-primary-dark-100-alpha-100': string + 'c-primary-dark-100-alpha-200': string + 'c-primary-dark-100-alpha-300': string + 'c-primary-dark-100-alpha-400': string + 'c-primary-dark-100-alpha-500': string + 'c-primary-dark-100-alpha-600': string + 'c-primary-dark-100-alpha-700': string + 'c-primary-dark-100-alpha-800': string + 'c-primary-dark-100-alpha-900': string + + 'c-primary-dark-200': string + 'c-primary-dark-200-alpha-100': string + 'c-primary-dark-200-alpha-200': string + 'c-primary-dark-200-alpha-300': string + 'c-primary-dark-200-alpha-400': string + 'c-primary-dark-200-alpha-500': string + 'c-primary-dark-200-alpha-600': string + 'c-primary-dark-200-alpha-700': string + 'c-primary-dark-200-alpha-800': string + 'c-primary-dark-200-alpha-900': string + + 'c-primary-dark-300': string + 'c-primary-dark-300-alpha-100': string + 'c-primary-dark-300-alpha-200': string + 'c-primary-dark-300-alpha-300': string + 'c-primary-dark-300-alpha-400': string + 'c-primary-dark-300-alpha-500': string + 'c-primary-dark-300-alpha-600': string + 'c-primary-dark-300-alpha-700': string + 'c-primary-dark-300-alpha-800': string + 'c-primary-dark-300-alpha-900': string + + 'c-primary-dark-400': string + 'c-primary-dark-400-alpha-100': string + 'c-primary-dark-400-alpha-200': string + 'c-primary-dark-400-alpha-300': string + 'c-primary-dark-400-alpha-400': string + 'c-primary-dark-400-alpha-500': string + 'c-primary-dark-400-alpha-600': string + 'c-primary-dark-400-alpha-700': string + 'c-primary-dark-400-alpha-800': string + 'c-primary-dark-400-alpha-900': string + + 'c-primary-dark-500': string + 'c-primary-dark-500-alpha-100': string + 'c-primary-dark-500-alpha-200': string + 'c-primary-dark-500-alpha-300': string + 'c-primary-dark-500-alpha-400': string + 'c-primary-dark-500-alpha-500': string + 'c-primary-dark-500-alpha-600': string + 'c-primary-dark-500-alpha-700': string + 'c-primary-dark-500-alpha-800': string + 'c-primary-dark-500-alpha-900': string + + 'c-primary-dark-600': string + 'c-primary-dark-600-alpha-100': string + 'c-primary-dark-600-alpha-200': string + 'c-primary-dark-600-alpha-300': string + 'c-primary-dark-600-alpha-400': string + 'c-primary-dark-600-alpha-500': string + 'c-primary-dark-600-alpha-600': string + 'c-primary-dark-600-alpha-700': string + 'c-primary-dark-600-alpha-800': string + 'c-primary-dark-600-alpha-900': string + + 'c-primary-dark-700': string + 'c-primary-dark-700-alpha-100': string + 'c-primary-dark-700-alpha-200': string + 'c-primary-dark-700-alpha-300': string + 'c-primary-dark-700-alpha-400': string + 'c-primary-dark-700-alpha-500': string + 'c-primary-dark-700-alpha-600': string + 'c-primary-dark-700-alpha-700': string + 'c-primary-dark-700-alpha-800': string + 'c-primary-dark-700-alpha-900': string + + 'c-primary-dark-800': string + 'c-primary-dark-800-alpha-100': string + 'c-primary-dark-800-alpha-200': string + 'c-primary-dark-800-alpha-300': string + 'c-primary-dark-800-alpha-400': string + 'c-primary-dark-800-alpha-500': string + 'c-primary-dark-800-alpha-600': string + 'c-primary-dark-800-alpha-700': string + 'c-primary-dark-800-alpha-800': string + 'c-primary-dark-800-alpha-900': string + + 'c-primary-dark-900': string + 'c-primary-dark-900-alpha-100': string + 'c-primary-dark-900-alpha-200': string + 'c-primary-dark-900-alpha-300': string + 'c-primary-dark-900-alpha-400': string + 'c-primary-dark-900-alpha-500': string + 'c-primary-dark-900-alpha-600': string + 'c-primary-dark-900-alpha-700': string + 'c-primary-dark-900-alpha-800': string + 'c-primary-dark-900-alpha-900': string + + 'c-primary-dark-1000': string + 'c-primary-dark-1000-alpha-100': string + 'c-primary-dark-1000-alpha-200': string + 'c-primary-dark-1000-alpha-300': string + 'c-primary-dark-1000-alpha-400': string + 'c-primary-dark-1000-alpha-500': string + 'c-primary-dark-1000-alpha-600': string + 'c-primary-dark-1000-alpha-700': string + 'c-primary-dark-1000-alpha-800': string + 'c-primary-dark-1000-alpha-900': string + + 'c-primary-light-100': string + 'c-primary-light-100-alpha-100': string + 'c-primary-light-100-alpha-200': string + 'c-primary-light-100-alpha-300': string + 'c-primary-light-100-alpha-400': string + 'c-primary-light-100-alpha-500': string + 'c-primary-light-100-alpha-600': string + 'c-primary-light-100-alpha-700': string + 'c-primary-light-100-alpha-800': string + 'c-primary-light-100-alpha-900': string + + 'c-primary-light-200': string + 'c-primary-light-200-alpha-100': string + 'c-primary-light-200-alpha-200': string + 'c-primary-light-200-alpha-300': string + 'c-primary-light-200-alpha-400': string + 'c-primary-light-200-alpha-500': string + 'c-primary-light-200-alpha-600': string + 'c-primary-light-200-alpha-700': string + 'c-primary-light-200-alpha-800': string + 'c-primary-light-200-alpha-900': string + + 'c-primary-light-300': string + 'c-primary-light-300-alpha-100': string + 'c-primary-light-300-alpha-200': string + 'c-primary-light-300-alpha-300': string + 'c-primary-light-300-alpha-400': string + 'c-primary-light-300-alpha-500': string + 'c-primary-light-300-alpha-600': string + 'c-primary-light-300-alpha-700': string + 'c-primary-light-300-alpha-800': string + 'c-primary-light-300-alpha-900': string + + 'c-primary-light-400': string + 'c-primary-light-400-alpha-100': string + 'c-primary-light-400-alpha-200': string + 'c-primary-light-400-alpha-300': string + 'c-primary-light-400-alpha-400': string + 'c-primary-light-400-alpha-500': string + 'c-primary-light-400-alpha-600': string + 'c-primary-light-400-alpha-700': string + 'c-primary-light-400-alpha-800': string + 'c-primary-light-400-alpha-900': string + + 'c-primary-light-500': string + 'c-primary-light-500-alpha-100': string + 'c-primary-light-500-alpha-200': string + 'c-primary-light-500-alpha-300': string + 'c-primary-light-500-alpha-400': string + 'c-primary-light-500-alpha-500': string + 'c-primary-light-500-alpha-600': string + 'c-primary-light-500-alpha-700': string + 'c-primary-light-500-alpha-800': string + 'c-primary-light-500-alpha-900': string + + 'c-primary-light-600': string + 'c-primary-light-600-alpha-100': string + 'c-primary-light-600-alpha-200': string + 'c-primary-light-600-alpha-300': string + 'c-primary-light-600-alpha-400': string + 'c-primary-light-600-alpha-500': string + 'c-primary-light-600-alpha-600': string + 'c-primary-light-600-alpha-700': string + 'c-primary-light-600-alpha-800': string + 'c-primary-light-600-alpha-900': string + + 'c-primary-light-700': string + 'c-primary-light-700-alpha-100': string + 'c-primary-light-700-alpha-200': string + 'c-primary-light-700-alpha-300': string + 'c-primary-light-700-alpha-400': string + 'c-primary-light-700-alpha-500': string + 'c-primary-light-700-alpha-600': string + 'c-primary-light-700-alpha-700': string + 'c-primary-light-700-alpha-800': string + 'c-primary-light-700-alpha-900': string + + 'c-primary-light-800': string + 'c-primary-light-800-alpha-100': string + 'c-primary-light-800-alpha-200': string + 'c-primary-light-800-alpha-300': string + 'c-primary-light-800-alpha-400': string + 'c-primary-light-800-alpha-500': string + 'c-primary-light-800-alpha-600': string + 'c-primary-light-800-alpha-700': string + 'c-primary-light-800-alpha-800': string + 'c-primary-light-800-alpha-900': string + + 'c-primary-light-900': string + 'c-primary-light-900-alpha-100': string + 'c-primary-light-900-alpha-200': string + 'c-primary-light-900-alpha-300': string + 'c-primary-light-900-alpha-400': string + 'c-primary-light-900-alpha-500': string + 'c-primary-light-900-alpha-600': string + 'c-primary-light-900-alpha-700': string + 'c-primary-light-900-alpha-800': string + 'c-primary-light-900-alpha-900': string + + 'c-primary-light-1000': string + 'c-primary-light-1000-alpha-100': string + 'c-primary-light-1000-alpha-200': string + 'c-primary-light-1000-alpha-300': string + 'c-primary-light-1000-alpha-400': string + 'c-primary-light-1000-alpha-500': string + 'c-primary-light-1000-alpha-600': string + 'c-primary-light-1000-alpha-700': string + 'c-primary-light-1000-alpha-800': string + 'c-primary-light-1000-alpha-900': string + } + + type ActiveTheme = ThemeColors & Omit<Theme['config']['extInfo'], 'bg-image'> & Pick<Theme, 'id' | 'name' | 'isDark'> & { + 'c-font': string + 'c-font-label': string + 'c-primary-font': string + 'c-primary-font-hover': string + 'c-primary-font-active': string + 'c-primary-background': string + 'c-primary-background-hover': string + 'c-primary-background-active': string + 'c-primary-input-background': string + 'c-button-font': string + 'c-button-font-selected': string + 'c-button-background': string + 'c-button-background-selected': string + 'c-button-background-hover': string + 'c-button-background-active': string + 'c-list-header-border-bottom': string + 'c-content-background': string + 'c-border-background': string + 'bg-image'?: ImageSourcePropType + } + + interface Theme { + id: string + name: string + isDark: boolean + isCustom: boolean + config: { + themeColors: ThemeColors + extInfo: { + 'c-app-background': string + 'c-main-background': string + 'bg-image': string + 'bg-image-position': string + 'bg-image-size': string + + // 徽章颜色 + 'c-badge-primary': string + 'c-badge-secondary': string + 'c-badge-tertiary': string + } + } + } + + interface ThemeInfo { + themes: LX.Theme[] + userThemes: LX.Theme[] + dataPath: string + } + + interface ThemeSetting { + shouldUseDarkColors: boolean + theme: { + id: string + name: string + isDark: boolean + colors: Record<string, string> + } + } + } +} diff --git a/src/types/utils.d.ts b/src/types/utils.d.ts new file mode 100644 index 000000000..eb6b0d4a9 --- /dev/null +++ b/src/types/utils.d.ts @@ -0,0 +1,11 @@ +type MakeOptional<Type, Key extends keyof Type> = Omit<Type, Key> & Partial<Pick<Type, Key>> + +type DeepPartial<T> = { + [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]; +} + +type Modify<T, R> = Omit<T, keyof R> & R + +type MakeArrayItemReadOnly<T extends any[]> = { [K in keyof T]: Readonly<T[K]> } + +type ForwardRefFn<R> = <P = {}>(p: React.PropsWithChildren<P> & React.RefAttributes<R>) => React.ReactNode | null diff --git a/src/utils/cache.js b/src/utils/cache.js deleted file mode 100644 index 088e140f1..000000000 --- a/src/utils/cache.js +++ /dev/null @@ -1,6 +0,0 @@ -import { NativeModules } from 'react-native' - -const { CacheModule } = NativeModules - -export const getAppCacheSize = () => CacheModule.getAppCacheSize().then(size => parseInt(size)) -export const clearAppCache = CacheModule.clearAppCache diff --git a/src/utils/common.js b/src/utils/common.js deleted file mode 100644 index f5e953e37..000000000 --- a/src/utils/common.js +++ /dev/null @@ -1,16 +0,0 @@ -import { hideLyric } from './lyricDesktop' -import { destroy as destroyPlayer } from '@/plugins/player/utils' -import { exitApp as utilExitApp } from './utils' - -let isDestroying = false -export const exitApp = () => { - if (isDestroying) return - isDestroying = true - Promise.all([ - hideLyric(), - destroyPlayer(), - ]).finally(() => { - isDestroying = false - utilExitApp() - }) -} diff --git a/src/utils/common.ts b/src/utils/common.ts new file mode 100644 index 000000000..ae08df9d5 --- /dev/null +++ b/src/utils/common.ts @@ -0,0 +1,235 @@ +// 非业务工具方法 + +/** + * 获取两个数之间的随机整数,大于等于min,小于max + * @param {*} min + * @param {*} max + */ +export const getRandom = (min: number, max: number): number => Math.floor(Math.random() * (max - min)) + min + + +export const sizeFormate = (size: number): string => { + // https://gist.github.com/thomseddon/3511330 + if (!size) return '0 B' + let units = ['B', 'KB', 'MB', 'GB', 'TB'] + let number = Math.floor(Math.log(size) / Math.log(1024)) + return `${(size / Math.pow(1024, Math.floor(number))).toFixed(2)} ${units[number]}` +} + +/** + * 将字符串、时间戳等格式转成时间对象 + * @param date 时间 + * @returns 时间对象或空字符串 + */ +export const toDateObj = (date: any): Date | '' => { + // console.log(date) + if (!date) return '' + switch (typeof date) { + case 'string': + if (!date.includes('T')) date = date.split('.')[0].replace(/-/g, '/') + // eslint-disable-next-line no-fallthrough + case 'number': + date = new Date(date) + // eslint-disable-next-line no-fallthrough + case 'object': + break + default: return '' + } + return date +} + +const numFix = (n: number): string => n < 10 ? (`0${n}`) : n.toString() +/** + * 时间格式化 + * @param _date 时间 + * @param format Y-M-D h:m:s Y年 M月 D日 h时 m分 s秒 + */ +export const dateFormat = (_date: any, format = 'Y-M-D h:m:s') => { + // console.log(date) + const date = toDateObj(_date) + if (!date) return '' + return format + .replace('Y', date.getFullYear().toString()) + .replace('M', numFix(date.getMonth() + 1)) + .replace('D', numFix(date.getDate())) + .replace('h', numFix(date.getHours())) + .replace('m', numFix(date.getMinutes())) + .replace('s', numFix(date.getSeconds())) +} + + +export const formatPlayTime = (time: number) => { + let m = Math.trunc(time / 60) + let s = Math.trunc(time % 60) + return m == 0 && s == 0 ? '--/--' : numFix(m) + ':' + numFix(s) +} + +export const formatPlayTime2 = (time: number) => { + let m = Math.trunc(time / 60) + let s = Math.trunc(time % 60) + return numFix(m) + ':' + numFix(s) +} + + +const encodeNames = { + ' ': ' ', + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'", + ''': "'", +} as const +export const decodeName = (str: string | null = '') => { + return str?.replace(/(?:&|<|>|"|'|'| )/gm, (s: string) => encodeNames[s as keyof typeof encodeNames]) ?? '' +} + +export const isUrl = (path: string) => /https?:\/\//.test(path) + +// 解析URL参数为对象 +export const parseUrlParams = (str: string): Record<string, string> => { + const params: Record<string, string> = {} + if (typeof str !== 'string') return params + const paramsArr = str.split('&') + for (const param of paramsArr) { + let [key, value] = param.split('=') + params[key] = value + } + return params +} + +/** + * 生成节流函数 + * @param fn 回调 + * @param delay 延迟 + * @returns + */ +export function throttle<Args extends any[]>(fn: (...args: Args) => void | Promise<void>, delay = 100) { + let timer: NodeJS.Timeout | null = null + let _args: Args + return (...args: Args) => { + _args = args + if (timer) return + timer = setTimeout(() => { + timer = null + void fn(..._args) + }, delay) + } +} + +/** + * 生成防抖函数 + * @param fn 回调 + * @param delay 延迟 + * @returns + */ +export function debounce<Args extends any[]>(fn: (...args: Args) => void | Promise<void>, delay = 100) { + let timer: NodeJS.Timeout | null = null + let _args: Args + return (...args: Args) => { + _args = args + if (timer) clearTimeout(timer) + timer = setTimeout(() => { + timer = null + void fn(..._args) + }, delay) + } +} + +const fileNameRxp = /[\\/:*?#"<>|]/g +export const filterFileName = (name: string): string => name.replace(fileNameRxp, '') + + +// https://blog.csdn.net/xcxy2015/article/details/77164126#comments +/** + * + * @param a + * @param b + */ +export const similar = (a: string, b: string) => { + if (!a || !b) return 0 + if (a.length > b.length) { // 保证 a <= b + let t = b + b = a + a = t + } + let al = a.length + let bl = b.length + let mp = [] // 一个表 + let i, j, ai, lt, tmp // ai:字符串a的第i个字符。 lt:左上角的值。 tmp:暂存新的值。 + for (i = 0; i <= bl; i++) mp[i] = i + for (i = 1; i <= al; i++) { + ai = a.charAt(i - 1) + lt = mp[0] + mp[0] = mp[0] + 1 + for (j = 1; j <= bl; j++) { + tmp = Math.min(mp[j] + 1, mp[j - 1] + 1, lt + (ai == b.charAt(j - 1) ? 0 : 1)) + lt = mp[j] + mp[j] = tmp + } + } + return 1 - (mp[bl] / bl) +} + +/** + * 排序字符串 + * @param arr + * @param data + */ +export const sortInsert = <T>(arr: Array<{ num: number, data: T }>, data: { num: number, data: T }) => { + let key = data.num + let left = 0 + let right = arr.length - 1 + + while (left <= right) { + let middle = Math.trunc((left + right) / 2) + if (key == arr[middle].num) { + left = middle + break + } else if (key < arr[middle].num) { + right = middle - 1 + } else { + left = middle + 1 + } + } + while (left > 0) { + if (arr[left - 1].num != key) break + left-- + } + + arr.splice(left, 0, data) +} + + +export const arrPush = <T>(list: T[], newList: T[]) => { + for (let i = 0; i * 1000 < newList.length; i++) { + list.push(...newList.slice(i * 1000, (i + 1) * 1000)) + } + return list +} + +export const arrUnshift = <T>(list: T[], newList: T[]) => { + for (let i = 0; i * 1000 < newList.length; i++) { + list.splice(i * 1000, 0, ...newList.slice(i * 1000, (i + 1) * 1000)) + } + return list +} + +export const arrPushByPosition = <T>(list: T[], newList: T[], position: number) => { + for (let i = 0; i * 1000 < newList.length; i++) { + list.splice(position + i * 1000, 0, ...newList.slice(i * 1000, (i + 1) * 1000)) + } + return list +} + +export const freezeListItem = <T extends any[]>(list: T): MakeArrayItemReadOnly<T> => { + for (let i = 0; i < list.length; i++) { + Object.freeze(list[i]) + } + return list +} + +export const b64DecodeUnicode = (str: string) => { + // Going backwards: from bytestream, to percent-encoding, to original string. + return Buffer.from(str, 'base64').toString() +} diff --git a/src/utils/data.ts b/src/utils/data.ts new file mode 100644 index 000000000..54b9662ac --- /dev/null +++ b/src/utils/data.ts @@ -0,0 +1,391 @@ +import { getData, saveData, getAllKeys, removeDataMultiple, saveDataMultiple, removeData, getDataMultiple } from '@/plugins/storage' +import { DEFAULT_SETTING, LIST_IDS, storageDataPrefix, type NAV_ID_Type } from '@/config/constant' +import { throttle } from './common' +// import { gzip, ungzip } from '@/utils/nativeModules/gzip' +// import { readFile, writeFile, temporaryDirectoryPath, unlink } from '@/utils/fs' +// import { isNotificationsEnabled, openNotificationPermissionActivity, shareText } from '@/utils/nativeModules/utils' +// import { i18n } from '@/plugins/i18n' +// import musicSdk from '@/utils/musicSdk' + +const fontSizeKey = storageDataPrefix.fontSize +const themeKey = storageDataPrefix.theme +const playInfoStorageKey = storageDataPrefix.playInfo +const userListKey = storageDataPrefix.userList +const viewPrevStateKey = storageDataPrefix.viewPrevState +const listScrollPositionKey = storageDataPrefix.listScrollPosition +const listUpdateInfoKey = storageDataPrefix.listUpdateInfo +const ignoreVersionKey = storageDataPrefix.ignoreVersion +const searchSettingKey = storageDataPrefix.searchSetting +const searchHistoryListKey = storageDataPrefix.searchHistoryList +const songListSettingKey = storageDataPrefix.songListSetting +const leaderboardSettingKey = storageDataPrefix.leaderboardSetting +const listPrevSelectIdKey = storageDataPrefix.listPrevSelectId +const syncAuthKeyPrefix = storageDataPrefix.syncAuthKey +const syncHostPrefix = storageDataPrefix.syncHost +const syncHostHistoryPrefix = storageDataPrefix.syncHostHistory +const listPrefix = storageDataPrefix.list + +// const defaultListKey = listPrefix + 'default' +// const loveListKey = listPrefix + 'love' + +let listPosition: LX.List.ListPositionInfo +let listPrevSelectId: string +let listUpdateInfo: LX.List.ListUpdateInfo + +let searchSetting: typeof DEFAULT_SETTING['search'] +let songListSetting: typeof DEFAULT_SETTING['songList'] +let leaderboardSetting: typeof DEFAULT_SETTING['leaderboard'] +let searchHistoryList: string[] + +const saveListPositionThrottle = throttle(() => { + void saveData(listScrollPositionKey, listPosition) +}, 1000) +const saveSearchSettingThrottle = throttle(() => { + void saveData(searchSettingKey, searchSetting) +}, 1000) +const saveSearchHistoryThrottle = throttle(() => { + void saveData(searchHistoryListKey, searchHistoryList) +}, 1000) +const saveSongListSettingThrottle = throttle(() => { + void saveData(songListSettingKey, songListSetting) +}, 1000) +const saveLeaderboardSettingThrottle = throttle(() => { + void saveData(leaderboardSettingKey, leaderboardSetting) +}, 1000) +const saveViewPrevStateThrottle = throttle((state) => { + void saveData(viewPrevStateKey, state) +}, 1000) + +export const getFontSize = async() => (await getData<number>(fontSizeKey) ?? 1) +export const saveFontSize = async(size: number) => { + await saveData(fontSizeKey, size) +} + +export const getUserTheme = async() => (await getData<LX.Theme[]>(themeKey) ?? []) +export const saveUserTheme = async(themes: LX.Theme[]) => { + await saveData(themeKey, themes) +} + + +const initPosition = async() => { + listPosition ??= await getData(listScrollPositionKey) ?? {} +} +export const getListPosition = async(id: string): Promise<number> => { + await initPosition() + return listPosition[id] ?? 0 +} +export const saveListPosition = async(id: string, position?: number) => { + await initPosition() + listPosition[id] = position ?? 0 + saveListPositionThrottle() +} +export const removeListPosition = async(id: string) => { + await initPosition() + delete listPosition[id] + saveListPositionThrottle() +} +export const overwriteListPosition = async(ids: string[]) => { + await initPosition() + const removedIds = [] + for (const id of Object.keys(listPosition)) { + if (ids.includes(id)) continue + removedIds.push(id) + } + for (const id of removedIds) delete listPosition[id] + saveListPositionThrottle() +} + +const saveListPrevSelectIdThrottle = throttle(() => { + void saveData(listPrevSelectIdKey, listPrevSelectId) +}, 200) +export const getListPrevSelectId = async() => { + listPrevSelectId ??= await getData(listPrevSelectIdKey) ?? LIST_IDS.DEFAULT + return listPrevSelectId || LIST_IDS.DEFAULT +} +export const saveListPrevSelectId = (id: string) => { + listPrevSelectId = id + saveListPrevSelectIdThrottle() +} + +const saveListUpdateInfoThrottle = throttle(() => { + void saveData(listUpdateInfoKey, listUpdateInfo) +}, 1000) + +const initListUpdateInfo = async() => { + listUpdateInfo ??= await getData(listUpdateInfoKey) ?? {} +} +export const getListUpdateInfo = async() => { + await initListUpdateInfo() + return listUpdateInfo +} +export const saveListUpdateInfo = async(info: LX.List.ListUpdateInfo) => { + await initListUpdateInfo() + listUpdateInfo = info + saveListUpdateInfoThrottle() +} +export const setListAutoUpdate = async(id: string, enable: boolean) => { + await initListUpdateInfo() + const targetInfo = listUpdateInfo[id] ?? { updateTime: 0, isAutoUpdate: false } + targetInfo.isAutoUpdate = enable + listUpdateInfo[id] = targetInfo + saveListUpdateInfoThrottle() +} +export const setListUpdateTime = async(id: string, time: number) => { + await initListUpdateInfo() + const targetInfo = listUpdateInfo[id] ?? { updateTime: 0, isAutoUpdate: false } + targetInfo.updateTime = time + listUpdateInfo[id] = targetInfo + saveListUpdateInfoThrottle() +} +// export const setListUpdateInfo = (id, { updateTime, isAutoUpdate }) => { +// listUpdateInfo[id] = { updateTime, isAutoUpdate } +// saveListUpdateInfo() +// } +export const removeListUpdateInfo = async(id: string) => { + await initListUpdateInfo() + delete listUpdateInfo[id] + saveListUpdateInfoThrottle() +} +export const overwriteListUpdateInfo = async(ids: string[]) => { + await initListUpdateInfo() + const removedIds = [] + for (const id of Object.keys(listUpdateInfo)) { + if (ids.includes(id)) continue + removedIds.push(id) + } + for (const id of removedIds) delete listUpdateInfo[id] + saveListUpdateInfoThrottle() +} + +let ignoreVersion: string | null +export const saveIgnoreVersion = (version: string | null) => { + ignoreVersion = version + if (version == null) { + void removeData(ignoreVersionKey) + } else { + void saveData(ignoreVersionKey, version) + } +} +// 获取忽略更新的版本号 +export const getIgnoreVersion = async() => { + if (ignoreVersion === undefined) ignoreVersion = (await getData<string | null>(ignoreVersionKey)) ?? null + return ignoreVersion +} + + +export const getSearchSetting = async() => { + searchSetting ??= await getData(searchSettingKey) ?? { ...DEFAULT_SETTING.search } + return { ...searchSetting } +} +export const saveSearchSetting = async(setting: Partial<typeof DEFAULT_SETTING['search']>) => { + if (!searchSetting) await getSearchSetting() + let requiredSave = false + if (setting.source && searchSetting.source != setting.source) requiredSave = true + if (setting.type && searchSetting.type != setting.type) requiredSave = true + if (setting.temp_source && searchSetting.temp_source != setting.temp_source) requiredSave = true + + if (!requiredSave) return + searchSetting = Object.assign(searchSetting, setting) + saveSearchSettingThrottle() +} + +export const getSearchHistory = async() => { + searchHistoryList ??= await getData(searchHistoryListKey) ?? [] + return [...searchHistoryList] +} +export const saveSearchHistory = async(historyList: typeof searchHistoryList) => { + if (!searchHistoryList) await getSearchHistory() + searchHistoryList = historyList + saveSearchHistoryThrottle() +} + +export const getSongListSetting = async() => { + songListSetting ??= await getData(songListSettingKey) ?? { ...DEFAULT_SETTING.songList } + return { ...songListSetting } +} +export const saveSongListSetting = async(setting: Partial<typeof DEFAULT_SETTING['songList']>) => { + if (!songListSetting) await getSongListSetting() + songListSetting = Object.assign(songListSetting, setting) + saveSongListSettingThrottle() +} + +export const getLeaderboardSetting = async() => { + leaderboardSetting ??= await getData(leaderboardSettingKey) ?? { ...DEFAULT_SETTING.leaderboard } + return { ...leaderboardSetting } +} +export const saveLeaderboardSetting = async(setting: Partial<typeof DEFAULT_SETTING['leaderboard']>) => { + if (!leaderboardSetting) await getLeaderboardSetting() + leaderboardSetting = Object.assign(leaderboardSetting, setting) + saveLeaderboardSettingThrottle() +} + +export const getViewPrevState = async() => { + return await getData<{ id: NAV_ID_Type }>(viewPrevStateKey) ?? { ...DEFAULT_SETTING.viewPrevState } +} +export const saveViewPrevState = (state: { id: NAV_ID_Type }) => { + saveViewPrevStateThrottle(state) +} + + +/** + * 获取用户列表 + */ +export const getUserLists = async(): Promise<LX.List.UserListInfo[]> => { + const list = await getData<LX.List.UserListInfo[]>(userListKey) + return list ?? [] +} + +/** + * 保存用户列表 + * @param listInfo + */ +export const saveUserList = async(listInfo: LX.List.UserListInfo[]) => { + await saveData(userListKey, listInfo) +} + +/** + * 获取列表内歌曲 + * @param listId 列表id + * @returns + */ +export const getListMusics = async(listId: string): Promise<LX.Music.MusicInfo[]> => { + const list = await getData<LX.Music.MusicInfo[]>(listPrefix + listId) + return list ?? [] +} + +/** + * 保存列表内歌曲 + * @param listData 列表数据 + */ +export const saveListMusics = async(listData: Array<{ id: string, musics: LX.Music.MusicInfo[] }>) => { + if (listData.length > 1) { + await saveDataMultiple(listData.map(list => ([listPrefix + list.id, list.musics]))) + } else { + const list = listData[0] + await saveData(listPrefix + list.id, list.musics) + } +} + +/** + * 移除歌曲列表 + * @param ids + */ +export const removeListMusics = async(ids: string[]): Promise<void> => { + if (ids.length > 1) { + await removeDataMultiple(ids.map(id => { + // delete global.lx.listScrollPosition[id] + // delete global.lx.listSort[id] + return listPrefix + id + })) + } else { + await removeData(listPrefix + ids[0]) + } + // await saveData(listSortPrefix, global.lx.listSort) + // delaySaveListScrollPosition(global.lx.listScrollPosition) +} + + +export const getMusicUrl = async(musicInfo: LX.Music.MusicInfo, type: LX.Quality) => getData<string>(`${storageDataPrefix.musicUrl}${musicInfo.id}_${type}`).then((url) => url ?? '') +export const saveMusicUrl = async(musicInfo: LX.Music.MusicInfo, type: LX.Quality, url: string) => saveData(`${storageDataPrefix.musicUrl}${musicInfo.id}_${type}`, url) +export const clearMusicUrl = async() => { + let keys = (await getAllKeys()).filter(key => key.startsWith(storageDataPrefix.musicUrl)) + await removeDataMultiple(keys) +} + +export const getLyric = async(musicInfo: LX.Music.MusicInfo) => getData<LX.Music.LyricInfo>(`${storageDataPrefix.lyric}${musicInfo.id}`).then(lrcInfo => lrcInfo ?? { lyric: '' }) +export const saveLyric = async(musicInfo: LX.Music.MusicInfo, lyricInfo: LX.Music.LyricInfo) => saveData(`${storageDataPrefix.lyric}${musicInfo.id}`, lyricInfo) +export const clearLyric = async() => { + let keys = (await getAllKeys()).filter(key => key.startsWith(storageDataPrefix.lyric)) + await removeDataMultiple(keys) +} +export const saveEditedLyric = async(musicInfo: LX.Music.MusicInfo, lyricInfo: LX.Music.LyricInfo) => saveData(`${storageDataPrefix.lyric}${musicInfo.id}_edited`, lyricInfo) +export const clearEditedLyric = async() => { + let keys = (await getAllKeys()).filter(key => key.startsWith(storageDataPrefix.lyric) && key.endsWith('_edited')) + await removeDataMultiple(keys) +} +export const getPlayerLyric = async(musicInfo: LX.Music.MusicInfo): Promise<LX.Player.LyricInfo> => { + return getDataMultiple([ + `${storageDataPrefix.lyric}${musicInfo.id}`, + `${storageDataPrefix.lyric}${musicInfo.id}_edited`, + ]).then(([lrcInfo, lrcInfo_edited]) => { + const lyricInfo: LX.Music.LyricInfo = lrcInfo_edited[1] as LX.Music.LyricInfo | null ?? { + lyric: '', + } + let rawLyricInfo: LX.Music.LyricInfo = lrcInfo[1] as LX.Music.LyricInfo | null ?? { + lyric: '', + } + return lyricInfo.lyric ? { + ...lyricInfo, + rawlrcInfo: rawLyricInfo, + } : { + ...rawLyricInfo, + rawlrcInfo: rawLyricInfo, + } + }) +} + +export const getOtherSource = async(id: string) => getData<LX.Music.MusicInfoOnline[]>(`${storageDataPrefix.musicOtherSource}${id}`).then((url) => url ?? []) +export const saveOtherSource = async(id: string, sourceInfo: LX.Music.MusicInfoOnline[]) => saveData(`${storageDataPrefix.musicOtherSource}${id}`, sourceInfo) +export const clearOtherSource = async() => { + let keys = (await getAllKeys()).filter(key => key.startsWith(storageDataPrefix.musicOtherSource)) + await removeDataMultiple(keys) +} + +export const clearMusicUrlAndLyric = async() => { + let keys = (await getAllKeys()).filter(key => key.startsWith(storageDataPrefix.musicUrl) || key.startsWith(storageDataPrefix.lyric)) + await removeDataMultiple(keys) +} + +export const savePlayInfo = async(playInfo: LX.Player.SavedPlayInfo) => { + return saveData(playInfoStorageKey, playInfo) +} +// 获取上次关闭时的当前歌曲播放信息 +export const getPlayInfo = async() => { + return getData<LX.Player.SavedPlayInfo | null>(playInfoStorageKey) +} + +export const getSyncAuthKey = async(serverId: string) => { + const keys = await getData<Record<string, LX.Sync.KeyInfo>>(syncAuthKeyPrefix) + if (!keys) return null + return keys[serverId] ?? null +} +export const setSyncAuthKey = async(serverId: string, key: string) => { + let keys = await getData<Record<string, string>>(syncAuthKeyPrefix) ?? {} + keys[serverId] = key + await saveData(syncAuthKeyPrefix, keys) +} + +let syncHostInfo: { host: string, port: string } +export const getSyncHost = async() => { + if (syncHostInfo === undefined) { + syncHostInfo = await getData(syncHostPrefix) ?? { host: '', port: '23332' } + } + return { ...syncHostInfo } +} +export const setSyncHost = async({ host, port }: { host: string, port: string }) => { + // let hostInfo = await getData(syncHostPrefix) || {} + // hostInfo.host = host + // hostInfo.port = port + syncHostInfo.host = host + syncHostInfo.port = port + await saveData(syncHostPrefix, syncHostInfo) +} +let syncHostHistory: Array<{ host: string, port: string }> +export const getSyncHostHistory = async() => { + if (syncHostHistory === undefined) { + syncHostHistory = await getData(syncHostHistoryPrefix) ?? [] + } + return syncHostHistory +} +export const addSyncHostHistory = async(host: string, port: string) => { + let syncHostHistory = await getSyncHostHistory() + if (syncHostHistory.some(h => h.host == host && h.port == port)) return + syncHostHistory.unshift({ host, port }) + if (syncHostHistory.length > 20) syncHostHistory = syncHostHistory.slice(0, 20) // 最多存储20个 + await saveData(syncHostHistoryPrefix, syncHostHistory) +} +export const removeSyncHostHistory = async(index: number) => { + syncHostHistory.splice(index, 1) + await saveData(syncHostHistoryPrefix, syncHostHistory) +} + diff --git a/src/utils/env.js b/src/utils/env.js deleted file mode 100644 index 553f01efa..000000000 --- a/src/utils/env.js +++ /dev/null @@ -1,5 +0,0 @@ -const isDev = process.env.NODE_ENV === 'development' - -export const debug = isDev && true -export const debugRequest = isDev && false -export const debugDownload = isDev && false diff --git a/src/utils/errorHandle.js b/src/utils/errorHandle.ts similarity index 64% rename from src/utils/errorHandle.js rename to src/utils/errorHandle.ts index 7576a2a03..5d5773a93 100644 --- a/src/utils/errorHandle.js +++ b/src/utils/errorHandle.ts @@ -1,14 +1,14 @@ import { Alert } from 'react-native' -import { exitApp } from '@/utils/common' +// import { exitApp } from '@/utils/common' import { setJSExceptionHandler, setNativeExceptionHandler } from 'react-native-exception-handler' import { log } from '@/utils/log' -const errorHandler = (e, isFatal) => { +const errorHandler = (e: Error, isFatal: boolean) => { if (isFatal) { Alert.alert( '💥Unexpected error occurred💥', ` -应用出bug了😭,已崩溃💥,以下是错误异常信息,请截图通过企鹅群或者GitHub反馈,现在应用将会关闭,请自行重新启动! +应用出bug了😭,以下是错误异常信息,请截图(并附上刚才你进行了什么操作)通过企鹅群或者GitHub反馈,现在应用可能会出现异常,若出现异常请尝试强制结束APP后重新启动! Error: ${isFatal ? 'Fatal:' : ''} ${e.name} ${e.message} @@ -16,7 +16,7 @@ ${isFatal ? 'Fatal:' : ''} ${e.name} ${e.message} [{ text: '关闭 (Close)', onPress: () => { - exitApp() + // exitApp() }, }], ) diff --git a/src/utils/fs.js b/src/utils/fs.ts similarity index 61% rename from src/utils/fs.js rename to src/utils/fs.ts index 3d0d6a233..ac4e4926e 100644 --- a/src/utils/fs.js +++ b/src/utils/fs.ts @@ -5,27 +5,27 @@ export const externalDirectoryPath = RNFS.ExternalDirectoryPath export const temporaryDirectoryPath = RNFS.TemporaryDirectoryPath export const externalStorageDirectoryPath = RNFS.ExternalStorageDirectoryPath -export const unlink = path => RNFS.unlink(path) +export const unlink = async(path: string) => RNFS.unlink(path) -export const readDir = path => RNFS.readDir(path) +export const readDir = async(path: string) => RNFS.readDir(path) -export const mkdir = path => RNFS.mkdir(path) +export const mkdir = async(path: string) => RNFS.mkdir(path) -export const stat = path => RNFS.stat(path) +export const stat = async(path: string) => RNFS.stat(path) -export const readFile = (path, encoding) => RNFS.readFile(path, encoding) +export const readFile = async(path: string, encoding = 'utf8') => RNFS.readFile(path, encoding) -export const copyFile = (fromPath, toPath) => RNFS.copyFile(fromPath, toPath) +export const copyFile = async(fromPath: string, toPath: string) => RNFS.copyFile(fromPath, toPath) -export const moveFile = (fromPath, toPath) => RNFS.moveFile(fromPath, toPath) +export const moveFile = async(fromPath: string, toPath: string) => RNFS.moveFile(fromPath, toPath) -export const existsFile = path => RNFS.exists(path) +export const existsFile = async(path: string) => RNFS.exists(path) -export const writeFile = (path, data, encoding = 'utf8') => RNFS.writeFile(path, data, encoding) +export const writeFile = async(path: string, data: string, encoding = 'utf8') => RNFS.writeFile(path, data, encoding) -export const appendFile = (path, data, encoding = 'utf8') => RNFS.appendFile(path, data, encoding) +export const appendFile = async(path: string, data: string, encoding = 'utf8') => RNFS.appendFile(path, data, encoding) -export const downloadFile = (url, path, options = {}) => { +export const downloadFile = (url: string, path: string, options: Omit<RNFS.DownloadFileOptions, 'fromUrl' | 'toFile'> = {}) => { if (!options.headers) { options.headers = { 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Mobile Safari/537.36', @@ -50,4 +50,4 @@ export const downloadFile = (url, path, options = {}) => { }) } -export const stopDownload = jobId => RNFS.stopDownload(jobId) +export const stopDownload = (jobId: number) => RNFS.stopDownload(jobId) diff --git a/src/utils/hooks/useLayout.js b/src/utils/hooks/useLayout.tsx similarity index 58% rename from src/utils/hooks/useLayout.js rename to src/utils/hooks/useLayout.tsx index 85c93f737..73c5aaaaa 100644 --- a/src/utils/hooks/useLayout.js +++ b/src/utils/hooks/useLayout.tsx @@ -1,4 +1,5 @@ import { useState, useCallback } from 'react' +import { type LayoutChangeEvent } from 'react-native' export default () => { const [layout, setLayout] = useState({ @@ -7,7 +8,7 @@ export default () => { width: 0, height: 0, }) - const onLayout = useCallback((e) => setLayout(e.nativeEvent.layout), []) + const onLayout = useCallback((e: LayoutChangeEvent) => { setLayout(e.nativeEvent.layout) }, []) return { onLayout, diff --git a/src/utils/index.js b/src/utils/index.js deleted file mode 100644 index 34dd5ba33..000000000 --- a/src/utils/index.js +++ /dev/null @@ -1,161 +0,0 @@ - - -/** - * 获取两个数之间的随机整数,大于等于min,小于max - * @param {*} min - * @param {*} max - */ -export const getRandom = (min, max) => Math.floor(Math.random() * (max - min)) + min - - -export const sizeFormate = size => { - // https://gist.github.com/thomseddon/3511330 - if (!size) return '0 B' - const units = ['B', 'KB', 'MB', 'GB', 'TB'] - const number = Math.floor(Math.log(size) / Math.log(1024)) - return `${(size / Math.pow(1024, Math.floor(number))).toFixed(2)} ${units[number]}` -} - -/** - * 日期格式化 - * @param {*} date 时间 - * @param {String} format 时间格式,默认YYYY-MM-DD hh:mm:ss - */ -export const dateFormat = (date = new Date(), format = 'YYYY-MM-DD hh:mm:ss') => { - if (typeof date != 'object') date = new Date(date) - const munFix = (n) => n < 10 ? ('0' + n) : n - return format - .replace('YYYY', date.getFullYear()) - .replace('MM', munFix(date.getMonth() + 1)) - .replace('DD', munFix(date.getDate())) - .replace('hh', munFix(date.getHours())) - .replace('mm', munFix(date.getMinutes())) - .replace('ss', munFix(date.getSeconds())) -} - -/** - * 时间格式化 - */ -export const dateFormat2 = time => { - let differ = parseInt((Date.now() - time) / 1000) - if (differ < 60) { - return global.i18n.t('date_format_second', { num: differ }) - } else if (differ < 3600) { - return global.i18n.t('date_format_minute', { num: parseInt(differ / 60) }) - } else if (differ < 86400) { - return global.i18n.t('date_format_hour', { num: parseInt(differ / 3600) }) - } else { - return dateFormat(time) - } -} - -export const formatPlayTime = time => { - const m = parseInt(time / 60) - const s = parseInt(time % 60) - return m === 0 && s === 0 ? '--/--' : (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s) -} - -export const formatPlayTime2 = time => { - const m = parseInt(time / 60) - const s = parseInt(time % 60) - return (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s) -} - -export const b64DecodeUnicode = str => { - // Going backwards: from bytestream, to percent-encoding, to original string. - return Buffer.from(str, 'base64').toString() -} - -const encodeNames = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': "'", - ''': "'", -} -export const decodeName = (str = '') => str.replace(/(?:&|<|>|"|'|')/gm, s => encodeNames[s]) - -// https://stackoverflow.com/a/53387532 -export const compareVer = (currentVer, targetVer) => { - // treat non-numerical characters as lower version - // replacing them with a negative number based on charcode of each character - const fix = s => `.${s.toLowerCase().charCodeAt(0) - 2147483647}.` - - currentVer = ('' + currentVer).replace(/[^0-9.]/g, fix).split('.') - targetVer = ('' + targetVer).replace(/[^0-9.]/g, fix).split('.') - const c = Math.max(currentVer.length, targetVer.length) - for (let i = 0; i < c; i++) { - // convert to integer the most efficient way - currentVer[i] = ~~currentVer[i] - targetVer[i] = ~~targetVer[i] - if (currentVer[i] > targetVer[i]) return 1 - else if (currentVer[i] < targetVer[i]) return -1 - } - return 0 -} - -export const isObject = item => item && typeof item === 'object' && !Array.isArray(item) - -/** - * 对象深度合并 - * @param {} target 要合并源对象 - * @param {} source 要合并目标对象 - */ -export const objectDeepMerge = (target, source, mergedObj) => { - if (!mergedObj) { - mergedObj = new Set() - mergedObj.add(target) - } - const base = {} - Object.keys(source).forEach(item => { - if (isObject(source[item])) { - if (mergedObj.has(source[item])) return - if (!isObject(target[item])) target[item] = {} - mergedObj.add(source[item]) - objectDeepMerge(target[item], source[item], mergedObj) - return - } - base[item] = source[item] - }) - Object.assign(target, base) -} - -/** - * 生成节流函数 - * @param {*} fn - * @param {*} delay - */ -export const throttle = (fn, delay = 100) => { - let timer = null - let _args = null - return function(...args) { - _args = args - if (timer) return - timer = setTimeout(() => { - timer = null - fn.apply(this, _args) - }, delay) - } -} - -/** - * 生成防抖函数 - * @param {*} fn - * @param {*} delay - */ -export const debounce = (fn, delay = 100) => { - let timer = null - let _args = null - return function(...args) { - _args = args - if (timer) clearTimeout(timer) - timer = setTimeout(() => { - timer = null - fn.apply(this, _args) - }, delay) - } -} - -const fileNameRxp = /[\\/:*?#"<>|]/g -export const filterFileName = name => name.replace(fileNameRxp, '') diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 000000000..565e0dcc5 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,182 @@ +import { dateFormat } from './common' + +export { tranditionalize as langS2T } from '@/utils/simplify-chinese-main' + +export * from './common' + +// https://stackoverflow.com/a/53387532 +export function compareVer(currentVer: string, targetVer: string): -1 | 0 | 1 { + // treat non-numerical characters as lower version + // replacing them with a negative number based on charcode of each character + const fix = (s: string) => `.${s.toLowerCase().charCodeAt(0) - 2147483647}.` + + const currentVerArr: Array<string | number> = ('' + currentVer).replace(/[^0-9.]/g, fix).split('.') + const targetVerArr: Array<string | number> = ('' + targetVer).replace(/[^0-9.]/g, fix).split('.') + let c = Math.max(currentVerArr.length, targetVerArr.length) + for (let i = 0; i < c; i++) { + // convert to integer the most efficient way + currentVerArr[i] = ~~currentVerArr[i] + targetVerArr[i] = ~~targetVerArr[i] + if (currentVerArr[i] > targetVerArr[i]) return 1 + else if (currentVerArr[i] < targetVerArr[i]) return -1 + } + return 0 +} + + +export const toNewMusicInfo = (oldMusicInfo: any): LX.Music.MusicInfo => { + const meta: Record<string, any> = { + songId: oldMusicInfo.songmid, // 歌曲ID,mg源为copyrightId,local为文件路径 + albumName: oldMusicInfo.albumName, // 歌曲专辑名称 + picUrl: oldMusicInfo.img, // 歌曲图片链接 + } + + if (oldMusicInfo.source == 'local') { + meta.filePath = oldMusicInfo.filePath ?? oldMusicInfo.songmid ?? '' + meta.ext = oldMusicInfo.ext ?? /\.(\w+)$/.exec(meta.filePath)?.[1] ?? '' + } else { + meta.qualitys = oldMusicInfo.types + meta._qualitys = oldMusicInfo._types + meta.albumId = oldMusicInfo.albumId + if (meta._qualitys.flac32bit && !meta._qualitys.flac24bit) { + meta._qualitys.flac24bit = meta._qualitys.flac32bit + delete meta._qualitys.flac32bit + + meta.qualitys = (meta.qualitys as any[]).map(quality => { + if (quality.type == 'flac32bit') quality.type = 'flac24bit' + return quality + }) + } + + switch (oldMusicInfo.source) { + case 'kg': + meta.hash = oldMusicInfo.hash + break + case 'tx': + meta.strMediaMid = oldMusicInfo.strMediaMid + meta.albumMid = oldMusicInfo.albumMid + meta.id = oldMusicInfo.songId + break + case 'mg': + meta.copyrightId = oldMusicInfo.copyrightId + meta.lrcUrl = oldMusicInfo.lrcUrl + meta.mrcUrl = oldMusicInfo.mrcUrl + meta.trcUrl = oldMusicInfo.trcUrl + break + } + } + + return { + id: `${oldMusicInfo.source as string}_${oldMusicInfo.songmid as string}`, + name: oldMusicInfo.name, + singer: oldMusicInfo.singer, + source: oldMusicInfo.source, + interval: oldMusicInfo.interval, + meta: meta as LX.Music.MusicInfoOnline['meta'], + } +} + +export const toOldMusicInfo = (minfo: LX.Music.MusicInfo): any => { + const oInfo: Record<string, any> = { + name: minfo.name, + singer: minfo.singer, + source: minfo.source, + songmid: minfo.meta.songId, + interval: minfo.interval, + albumName: minfo.meta.albumName, + img: minfo.meta.picUrl ?? '', + typeUrl: {}, + } + if (minfo.source == 'local') { + oInfo.filePath = minfo.meta.filePath + oInfo.ext = minfo.meta.ext + oInfo.albumId = '' + oInfo.types = [] + oInfo._types = {} + } else { + oInfo.albumId = minfo.meta.albumId + oInfo.types = minfo.meta.qualitys + oInfo._types = minfo.meta._qualitys + + switch (minfo.source) { + case 'kg': + oInfo.hash = minfo.meta.hash + break + case 'tx': + oInfo.strMediaMid = minfo.meta.strMediaMid + oInfo.albumMid = minfo.meta.albumMid + oInfo.songId = minfo.meta.id + break + case 'mg': + oInfo.copyrightId = minfo.meta.copyrightId + oInfo.lrcUrl = minfo.meta.lrcUrl + oInfo.mrcUrl = minfo.meta.mrcUrl + oInfo.trcUrl = minfo.meta.trcUrl + break + } + } + + return oInfo +} + +/** + * 修复2.0.0-dev.8之前的新列表数据音质 + * @param musicInfo + */ +export const fixNewMusicInfoQuality = (musicInfo: LX.Music.MusicInfo) => { + if (musicInfo.source == 'local') return musicInfo + + // @ts-expect-error + if (musicInfo.meta._qualitys.flac32bit && !musicInfo.meta._qualitys.flac24bit) { + // @ts-expect-error + musicInfo.meta._qualitys.flac24bit = musicInfo.meta._qualitys.flac32bit + // @ts-expect-error + delete musicInfo.meta._qualitys.flac32bit + + musicInfo.meta.qualitys = musicInfo.meta.qualitys.map(quality => { + // @ts-expect-error + if (quality.type == 'flac32bit') quality.type = 'flac24bit' + return quality + }) + } + + return musicInfo +} + + +export const filterMusicList = <T extends LX.Music.MusicInfo>(list: T[]): T[] => { + const ids = new Set<string>() + return list.filter(s => { + if (!s.id || ids.has(s.id) || !s.name) return false + if (s.singer == null) s.singer = '' + ids.add(s.id) + return true + }) +} + + +export const deduplicationList = <T extends LX.Music.MusicInfo>(list: T[]): T[] => { + const ids = new Set<string>() + return list.filter(s => { + if (ids.has(s.id)) return false + ids.add(s.id) + return true + }) +} + + +/** + * 时间格式化 + */ +export const dateFormat2 = (time: number): string => { + let differ = Math.trunc((Date.now() - time) / 1000) + if (differ < 60) { + return global.i18n.t('date_format_second', { num: differ }) + } else if (differ < 3600) { + return global.i18n.t('date_format_minute', { num: Math.trunc(differ / 60) }) + } else if (differ < 86400) { + return global.i18n.t('date_format_hour', { num: Math.trunc(differ / 3600) }) + } else { + return dateFormat(time) + } +} diff --git a/src/utils/listData.js b/src/utils/listData.js deleted file mode 100644 index 521d9c3ac..000000000 --- a/src/utils/listData.js +++ /dev/null @@ -1,95 +0,0 @@ - -export const toNewMusicInfo = (oldMusicInfo) => { - const meta = { - songId: oldMusicInfo.songmid, // 歌曲ID,mg源为copyrightId,local为文件路径 - albumName: oldMusicInfo.albumName, // 歌曲专辑名称 - picUrl: oldMusicInfo.img, // 歌曲图片链接 - } - - if (oldMusicInfo.source == 'local') { - meta.filePath = oldMusicInfo.filePath ?? oldMusicInfo.songmid ?? '' - meta.ext = oldMusicInfo.ext ?? /\.(\w+)$/.exec(meta.filePath)?.[1] ?? '' - } else { - meta.qualitys = oldMusicInfo.types - meta._qualitys = oldMusicInfo._types - meta.albumId = oldMusicInfo.albumId - if (meta._qualitys.flac32bit && !meta._qualitys.flac24bit) { - meta._qualitys.flac24bit = meta._qualitys.flac32bit - delete meta._qualitys.flac32bit - - meta.qualitys = meta.qualitys.map(quality => { - if (quality.type == 'flac32bit') quality.type = 'flac24bit' - return quality - }) - } - - switch (oldMusicInfo.source) { - case 'kg': - meta.hash = oldMusicInfo.hash - break - case 'tx': - meta.strMediaMid = oldMusicInfo.strMediaMid - meta.albumMid = oldMusicInfo.albumMid - meta.id = oldMusicInfo.songId - break - case 'mg': - meta.copyrightId = oldMusicInfo.copyrightId - meta.lrcUrl = oldMusicInfo.lrcUrl - meta.mrcUrl = oldMusicInfo.mrcUrl - meta.trcUrl = oldMusicInfo.trcUrl - break - } - } - - return { - id: `${oldMusicInfo.source}_${oldMusicInfo.songmid}`, - name: oldMusicInfo.name, - singer: oldMusicInfo.singer, - source: oldMusicInfo.source, - interval: oldMusicInfo.interval, - meta, - } -} - -export const toOldMusicInfo = (minfo) => { - const oInfo = { - name: minfo.name, - singer: minfo.singer, - source: minfo.source, - songmid: minfo.meta.songId, - interval: minfo.interval, - albumName: minfo.meta.albumName, - img: minfo.meta.picUrl ?? '', - typeUrl: {}, - } - if (minfo.source == 'local') { - oInfo.filePath = minfo.meta.filePath - oInfo.ext = minfo.meta.ext - oInfo.albumId = '' - oInfo.types = [] - oInfo._types = {} - } else { - oInfo.albumId = minfo.meta.albumId - oInfo.types = minfo.meta.qualitys - oInfo._types = minfo.meta._qualitys - - switch (minfo.source) { - case 'kg': - oInfo.hash = minfo.meta.hash - break - case 'tx': - oInfo.strMediaMid = minfo.meta.strMediaMid - oInfo.albumMid = minfo.meta.albumMid - oInfo.songId = minfo.meta.id - break - case 'mg': - oInfo.copyrightId = minfo.meta.copyrightId - oInfo.lrcUrl = minfo.meta.lrcUrl - oInfo.mrcUrl = minfo.meta.mrcUrl - oInfo.trcUrl = minfo.meta.trcUrl - break - } - } - - return oInfo -} diff --git a/src/utils/listManage.ts b/src/utils/listManage.ts new file mode 100644 index 000000000..031401387 --- /dev/null +++ b/src/utils/listManage.ts @@ -0,0 +1,329 @@ +import { + getUserLists as getUserListsFromStore, + getListMusics as getListMusicsFromStore, + // saveListMusics as saveListMusicsFromStore, + // removeListMusics as removeListMusicsFromStore, + overwriteListPosition, + overwriteListUpdateInfo, + removeListPosition, + removeListUpdateInfo, +} from '@/utils/data' +import { arrPush, arrPushByPosition, arrUnshift, freezeListItem } from '@/utils/common' +import { LIST_IDS } from '@/config/constant' + +export const userLists: LX.List.UserListInfo[] = [] +export const allMusicList = new Map<string, LX.Music.MusicInfo[]>() + +export const setUserLists = (lists: LX.List.UserListInfo[]) => { + userLists.splice(0, userLists.length, ...lists) + return userLists +} + +export const setMusicList = (listId: string, musicList: LX.Music.MusicInfo[]): LX.Music.MusicInfo[] => { + const list = freezeListItem(musicList) + allMusicList.set(listId, list) + return list +} +export const removeMusicList = (id: string) => { + allMusicList.delete(id) +} + + +const createUserList = ({ + name, + id, + source, + sourceListId, + locationUpdateTime, +}: LX.List.UserListInfo, position: number) => { + if (position < 0 || position >= userLists.length) { + userLists.push({ + name, + id, + source, + sourceListId, + locationUpdateTime, + }) + } else { + userLists.splice(position, 0, { + name, + id, + source, + sourceListId, + locationUpdateTime, + }) + } +} + +const updateList = ({ + name, + id, + source, + sourceListId, + // meta, + locationUpdateTime, +}: LX.List.UserListInfo & { meta?: { id?: string } }) => { + let index + switch (id) { + case LIST_IDS.DEFAULT: + case LIST_IDS.LOVE: + break + case LIST_IDS.TEMP: + // tempList.meta = meta ?? {} + // break + default: + index = userLists.findIndex(l => l.id == id) + if (index < 0) return + userLists.splice(index, 1, { ...userLists[index], name, source, sourceListId, locationUpdateTime }) + break + } +} + +const removeUserList = (id: string) => { + const index = userLists.findIndex(l => l.id == id) + if (index < 0) return + userLists.splice(index, 1) + // removeMusicList(id) +} + +const overwriteUserList = (lists: LX.List.UserListInfo[]) => { + userLists.splice(0, userLists.length, ...lists) +} + + +// const sendMyListUpdateEvent = (ids: string[]) => { +// window.app_event.myListUpdate(ids) +// } + +/** + * 获取用户列表 + * @returns 所有用户列表 + */ +export const getUserLists = async() => { + const lists = await getUserListsFromStore() + return setUserLists(lists) +} + + +export const listDataOverwrite = ({ defaultList, loveList, userList, tempList }: MakeOptional<LX.List.ListDataFull, 'tempList'>): string[] => { + const updatedListIds: string[] = [] + const newUserIds: string[] = [] + const newUserListInfos = userList.map(({ list, ...listInfo }) => { + if (allMusicList.has(listInfo.id)) updatedListIds.push(listInfo.id) + newUserIds.push(listInfo.id) + setMusicList(listInfo.id, list) + return listInfo + }) + for (const list of userLists) { + if (!allMusicList.has(list.id) || newUserIds.includes(list.id)) continue + removeMusicList(list.id) + updatedListIds.push(list.id) + } + overwriteUserList(newUserListInfos) + + if (allMusicList.has(LIST_IDS.DEFAULT)) updatedListIds.push(LIST_IDS.DEFAULT) + setMusicList(LIST_IDS.DEFAULT, defaultList) + setMusicList(LIST_IDS.LOVE, loveList) + updatedListIds.push(LIST_IDS.LOVE) + + if (tempList && allMusicList.has(LIST_IDS.TEMP)) { + setMusicList(LIST_IDS.TEMP, tempList) + updatedListIds.push(LIST_IDS.TEMP) + } + const newIds = [LIST_IDS.DEFAULT, LIST_IDS.LOVE, ...userList.map(l => l.id)] + if (tempList) newIds.push(LIST_IDS.TEMP) + void overwriteListPosition(newIds) + void overwriteListUpdateInfo(newIds) + return updatedListIds +} + +export const userListCreate = ({ name, id, source, sourceListId, position, locationUpdateTime }: { + name: string + id: string + source?: LX.OnlineSource + sourceListId?: string + position: number + locationUpdateTime: number | null +}) => { + if (userLists.some(item => item.id == id)) return + const newList: LX.List.UserListInfo = { + name, + id, + source, + sourceListId, + locationUpdateTime, + } + createUserList(newList, position) +} + +export const userListsRemove = (ids: string[]) => { + const changedIds = [] + for (const id of ids) { + removeUserList(id) + if (!allMusicList.has(id)) continue + removeMusicList(id) + void removeListPosition(id) + void removeListUpdateInfo(id) + changedIds.push(id) + } + + return changedIds +} + +export const userListsUpdate = (listInfos: LX.List.UserListInfo[]) => { + for (const info of listInfos) { + updateList(info) + } +} + +export const userListsUpdatePosition = (position: number, ids: string[]) => { + const newUserLists = [...userLists] + + // console.log(position, ids) + + const updateLists: LX.List.UserListInfo[] = [] + + // const targetItem = list[position] + const map = new Map<string, LX.List.UserListInfo>() + for (const item of newUserLists) map.set(item.id, item) + for (const id of ids) { + const listInfo = map.get(id) as LX.List.UserListInfo + listInfo.locationUpdateTime = Date.now() + updateLists.push(listInfo) + map.delete(id) + } + newUserLists.splice(0, newUserLists.length, ...newUserLists.filter(mInfo => map.has(mInfo.id))) + newUserLists.splice(Math.min(position, newUserLists.length), 0, ...updateLists) + + setUserLists(newUserLists) +} + +export const getListMusicSync = (id: string | null) => { + return id ? allMusicList.get(id) ?? [] : [] +} + +/** + * 获取列表内的歌曲 + * @param listId + */ +export const getListMusics = async(listId: string): Promise<LX.Music.MusicInfo[]> => { + if (!listId) return [] + if (allMusicList.has(listId)) return allMusicList.get(listId) as LX.Music.MusicInfo[] + const list = await getListMusicsFromStore(listId) + return setMusicList(listId, list) +} + +export const listMusicOverwrite = async(listId: string, musicInfos: LX.Music.MusicInfo[]): Promise<string[]> => { + setMusicList(listId, musicInfos) + return [listId] +} + +export const listMusicAdd = async(id: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType): Promise<string[]> => { + const targetList = await getListMusics(id) + + const listSet = new Set<string>() + for (const item of targetList) listSet.add(item.id) + musicInfos = musicInfos.filter(item => { + if (listSet.has(item.id)) return false + Object.freeze(item) + listSet.add(item.id) + return true + }) + switch (addMusicLocationType) { + case 'top': + arrUnshift(targetList, musicInfos) + break + case 'bottom': + default: + arrPush(targetList, musicInfos) + break + } + + return [id] +} + +export const listMusicRemove = async(listId: string, ids: string[]): Promise<string[]> => { + let targetList = await getListMusics(listId) + + const listSet = new Set<string>() + for (const item of targetList) listSet.add(item.id) + for (const id of ids) listSet.delete(id) + const newList = targetList.filter(mInfo => listSet.has(mInfo.id)) + targetList.splice(0, targetList.length) + arrPush(targetList, newList) + + return [listId] +} + +export const listMusicMove = async(fromId: string, toId: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType): Promise<string[]> => { + return [ + ...await listMusicRemove(fromId, musicInfos.map(musicInfo => musicInfo.id)), + ...await listMusicAdd(toId, musicInfos, addMusicLocationType), + ] +} + +export const listMusicUpdateInfo = async(musicInfos: LX.List.ListActionMusicUpdate): Promise<string[]> => { + const updateListIds = new Set<string>() + for (const { id, musicInfo } of musicInfos) { + const targetList = await getListMusics(id) + if (!targetList.length) continue + const index = targetList.findIndex(l => l.id == musicInfo.id) + if (index < 0) continue + const info: LX.Music.MusicInfo = { ...targetList[index] } + Object.assign(info, { + name: musicInfo.name, + singer: musicInfo.singer, + source: musicInfo.source, + interval: musicInfo.interval, + meta: musicInfo.meta, + }) + targetList.splice(index, 1, Object.freeze(info)) + updateListIds.add(id) + } + return Array.from(updateListIds) +} + + +export const listMusicUpdatePosition = async(listId: string, position: number, ids: string[]): Promise<string[]> => { + let targetList = await getListMusics(listId) + + // const infos = Array(ids.length) + // for (let i = targetList.length; i--;) { + // const item = targetList[i] + // const index = ids.indexOf(item.id) + // if (index < 0) continue + // infos.splice(index, 1, targetList.splice(i, 1)[0]) + // } + // targetList.splice(Math.min(position, targetList.length - 1), 0, ...infos) + + // console.time('ts') + + // const list = createSortedList(targetList, position, ids) + const infos: LX.Music.MusicInfo[] = [] + const map = new Map<string, LX.Music.MusicInfo>() + for (const item of targetList) map.set(item.id, item) + for (const id of ids) { + infos.push(map.get(id) as LX.Music.MusicInfo) + map.delete(id) + } + const list = targetList.filter(mInfo => map.has(mInfo.id)) + arrPushByPosition(list, infos, Math.min(position, list.length)) + + targetList.splice(0, targetList.length) + arrPush(targetList, list) + + // console.timeEnd('ts') + return [listId] +} + + +export const listMusicClear = async(ids: string[]): Promise<string[]> => { + const changedIds: string[] = [] + for (const id of ids) { + const list = await getListMusics(id) + if (!list.length) continue + setMusicList(id, []) + changedIds.push(id) + } + return changedIds +} diff --git a/src/utils/log.js b/src/utils/log.ts similarity index 85% rename from src/utils/log.js rename to src/utils/log.ts index 7e3834d08..f55ec1c5a 100644 --- a/src/utils/log.js +++ b/src/utils/log.ts @@ -4,16 +4,16 @@ import { temporaryDirectoryPath, existsFile, writeFile, appendFile, readFile, un const logPath = temporaryDirectoryPath + '/error.log' const logTools = { - tempLog: [], - writeLog(msg) { + tempLog: [] as Array<{ time: string, type: 'LOG' | 'WARN' | 'ERROR', text: string }> | null, + writeLog(msg: string) { console.log(msg) - appendFile(logPath, '\n----lx log----\n' + msg) + void appendFile(logPath, '\n----lx log----\n' + msg) }, async initLogFile() { try { let isExists = await existsFile(logPath) if (!isExists) await writeFile(logPath, '') - if (this.tempLog.length) this.writeLog(this.tempLog.map(m => `${m.time} ${m.type} ${m.text}`).join('\n----lx log----\n')) + if (this.tempLog?.length) this.writeLog(this.tempLog.map(m => `${m.time} ${m.type} ${m.text}`).join('\n----lx log----\n')) this.tempLog = null } catch (err) { console.log(err) @@ -21,20 +21,20 @@ const logTools = { }, } -export const init = () => { +export const init = async() => { return logTools.initLogFile() } -export const getLogs = () => { +export const getLogs = async() => { return readFile(logPath) } -export const clearLogs = () => { - return unlink(logPath).then(() => writeFile(logPath, '')) +export const clearLogs = async() => { + return unlink(logPath).then(async() => writeFile(logPath, '')) } export const log = { - info(...msgs) { + info(...msgs: any[]) { // console.info(...msgs) const msg = msgs.map(m => typeof m == 'string' ? m : JSON.stringify(m)).join(' ') if (msg.startsWith('%c')) return @@ -43,7 +43,7 @@ export const log = { logTools.tempLog.push({ type: 'LOG', time, text: msg }) } else logTools.writeLog(`${time} LOG ${msg}`) }, - warn(...msgs) { + warn(...msgs: any[]) { // console.warn(...msgs) const msg = msgs.map(m => typeof m == 'string' ? m : JSON.stringify(m)).join(' ') const time = new Date().toLocaleString() @@ -51,7 +51,7 @@ export const log = { logTools.tempLog.push({ type: 'WARN', time, text: msg }) } else logTools.writeLog(`${time} WARN ${msg}`) }, - error(...msgs) { + error(...msgs: any[]) { // console.error...(msgs) const msg = msgs.map(m => typeof m == 'string' ? m : JSON.stringify(m)).join(' ') const time = new Date().toLocaleString() diff --git a/src/utils/lyric.js b/src/utils/lyric.js deleted file mode 100644 index aadbed730..000000000 --- a/src/utils/lyric.js +++ /dev/null @@ -1,76 +0,0 @@ -import { - play as lrcPlay, - setLyric as lrcSetLyric, - pause as lrcPause, - toggleTranslation as lrcToggleTranslation, - toggleRoma as lrcToggleRoma, - init as lrcInit, -} from '@/plugins/lyric' -import { - play as lrcdPlay, - setLyric as lrcdSetLyric, - pause as lrcdPause, - toggleTranslation as lrcdToggleTranslation, - toggleRoma as lrcdToggleRoma, -} from '@/utils/lyricDesktop' - -/** - * init lyric - * @returns {Promise} - */ -export const init = () => { - return lrcInit() -} - -/** - * set lyric - * @param {String} lyric lyric str - * @param {String} translation lyric translation - */ -export const setLyric = (lyric, translation = '', romalrc = '') => { - lrcdSetLyric(lyric, translation, romalrc) - lrcSetLyric(lyric, translation, romalrc) -} - -/** - * play lyric - * @param {Number} time play time - */ -export const play = time => { - lrcPlay(time) - lrcdPlay(time) -} - -/** - * pause lyric - */ -export const pause = () => { - lrcPause() - lrcdPause() -} - -/** - * stop lyric - */ -export const stop = () => { - setLyric('') -} - -/** - * toggle show translation - * @param {Boolean} isShowTranslation is show translation - */ -export const toggleTranslation = isShowTranslation => { - lrcToggleTranslation(isShowTranslation) - lrcdToggleTranslation(isShowTranslation) -} - -/** - * toggle show roma lyric - * @param {Boolean} isShowLyricRoma is show roma lyric - */ -export const toggleRoma = isShowLyricRoma => { - lrcToggleRoma(isShowLyricRoma) - lrcdToggleRoma(isShowLyricRoma) -} - diff --git a/src/utils/lyricDesktop.js b/src/utils/lyricDesktop.js deleted file mode 100644 index b11ec1a53..000000000 --- a/src/utils/lyricDesktop.js +++ /dev/null @@ -1,231 +0,0 @@ -import { NativeModules, NativeEventEmitter } from 'react-native' - -const { LyricModule } = NativeModules - -let isShowLyric = false - -export const themes = [ - { id: 'green', value: '#07c556' }, - { id: 'yellow', value: '#fffa12' }, - { id: 'blue', value: '#19b5fe' }, - { id: 'red', value: '#ff1222' }, - { id: 'pink', value: '#f1828d' }, - { id: 'purple', value: '#c851d4' }, - { id: 'orange', value: '#ffad12' }, - { id: 'grey', value: '#bdc3c7' }, - { id: 'black', value: '#333333' }, - { id: 'white', value: '#ffffff' }, -] - -export const textPositionX = [ - { id: 'left', value: 'LEFT' }, - { id: 'center', value: 'CENTER' }, - { id: 'right', value: 'RIGHT' }, -] -export const textPositionY = [ - { id: 'top', value: 'TOP' }, - { id: 'center', value: 'CENTER' }, - { id: 'bottom', value: 'BOTTOM' }, -] - -const getThemeColor = themeId => (themes.find(t => t.id == themeId) || themes[0]).value -const getTextPositionX = x => (textPositionX.find(t => t.id == x) || textPositionX[0]).value -const getTextPositionY = y => (textPositionY.find(t => t.id == y) || textPositionY[0]).value -const getAlpha = num => parseInt(num) / 100 -const getTextSize = num => parseInt(num) / 10 - - -/** - * show lyric - * @param {Number} isLock is lock lyric window - * @returns {Promise} Promise - */ -export const showLyric = ({ - isShowToggleAnima, - isSingleLine, - width, - maxLineNum, - isLock, - themeId, - opacity, - textSize, - positionX, - positionY, - textPositionX, - textPositionY, -}) => { - if (isShowLyric) return Promise.resolve() - return LyricModule.showLyric({ - isSingleLine, - isShowToggleAnima, - isLock, - themeColor: getThemeColor(themeId), - alpha: getAlpha(opacity), - textSize: getTextSize(textSize), - lyricViewX: positionX, - lyricViewY: positionY, - textX: getTextPositionX(textPositionX), - textY: getTextPositionY(textPositionY), - width, - maxLineNum, - }).then(() => { - isShowLyric = true - }) -} - -/** - * hide lyric - * @returns {Promise} Promise - */ -export const hideLyric = () => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.hideLyric().then(() => { - isShowLyric = false - }) -} - - -/** - * play lyric - * @param {Number} time play time - * @returns {Promise} Promise - */ -export const play = time => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.play(time) -} - -/** - * pause lyric - * @returns {Promise} Promise - */ -export const pause = () => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.pause() -} - -/** - * set lyric - * @param {String} lyric lyric str - * @param {String} translation lyric translation - * @returns {Promise} Promise - */ -export const setLyric = (lyric, translation, romalrc) => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.setLyric(lyric, translation || '', romalrc || '') -} - -/** - * toggle show translation - * @param {Boolean} isShowTranslation is show translation - * @returns {Promise} Promise - */ -export const toggleTranslation = isShowTranslation => { - // if (!isShowLyric) return Promise.resolve() - return LyricModule.toggleTranslation(isShowTranslation) -} - -/** - * toggle show roma lyric - * @param {Boolean} isShowRoma is show roma lyric - * @returns {Promise} Promise - */ -export const toggleRoma = isShowRoma => { - // if (!isShowLyric) return Promise.resolve() - return LyricModule.toggleRoma(isShowRoma) -} - -/** - * toggle is lock lyric window - * @param {Boolean} isLock is lock lyric window - * @returns {Promise} Promise - */ -export const toggleLock = isLock => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.toggleLock(isLock) -} - -/** - * set theme - * @param {*} themeId theme id - * @returns {Promise} Promise - */ -export const setTheme = themeId => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.setColor(getThemeColor(themeId)) -} - -/** - * set text alpha - * @param {*} alpha text alpha - * @returns {Promise} Promise - */ -export const setAlpha = alpha => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.setAlpha(getAlpha(alpha)) -} - -/** - * set text size - * @param {*} size text size - * @returns {Promise} Promise - */ -export const setTextSize = size => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.setTextSize(getTextSize(size)) -} - -export const setShowToggleAnima = isShowToggleAnima => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.setShowToggleAnima(isShowToggleAnima) -} - -export const setSingleLine = isSingleLine => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.setSingleLine(isSingleLine) -} - -export const setPosition = (x, y) => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.setPosition(x, y) -} - -export const setMaxLineNum = maxLineNum => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.setMaxLineNum(maxLineNum) -} - -export const setWidth = width => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.setWidth(width) -} - -export const fixViewPosition = () => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.fixViewPosition() -} - -export const setLyricTextPosition = (textX, textY) => { - if (!isShowLyric) return Promise.resolve() - return LyricModule.setLyricTextPosition(getTextPositionX(textX), getTextPositionY(textY)) -} - -export const checkOverlayPermission = () => { - return LyricModule.checkOverlayPermission() -} - -export const openOverlayPermissionActivity = () => { - return LyricModule.openOverlayPermissionActivity() -} - -export const onPositionChange = callback => { - const eventEmitter = new NativeEventEmitter(LyricModule) - const eventListener = eventEmitter.addListener('set-position', event => { - callback(event) - }) - - return () => { - eventListener.remove() - } -} - diff --git a/src/utils/message.js b/src/utils/message.ts similarity index 97% rename from src/utils/message.js rename to src/utils/message.ts index fb5accd95..f1d15b84a 100644 --- a/src/utils/message.js +++ b/src/utils/message.ts @@ -5,4 +5,4 @@ export const requestMsg = { // unachievable: '哦No😱...接口无法访问了!已帮你切换到临时接口,重试下看能不能播放吧~', notConnectNetwork: '无法连接到服务器', cancelRequest: '取消http请求', -} +} as const diff --git a/src/utils/music/api-source-info.js b/src/utils/musicSdk/api-source-info.js similarity index 100% rename from src/utils/music/api-source-info.js rename to src/utils/musicSdk/api-source-info.js diff --git a/src/utils/music/api-source.js b/src/utils/musicSdk/api-source.js similarity index 90% rename from src/utils/music/api-source.js rename to src/utils/musicSdk/api-source.js index b7833672d..969b41171 100644 --- a/src/utils/music/api-source.js +++ b/src/utils/musicSdk/api-source.js @@ -13,6 +13,9 @@ import direct_api_tx from './tx/api-direct' import direct_api_wy from './wy/api-direct' import direct_api_mg from './mg/api-direct' +import settingState from '@/store/setting/state' + + const apiList = { temp_api_kw, // test_api_bd: require('./bd/api-test'), @@ -41,7 +44,7 @@ for (const api of apiSourceInfo) { // } } -const getAPI = source => apiList[`${global.globalObj.apiSource}_api_${source}`] +const getAPI = source => apiList[`${settingState.setting['common.apiSource']}_api_${source}`] const apis = source => { const api = getAPI(source) diff --git a/src/utils/music/bd/api-test.js b/src/utils/musicSdk/bd/api-test.js similarity index 100% rename from src/utils/music/bd/api-test.js rename to src/utils/musicSdk/bd/api-test.js diff --git a/src/utils/music/bd/hotSearch.js b/src/utils/musicSdk/bd/hotSearch.js similarity index 100% rename from src/utils/music/bd/hotSearch.js rename to src/utils/musicSdk/bd/hotSearch.js diff --git a/src/utils/music/bd/index.js b/src/utils/musicSdk/bd/index.js similarity index 100% rename from src/utils/music/bd/index.js rename to src/utils/musicSdk/bd/index.js diff --git a/src/utils/music/bd/leaderboard.js b/src/utils/musicSdk/bd/leaderboard.js similarity index 100% rename from src/utils/music/bd/leaderboard.js rename to src/utils/musicSdk/bd/leaderboard.js diff --git a/src/utils/music/bd/musicInfo.js b/src/utils/musicSdk/bd/musicInfo.js similarity index 100% rename from src/utils/music/bd/musicInfo.js rename to src/utils/musicSdk/bd/musicInfo.js diff --git a/src/utils/music/bd/musicSearch.js b/src/utils/musicSdk/bd/musicSearch.js similarity index 100% rename from src/utils/music/bd/musicSearch.js rename to src/utils/musicSdk/bd/musicSearch.js diff --git a/src/utils/music/bd/songList.js b/src/utils/musicSdk/bd/songList.js similarity index 100% rename from src/utils/music/bd/songList.js rename to src/utils/musicSdk/bd/songList.js diff --git a/src/utils/music/index.js b/src/utils/musicSdk/index.js similarity index 100% rename from src/utils/music/index.js rename to src/utils/musicSdk/index.js diff --git a/src/utils/music/kg/api-direct.js b/src/utils/musicSdk/kg/api-direct.js similarity index 100% rename from src/utils/music/kg/api-direct.js rename to src/utils/musicSdk/kg/api-direct.js diff --git a/src/utils/music/kg/api-test.js b/src/utils/musicSdk/kg/api-test.js similarity index 100% rename from src/utils/music/kg/api-test.js rename to src/utils/musicSdk/kg/api-test.js diff --git a/src/utils/music/kg/comment.js b/src/utils/musicSdk/kg/comment.js similarity index 89% rename from src/utils/music/kg/comment.js rename to src/utils/musicSdk/kg/comment.js index 17f992896..a2178e0b4 100644 --- a/src/utils/music/kg/comment.js +++ b/src/utils/musicSdk/kg/comment.js @@ -1,5 +1,5 @@ import { httpFetch } from '../../request' -import { decodeName, dateFormat2 } from '../../' +import { decodeName, dateFormat2 } from '../../index' export default { _requestObj: null, @@ -7,7 +7,7 @@ export default { async getComment({ hash }, page = 1, limit = 20) { if (this._requestObj) this._requestObj.cancelHttp() - const _requestObj = httpFetch(`http://comment.service.kugou.com/index.php?r=commentsv2/getCommentWithLike&code=fc4be23b4e972707f36b8a828a93ba8a&extdata=${hash}&p=${page}&pagesize=${limit}&ver=1.01&clientver=8373&appid=1001&kugouid=687373022`, { + const _requestObj = httpFetch(`http://comment.service.kugou.com/index.php?r=commentsv2/getCommentWithLike&code=fc4be23b4e972707f36b8a828a93ba8a&extdata=${hash}&p=${page}&pagesize=${limit}&ver=1.01&clientver=8373&appid=1001&kugouid=687373022&need_show_image=1`, { headers: { 'User-Agent': 'Android712-AndroidPhone-8983-18-0-COMMENT-wifi', }, @@ -21,7 +21,7 @@ export default { // console.log(songmid) if (this._requestObj2) this._requestObj2.cancelHttp() - const _requestObj2 = httpFetch(`http://comment.service.kugou.com/index.php?r=commentsv2/getCommentWithLike&code=fc4be23b4e972707f36b8a828a93ba8a&extdata=${hash}&p=${page}&pagesize=${limit}&ver=1.01&clientver=8373&appid=1001&kugouid=687373022`, { + const _requestObj2 = httpFetch(`http://comment.service.kugou.com/index.php?r=commentsv2/getCommentWithLike&code=fc4be23b4e972707f36b8a828a93ba8a&extdata=${hash}&p=${page}&pagesize=${limit}&ver=1.01&clientver=8373&appid=1001&kugouid=687373022&need_show_image=1`, { headers: { 'User-Agent': 'Android712-AndroidPhone-8983-18-0-COMMENT-wifi', }, @@ -39,7 +39,7 @@ export default { ? audioId.split('_')[0] : songmid - const _requestObj2 = httpFetch(`http://comment.service.kugou.com/index.php?r=commentsv2/getReplyWithLike&code=fc4be23b4e972707f36b8a828a93ba8a&p=${page}&pagesize=${limit}&ver=1.01&clientver=8373&kugouid=687373022&appid=1001&childrenid=${songmid}&tid=${replyId}`, { + const _requestObj2 = httpFetch(`http://comment.service.kugou.com/index.php?r=commentsv2/getReplyWithLike&code=fc4be23b4e972707f36b8a828a93ba8a&p=${page}&pagesize=${limit}&ver=1.01&clientver=8373&kugouid=687373022&need_show_image=1&appid=1001&childrenid=${songmid}&tid=${replyId}`, { headers: { 'User-Agent': 'Android712-AndroidPhone-8983-18-0-COMMENT-wifi', }, @@ -54,6 +54,8 @@ export default { let data = { id: item.id, text: decodeName(item.content || '').split('\n'), + images: item.images ? item.images.map(i => i.url) : [], + location: item.location, time: item.addtime, timeStr: dateFormat2(new Date(item.addtime).getTime()), userName: item.user_name, diff --git a/src/utils/music/kg/hotSearch.js b/src/utils/musicSdk/kg/hotSearch.js similarity index 98% rename from src/utils/music/kg/hotSearch.js rename to src/utils/musicSdk/kg/hotSearch.js index 4e0e24439..0496c0edb 100644 --- a/src/utils/music/kg/hotSearch.js +++ b/src/utils/musicSdk/kg/hotSearch.js @@ -9,6 +9,7 @@ export default { const _requestObj = httpFetch('http://gateway.kugou.com/api/v3/search/hot_tab?signature=ee44edb9d7155821412d220bcaf509dd&appid=1005&clientver=10026&plat=0', { method: 'get', + cache: null, headers: { dfid: '1ssiv93oVqMp27cirf2CvoF1', mid: '156798703528610303473757548878786007104', diff --git a/src/utils/music/kg/index.js b/src/utils/musicSdk/kg/index.js similarity index 100% rename from src/utils/music/kg/index.js rename to src/utils/musicSdk/kg/index.js diff --git a/src/utils/music/kg/leaderboard.js b/src/utils/musicSdk/kg/leaderboard.js similarity index 100% rename from src/utils/music/kg/leaderboard.js rename to src/utils/musicSdk/kg/leaderboard.js diff --git a/src/utils/music/kg/lyric.js b/src/utils/musicSdk/kg/lyric.js similarity index 100% rename from src/utils/music/kg/lyric.js rename to src/utils/musicSdk/kg/lyric.js diff --git a/src/utils/music/kg/musicSearch.js b/src/utils/musicSdk/kg/musicSearch.js similarity index 98% rename from src/utils/music/kg/musicSearch.js rename to src/utils/musicSdk/kg/musicSearch.js index 20c59a4c1..b9357cb62 100644 --- a/src/utils/music/kg/musicSearch.js +++ b/src/utils/musicSdk/kg/musicSearch.js @@ -77,7 +77,7 @@ export default { }) return list }, - search(str, page = 1, { limit } = {}, retryNum = 0) { + search(str, page = 1, limit, retryNum = 0) { if (++retryNum > 3) return Promise.reject(new Error('try max num')) if (limit == null) limit = this.limit // http://newlyric.kuwo.cn/newlyric.lrc?62355680 diff --git a/src/utils/music/kg/pic.js b/src/utils/musicSdk/kg/pic.js similarity index 100% rename from src/utils/music/kg/pic.js rename to src/utils/musicSdk/kg/pic.js diff --git a/src/utils/music/kg/songList.js b/src/utils/musicSdk/kg/songList.js similarity index 94% rename from src/utils/music/kg/songList.js rename to src/utils/musicSdk/kg/songList.js index 3477fe345..fe0dd0144 100644 --- a/src/utils/music/kg/songList.js +++ b/src/utils/musicSdk/kg/songList.js @@ -1,5 +1,5 @@ import { httpFetch } from '../../request' -import { decodeName, formatPlayTime, sizeFormate } from '../../index' +import { decodeName, formatPlayTime, sizeFormate, dateFormat } from '../../index' import { toMD5 } from '../utils' import infSign from './vendors/infSign.min' @@ -154,8 +154,9 @@ export default { id: 'id_' + item.specialid, author: item.nickname, name: item.specialname, - time: item.publish_time || item.publishtime, + time: dateFormat(item.publish_time || item.publishtime, 'Y-M-D'), img: item.img || item.imgurl, + total: item.songcount, grade: item.grade, desc: item.intro, source: 'kg', @@ -165,7 +166,6 @@ export default { async createHttp(url, options, retryNum = 0) { if (retryNum > 2) throw new Error('try max num') let result - options.cache = 'default' try { result = await httpFetch(url, options).promise } catch (err) { @@ -522,7 +522,8 @@ export default { if (id.includes('special/single/')) { id = id.replace(this.regExps.listDetailLink, '$1') } else if (/https?:/.test(id)) { - return this.getUserListDetail(id.replace(/^.*http/, 'http'), page) + // fix https://www.kugou.com/songlist/xxx/?uid=xxx&chl=qq_client&cover=http%3A%2F%2Fimge.kugou.com%xxx.jpg&iszlist=1 + return this.getUserListDetail(id.replace(/^.*?http/, 'http'), page) } else if (/^\d+$/.test(id)) { return this.getUserListDetailByCode(id) } else if (id.startsWith('id_')) { @@ -729,6 +730,35 @@ export default { } return `https://www.kugou.com/yy/special/single/${id}.html` }, + + search(text, page, limit = 20) { + // http://msearchretry.kugou.com/api/v3/search/special?version=9209&keyword=%E5%91%A8%E6%9D%B0%E4%BC%A6&pagesize=20&filter=0&page=1&sver=2&with_res_tag=0 + // return httpFetch(`http://ioscdn.kugou.com/api/v3/search/special?keyword=${encodeURIComponent(text)}&page=${page}&pagesize=${limit}&showtype=10&plat=2&version=7910&correct=1&sver=5`) + return httpFetch(`http://msearchretry.kugou.com/api/v3/search/special?keyword=${encodeURIComponent(text)}&page=${page}&pagesize=${limit}&showtype=10&filter=0&version=7910&sver=2`) + .promise.then(({ body }) => { + if (body.errcode != 0) throw new Error('filed') + // console.log(body.data.info) + return { + list: body.data.info.map(item => { + return { + play_count: this.formatPlayCount(item.playcount), + id: 'id_' + item.specialid, + author: item.nickname, + name: item.specialname, + time: dateFormat(item.publishtime, 'Y-M-D'), + img: item.imgurl, + grade: item.grade, + desc: item.intro, + total: item.songcount, + source: 'kg', + } + }), + limit, + total: body.data.total, + source: 'kg', + } + }) + }, } // getList diff --git a/src/utils/music/kg/util.js b/src/utils/musicSdk/kg/util.js similarity index 100% rename from src/utils/music/kg/util.js rename to src/utils/musicSdk/kg/util.js diff --git a/src/utils/music/kg/vendors/infSign.min.js b/src/utils/musicSdk/kg/vendors/infSign.min.js similarity index 100% rename from src/utils/music/kg/vendors/infSign.min.js rename to src/utils/musicSdk/kg/vendors/infSign.min.js diff --git a/src/utils/music/kw/album.js b/src/utils/musicSdk/kw/album.js similarity index 100% rename from src/utils/music/kw/album.js rename to src/utils/musicSdk/kw/album.js diff --git a/src/utils/music/kw/api-direct.js b/src/utils/musicSdk/kw/api-direct.js similarity index 100% rename from src/utils/music/kw/api-direct.js rename to src/utils/musicSdk/kw/api-direct.js diff --git a/src/utils/music/kw/api-temp.js b/src/utils/musicSdk/kw/api-temp.js similarity index 100% rename from src/utils/music/kw/api-temp.js rename to src/utils/musicSdk/kw/api-temp.js diff --git a/src/utils/music/kw/api-test.js b/src/utils/musicSdk/kw/api-test.js similarity index 100% rename from src/utils/music/kw/api-test.js rename to src/utils/musicSdk/kw/api-test.js diff --git a/src/utils/music/kw/comment.js b/src/utils/musicSdk/kw/comment.js similarity index 100% rename from src/utils/music/kw/comment.js rename to src/utils/musicSdk/kw/comment.js diff --git a/src/utils/music/kw/decodeLyric.js b/src/utils/musicSdk/kw/decodeLyric.js similarity index 98% rename from src/utils/music/kw/decodeLyric.js rename to src/utils/musicSdk/kw/decodeLyric.js index d36aa6f46..25d32ee3b 100644 --- a/src/utils/music/kw/decodeLyric.js +++ b/src/utils/musicSdk/kw/decodeLyric.js @@ -13,7 +13,7 @@ const decodeLyric = async(buf, isGetLyricx) => { // if (!info.startsWith('tp=content')) return null // const isLyric = info.includes('\r\nlrcx=0\r\n') if (buf.toString('utf8', 0, 10) != 'tp=content') return '' - console.log(buf) + // console.log(buf) // const index = buf.indexOf('\r\n\r\n') + 4 const lrcData = await handleInflate(buf.slice(buf.indexOf('\r\n\r\n') + 4)) diff --git a/src/utils/music/kw/hotSearch.js b/src/utils/musicSdk/kw/hotSearch.js similarity index 100% rename from src/utils/music/kw/hotSearch.js rename to src/utils/musicSdk/kw/hotSearch.js diff --git a/src/utils/music/kw/index.js b/src/utils/musicSdk/kw/index.js similarity index 100% rename from src/utils/music/kw/index.js rename to src/utils/musicSdk/kw/index.js diff --git a/src/utils/music/kw/leaderboard.js b/src/utils/musicSdk/kw/leaderboard.js similarity index 100% rename from src/utils/music/kw/leaderboard.js rename to src/utils/musicSdk/kw/leaderboard.js diff --git a/src/utils/music/kw/lyric.js b/src/utils/musicSdk/kw/lyric.js similarity index 100% rename from src/utils/music/kw/lyric.js rename to src/utils/musicSdk/kw/lyric.js diff --git a/src/utils/music/kw/musicSearch.js b/src/utils/musicSdk/kw/musicSearch.js similarity index 98% rename from src/utils/music/kw/musicSearch.js rename to src/utils/musicSdk/kw/musicSearch.js index e348b204d..9edd8e97f 100644 --- a/src/utils/music/kw/musicSearch.js +++ b/src/utils/musicSdk/kw/musicSearch.js @@ -100,7 +100,7 @@ export default { // console.log(result) return result }, - search(str, page = 1, { limit } = {}, retryNum = 0) { + search(str, page = 1, limit, retryNum = 0) { if (retryNum > 2) return Promise.reject(new Error('try max num')) if (limit == null) limit = this.limit // http://newlyric.kuwo.cn/newlyric.lrc?62355680 diff --git a/src/utils/music/kw/pic.js b/src/utils/musicSdk/kw/pic.js similarity index 100% rename from src/utils/music/kw/pic.js rename to src/utils/musicSdk/kw/pic.js diff --git a/src/utils/music/kw/songList.js b/src/utils/musicSdk/kw/songList.js similarity index 93% rename from src/utils/music/kw/songList.js rename to src/utils/musicSdk/kw/songList.js index ca3b7a5db..c81e458a7 100644 --- a/src/utils/music/kw/songList.js +++ b/src/utils/musicSdk/kw/songList.js @@ -1,6 +1,6 @@ import { httpFetch } from '../../request' import { formatPlayTime, decodeName } from '../../index' -import { formatSinger } from './util' +import { formatSinger, objStr2JSON } from './util' import album from './album' export default { @@ -110,7 +110,7 @@ export default { source: 'kw', } } else if (!body.length) { - return this.getList(sortId, id, type, page, ++tryNum) + return this.getList(sortId, tagId, page, ++tryNum) } return { list: this.filterList2(body), @@ -402,8 +402,8 @@ export default { if (info) { switch (info[2]) { case '4000': - types.push({ type: 'flac32bit', size: info[4] }) - _types.flac32bit = { + types.push({ type: 'flac24bit', size: info[4] }) + _types.flac24bit = { size: info[4].toLocaleUpperCase(), } break @@ -459,6 +459,32 @@ export default { } return `http://www.kuwo.cn/playlist_detail/${id}` }, + + search(text, page, limit = 20) { + return httpFetch(`http://search.kuwo.cn/r.s?all=${encodeURIComponent(text)}&pn=${page - 1}&rn=${limit}&rformat=json&encoding=utf8&ver=mbox&vipver=MUSIC_8.7.7.0_BCS37&plat=pc&devid=28156413&ft=playlist&pay=0&needliveshow=0`) + .promise.then(({ body }) => { + body = objStr2JSON(body) + // console.log(body) + return { + list: body.abslist.map(item => { + return { + play_count: this.formatPlayCount(item.playcnt), + id: item.playlistid, + author: decodeName(item.nickname), + name: decodeName(item.name), + total: item.songnum, + // time: item.publish_time, + img: item.pic, + desc: decodeName(item.intro), + source: 'kw', + } + }), + limit, + total: parseInt(body.TOTAL), + source: 'kw', + } + }) + }, } // getList diff --git a/src/utils/music/kw/tempSearch.js b/src/utils/musicSdk/kw/tempSearch.js similarity index 100% rename from src/utils/music/kw/tempSearch.js rename to src/utils/musicSdk/kw/tempSearch.js diff --git a/src/utils/music/kw/util.js b/src/utils/musicSdk/kw/util.js similarity index 73% rename from src/utils/music/kw/util.js rename to src/utils/musicSdk/kw/util.js index 4df9da096..625f48c4b 100644 --- a/src/utils/music/kw/util.js +++ b/src/utils/musicSdk/kw/util.js @@ -7,26 +7,32 @@ const kw_token = { isGetingToken: false, } -const translationMap = { - "{'": '{"', - "'}\n": '"}', - "'}": '"}', - "':'": '":"', - "','": '","', - "':{'": '":{"', - "':['": '":["', - "'}],'": '"}],"', - "':[{'": '":[{"', - "'},'": '"},"', - "'},{'": '"},{"', - "':[],'": '":[],"', - "':{},'": '":{},"', -} +// const translationMap = { +// "{'": '{"', +// "'}\n": '"}', +// "'}": '"}', +// "':'": '":"', +// "','": '","', +// "':{'": '":{"', +// "':['": '":["', +// "'}],'": '"}],"', +// "':[{'": '":[{"', +// "'},'": '"},"', +// "'},{'": '"},{"', +// "':[],'": '":[],"', +// "':{},'": '":{},"', +// "'}]}": '"}]}', +// } + +// export const objStr2JSON = str => { +// return JSON.parse(str.replace(/(^{'|'}\n$|'}$|':'|','|':\[{'|'}\],'|':{'|'},'|'},{'|':\['|':\[\],'|':{},'|'}]})/g, s => translationMap[s])) +// } export const objStr2JSON = str => { - return JSON.parse(str.replace(/(^{'|'}\n$|'}$|':'|','|':\[{'|'}\],'|':{'|'},'|'},{'|':\['|':\[\],'|':{},')/g, s => translationMap[s])) + return JSON.parse(str.replace(/('(?=(,\s*')))|('(?=:))|((?<=([:,]\s*))')|((?<={)')|('(?=}))/g, '"')) } + export const formatSinger = rawData => rawData.replace(/&/g, '、') export const matchToken = headers => { diff --git a/src/utils/music/mg/album.js b/src/utils/musicSdk/mg/album.js similarity index 97% rename from src/utils/music/mg/album.js rename to src/utils/musicSdk/mg/album.js index 625fc3ac7..759f36367 100644 --- a/src/utils/music/mg/album.js +++ b/src/utils/musicSdk/mg/album.js @@ -22,7 +22,7 @@ export default { requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj) return tryRequestObj.promise } - console.log(body) + // console.log(body) return body.songList }) return requestObj diff --git a/src/utils/music/mg/api-direct.js b/src/utils/musicSdk/mg/api-direct.js similarity index 100% rename from src/utils/music/mg/api-direct.js rename to src/utils/musicSdk/mg/api-direct.js diff --git a/src/utils/music/mg/api-test.js b/src/utils/musicSdk/mg/api-test.js similarity index 100% rename from src/utils/music/mg/api-test.js rename to src/utils/musicSdk/mg/api-test.js diff --git a/src/utils/music/mg/comment.js b/src/utils/musicSdk/mg/comment.js similarity index 100% rename from src/utils/music/mg/comment.js rename to src/utils/musicSdk/mg/comment.js diff --git a/src/utils/music/mg/hotSearch.js b/src/utils/musicSdk/mg/hotSearch.js similarity index 100% rename from src/utils/music/mg/hotSearch.js rename to src/utils/musicSdk/mg/hotSearch.js diff --git a/src/utils/music/mg/index.js b/src/utils/musicSdk/mg/index.js similarity index 100% rename from src/utils/music/mg/index.js rename to src/utils/musicSdk/mg/index.js diff --git a/src/utils/music/mg/leaderboard.js b/src/utils/musicSdk/mg/leaderboard.js similarity index 100% rename from src/utils/music/mg/leaderboard.js rename to src/utils/musicSdk/mg/leaderboard.js diff --git a/src/utils/music/mg/leaderboard2.js b/src/utils/musicSdk/mg/leaderboard2.js similarity index 100% rename from src/utils/music/mg/leaderboard2.js rename to src/utils/musicSdk/mg/leaderboard2.js diff --git a/src/utils/music/mg/lyric.js b/src/utils/musicSdk/mg/lyric.js similarity index 100% rename from src/utils/music/mg/lyric.js rename to src/utils/musicSdk/mg/lyric.js diff --git a/src/utils/music/mg/musicSearch.js b/src/utils/musicSdk/mg/musicSearch.js similarity index 98% rename from src/utils/music/mg/musicSearch.js rename to src/utils/musicSdk/mg/musicSearch.js index 43bc8c972..421f4ce8c 100644 --- a/src/utils/music/mg/musicSearch.js +++ b/src/utils/musicSdk/mg/musicSearch.js @@ -107,7 +107,7 @@ export default { }) return list }, - search(str, page = 1, { limit } = {}, retryNum = 0) { + search(str, page = 1, limit, retryNum = 0) { if (++retryNum > 3) return Promise.reject(new Error('try max num')) if (limit == null) limit = this.limit // http://newlyric.kuwo.cn/newlyric.lrc?62355680 diff --git a/src/utils/music/mg/pic.js b/src/utils/musicSdk/mg/pic.js similarity index 100% rename from src/utils/music/mg/pic.js rename to src/utils/musicSdk/mg/pic.js diff --git a/src/utils/music/mg/songList.js b/src/utils/musicSdk/mg/songList.js similarity index 93% rename from src/utils/music/mg/songList.js rename to src/utils/musicSdk/mg/songList.js index 9bfaed5f5..243008d2e 100644 --- a/src/utils/music/mg/songList.js +++ b/src/utils/musicSdk/mg/songList.js @@ -1,5 +1,5 @@ import { httpFetch } from '../../request' -import { sizeFormate } from '../../index' +import { sizeFormate, dateFormat } from '../../index' // const tagData = { code: '000000', info: 'SUCCESS', columnInfo: { columnTitle: '分类', columnId: '15244430', columnPid: '15031270', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 6, columnStatus: 1, columnCreateTime: '2016-11-10 10:53:05.077', columntype: 2011, contents: [{ contentId: '18464615', relationType: 2011, objectInfo: { columnTitle: '热门', columnId: '18464615', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 8, columnStatus: 1, columnCreateTime: '2017-02-20 16:09:13.400', columntype: 2011, contents: [{ contentId: '1000001672', relationType: 4034, objectInfo: { tagId: '1000001672', tagName: '流行', resourceType: '2034' }, relationSort: 9 }, { contentId: '1003449727', relationType: 4034, objectInfo: { tagId: '1003449727', tagName: '厂牌', resourceType: '2034' }, relationSort: 8 }, { contentId: '1000001795', relationType: 4034, objectInfo: { tagId: '1000001795', tagName: '伤感', resourceType: '2034' }, relationSort: 7 }, { contentId: '1001076080', relationType: 4034, objectInfo: { tagId: '1001076080', tagName: '电影', resourceType: '2034' }, relationSort: 6 }, { contentId: '1000001675', relationType: 4034, objectInfo: { tagId: '1000001675', tagName: '中国风', resourceType: '2034' }, relationSort: 5 }, { contentId: '1000001635', relationType: 4034, objectInfo: { tagId: '1000001635', tagName: '经典老歌', resourceType: '2034' }, relationSort: 4 }, { contentId: '1000001831', relationType: 4034, objectInfo: { tagId: '1000001831', tagName: '翻唱', resourceType: '2034' }, relationSort: 3 }, { contentId: '1000001762', relationType: 4034, objectInfo: { tagId: '1000001762', tagName: '国语', resourceType: '2034' }, relationSort: 1 }], dataVersion: '1620410266029', customizedPicUrls: [] }, relationSort: 6 }, { contentId: '15244503', relationType: 2011, objectInfo: { columnTitle: '主题', columnId: '15244503', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 23, columnStatus: 1, columnCreateTime: '2016-11-10 10:54:10.261', columntype: 2011, contents: [{ contentId: '1003449727', relationType: 4034, objectInfo: { tagId: '1003449727', tagName: '厂牌', resourceType: '2034' }, relationSort: 29 }, { contentId: '1001076080', relationType: 4034, objectInfo: { tagId: '1001076080', tagName: '电影', resourceType: '2034' }, relationSort: 28 }, { contentId: '1001076078', relationType: 4034, objectInfo: { tagId: '1001076078', tagName: '电视剧', resourceType: '2034' }, relationSort: 27 }, { contentId: '1001076083', relationType: 4034, objectInfo: { tagId: '1001076083', tagName: '综艺', resourceType: '2034' }, relationSort: 26 }, { contentId: '1000001827', relationType: 4034, objectInfo: { tagId: '1000001827', tagName: 'KTV', resourceType: '2034' }, relationSort: 23 }, { contentId: '1000001698', relationType: 4034, objectInfo: { tagId: '1000001698', tagName: '爱情', resourceType: '2034' }, relationSort: 22 }, { contentId: '1000001635', relationType: 4034, objectInfo: { tagId: '1000001635', tagName: '经典老歌', resourceType: '2034' }, relationSort: 21 }, { contentId: '1001076096', relationType: 4034, objectInfo: { tagId: '1001076096', tagName: '网络热歌', resourceType: '2034' }, relationSort: 20 }, { contentId: '1000001780', relationType: 4034, objectInfo: { tagId: '1000001780', tagName: '儿童歌曲', resourceType: '2034' }, relationSort: 19 }, { contentId: '1000587702', relationType: 4034, objectInfo: { tagId: '1000587702', tagName: '广场舞', resourceType: '2034' }, relationSort: 18 }, { contentId: '1000587717', relationType: 4034, objectInfo: { tagId: '1000587717', tagName: '70后', resourceType: '2034' }, relationSort: 17 }, { contentId: '1000587718', relationType: 4034, objectInfo: { tagId: '1000587718', tagName: '80后', resourceType: '2034' }, relationSort: 16 }, { contentId: '1000587726', relationType: 4034, objectInfo: { tagId: '1000587726', tagName: '90后', resourceType: '2034' }, relationSort: 15 }, { contentId: '1000001670', relationType: 4034, objectInfo: { tagId: '1000001670', tagName: '红歌', resourceType: '2034' }, relationSort: 14 }, { contentId: '1000587698', relationType: 4034, objectInfo: { tagId: '1000587698', tagName: '游戏', resourceType: '2034' }, relationSort: 13 }, { contentId: '1000587706', relationType: 4034, objectInfo: { tagId: '1000587706', tagName: '动漫', resourceType: '2034' }, relationSort: 12 }, { contentId: '1000001675', relationType: 4034, objectInfo: { tagId: '1000001675', tagName: '中国风', resourceType: '2034' }, relationSort: 11 }, { contentId: '1000587712', relationType: 4034, objectInfo: { tagId: '1000587712', tagName: '青春校园', resourceType: '2034' }, relationSort: 10 }, { contentId: '1000587673', relationType: 4034, objectInfo: { tagId: '1000587673', tagName: '小清新', resourceType: '2034' }, relationSort: 9 }, { contentId: '1000093902', relationType: 4034, objectInfo: { tagId: '1000093902', tagName: 'DJ舞曲', resourceType: '2034' }, relationSort: 7 }, { contentId: '1000093963', relationType: 4034, objectInfo: { tagId: '1000093963', tagName: '广告', resourceType: '2034' }, relationSort: 6 }, { contentId: '1000001831', relationType: 4034, objectInfo: { tagId: '1000001831', tagName: '翻唱', resourceType: '2034' }, relationSort: 2 }, { contentId: '1003449726', relationType: 4034, objectInfo: { tagId: '1003449726', tagName: '读书', resourceType: '2034' }, relationSort: 1 }], dataVersion: '1620410266055', customizedPicUrls: [] }, relationSort: 5 }, { contentId: '15244509', relationType: 2011, objectInfo: { columnTitle: '风格', columnId: '15244509', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 12, columnStatus: 1, columnCreateTime: '2016-11-10 10:54:57.257', columntype: 2011, contents: [{ contentId: '1000001672', relationType: 4034, objectInfo: { tagId: '1000001672', tagName: '流行', resourceType: '2034' }, relationSort: 14 }, { contentId: '1000001808', relationType: 4034, objectInfo: { tagId: '1000001808', tagName: 'R&B', resourceType: '2034' }, relationSort: 13 }, { contentId: '1000001809', relationType: 4034, objectInfo: { tagId: '1000001809', tagName: '嘻哈', resourceType: '2034' }, relationSort: 12 }, { contentId: '1000001674', relationType: 4034, objectInfo: { tagId: '1000001674', tagName: '摇滚', resourceType: '2034' }, relationSort: 11 }, { contentId: '1000001682', relationType: 4034, objectInfo: { tagId: '1000001682', tagName: '电子', resourceType: '2034' }, relationSort: 10 }, { contentId: '1000001852', relationType: 4034, objectInfo: { tagId: '1000001852', tagName: '电子舞曲', resourceType: '2034' }, relationSort: 9 }, { contentId: '1000001681', relationType: 4034, objectInfo: { tagId: '1000001681', tagName: '爵士', resourceType: '2034' }, relationSort: 6 }, { contentId: '1000001683', relationType: 4034, objectInfo: { tagId: '1000001683', tagName: '乡村', resourceType: '2034' }, relationSort: 5 }, { contentId: '1000001851', relationType: 4034, objectInfo: { tagId: '1000001851', tagName: '蓝调', resourceType: '2034' }, relationSort: 4 }, { contentId: '1000001775', relationType: 4034, objectInfo: { tagId: '1000001775', tagName: '民谣', resourceType: '2034' }, relationSort: 3 }, { contentId: '1000001807', relationType: 4034, objectInfo: { tagId: '1000001807', tagName: '纯音乐', resourceType: '2034' }, relationSort: 2 }, { contentId: '1000001783', relationType: 4034, objectInfo: { tagId: '1000001783', tagName: '古典', resourceType: '2034' }, relationSort: 1 }], dataVersion: '1620410266033', customizedPicUrls: [] }, relationSort: 4 }, { contentId: '18464665', relationType: 2011, objectInfo: { columnTitle: '语种', columnId: '18464665', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 6, columnStatus: 1, columnCreateTime: '2017-02-20 16:07:16.566', columntype: 2011, contents: [{ contentId: '1000001762', relationType: 4034, objectInfo: { tagId: '1000001762', tagName: '国语', resourceType: '2034' }, relationSort: 6 }, { contentId: '1000001763', relationType: 4034, objectInfo: { tagId: '1000001763', tagName: '粤语', resourceType: '2034' }, relationSort: 5 }, { contentId: '1000001766', relationType: 4034, objectInfo: { tagId: '1000001766', tagName: '英语', resourceType: '2034' }, relationSort: 4 }, { contentId: '1000001599', relationType: 4034, objectInfo: { tagId: '1000001599', tagName: '韩语', resourceType: '2034' }, relationSort: 3 }, { contentId: '1000001767', relationType: 4034, objectInfo: { tagId: '1000001767', tagName: '日语', resourceType: '2034' }, relationSort: 2 }, { contentId: '1003449724', relationType: 4034, objectInfo: { tagId: '1003449724', tagName: '小语种', resourceType: '2034' }, relationSort: 1 }], dataVersion: '1620410266036', customizedPicUrls: [] }, relationSort: 3 }, { contentId: '18464583', relationType: 2011, objectInfo: { columnTitle: '心情', columnId: '18464583', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 13, columnStatus: 1, columnCreateTime: '2017-02-20 15:59:03.412', columntype: 2011, contents: [{ contentId: '1000587677', relationType: 4034, objectInfo: { tagId: '1000587677', tagName: '幸福', resourceType: '2034' }, relationSort: 15 }, { contentId: '1000587710', relationType: 4034, objectInfo: { tagId: '1000587710', tagName: '治愈', resourceType: '2034' }, relationSort: 14 }, { contentId: '1000001703', relationType: 4034, objectInfo: { tagId: '1000001703', tagName: '思念', resourceType: '2034' }, relationSort: 13 }, { contentId: '1000587667', relationType: 4034, objectInfo: { tagId: '1000587667', tagName: '期待', resourceType: '2034' }, relationSort: 12 }, { contentId: '1000001700', relationType: 4034, objectInfo: { tagId: '1000001700', tagName: '励志', resourceType: '2034' }, relationSort: 11 }, { contentId: '1000001694', relationType: 4034, objectInfo: { tagId: '1000001694', tagName: '欢快', resourceType: '2034' }, relationSort: 10 }, { contentId: '1002600588', relationType: 4034, objectInfo: { tagId: '1002600588', tagName: '叛逆', resourceType: '2034' }, relationSort: 9 }, { contentId: '1002600585', relationType: 4034, objectInfo: { tagId: '1002600585', tagName: '宣泄', resourceType: '2034' }, relationSort: 8 }, { contentId: '1000001696', relationType: 4034, objectInfo: { tagId: '1000001696', tagName: '怀旧', resourceType: '2034' }, relationSort: 7 }, { contentId: '1000587679', relationType: 4034, objectInfo: { tagId: '1000587679', tagName: '减压', resourceType: '2034' }, relationSort: 6 }, { contentId: '1000001699', relationType: 4034, objectInfo: { tagId: '1000001699', tagName: '寂寞', resourceType: '2034' }, relationSort: 5 }, { contentId: '1002600579', relationType: 4034, objectInfo: { tagId: '1002600579', tagName: '忧郁', resourceType: '2034' }, relationSort: 4 }, { contentId: '1000001795', relationType: 4034, objectInfo: { tagId: '1000001795', tagName: '伤感', resourceType: '2034' }, relationSort: 3 }], dataVersion: '1620410266187', customizedPicUrls: [] }, relationSort: 2 }, { contentId: '18464638', relationType: 2011, objectInfo: { columnTitle: '场景', columnId: '18464638', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 13, columnStatus: 1, columnCreateTime: '2017-02-20 16:02:59.711', columntype: 2011, contents: [{ contentId: '1000587689', relationType: 4034, objectInfo: { tagId: '1000587689', tagName: '清晨', resourceType: '2034' }, relationSort: 21 }, { contentId: '1000587690', relationType: 4034, objectInfo: { tagId: '1000587690', tagName: '夜晚', resourceType: '2034' }, relationSort: 20 }, { contentId: '1000587688', relationType: 4034, objectInfo: { tagId: '1000587688', tagName: '睡前安眠', resourceType: '2034' }, relationSort: 19 }, { contentId: '1003449726', relationType: 4034, objectInfo: { tagId: '1003449726', tagName: '读书', resourceType: '2034' }, relationSort: 18 }, { contentId: '1003449723', relationType: 4034, objectInfo: { tagId: '1003449723', tagName: '下午·茶', resourceType: '2034' }, relationSort: 16 }, { contentId: '1000093923', relationType: 4034, objectInfo: { tagId: '1000093923', tagName: '驾车', resourceType: '2034' }, relationSort: 15 }, { contentId: '1003449615', relationType: 4034, objectInfo: { tagId: '1003449615', tagName: '运动', resourceType: '2034' }, relationSort: 13 }, { contentId: '1000587694', relationType: 4034, objectInfo: { tagId: '1000587694', tagName: '散步', resourceType: '2034' }, relationSort: 12 }, { contentId: '1000001749', relationType: 4034, objectInfo: { tagId: '1000001749', tagName: '旅行', resourceType: '2034' }, relationSort: 11 }, { contentId: '1000587686', relationType: 4034, objectInfo: { tagId: '1000587686', tagName: '夜店', resourceType: '2034' }, relationSort: 10 }, { contentId: '1002600606', relationType: 4034, objectInfo: { tagId: '1002600606', tagName: '派对', resourceType: '2034' }, relationSort: 9 }, { contentId: '1000001634', relationType: 4034, objectInfo: { tagId: '1000001634', tagName: '咖啡馆', resourceType: '2034' }, relationSort: 3 }, { contentId: '1000587692', relationType: 4034, objectInfo: { tagId: '1000587692', tagName: '瑜伽', resourceType: '2034' }, relationSort: 1 }], dataVersion: '1620846028994', customizedPicUrls: [] }, relationSort: 1 }], dataVersion: '1620846028941', customizedPicUrls: [] } } @@ -169,30 +169,30 @@ export default { let size switch (type.formatType) { case 'PQ': - size = sizeFormate(type.size) + size = sizeFormate(type.size ?? type.androidSize) types.push({ type: '128k', size }) _types['128k'] = { size, } break case 'HQ': - size = sizeFormate(type.size) + size = sizeFormate(type.size ?? type.androidSize) types.push({ type: '320k', size }) _types['320k'] = { size, } break case 'SQ': - size = sizeFormate(type.size) + size = sizeFormate(type.size ?? type.androidSize) types.push({ type: 'flac', size }) _types.flac = { size, } break case 'ZQ': - size = sizeFormate(type.size) - types.push({ type: 'flac32bit', size }) - _types.flac32bit = { + size = sizeFormate(type.size ?? type.androidSize) + types.push({ type: 'flac24bit', size }) + _types.flac24bit = { size, } break @@ -286,12 +286,13 @@ export default { // }) }, filterList(rawData) { + // console.log(rawData) return rawData.map(item => ({ play_count: this.formatPlayCount(item.playCount), id: item.playListId, author: item.createName, name: item.playListName, - time: item.createTime, + time: dateFormat(item.createTime, 'Y-M-D'), img: item.image, grade: item.grade, total: item.contentCount, @@ -362,6 +363,38 @@ export default { } return `https://music.migu.cn/v3/music/playlist/${id}` }, + + search(text, page, limit = 20) { + // return httpFetch(`http://search.kuwo.cn/r.s?all=${encodeURIComponent(text)}&pn=${page - 1}&rn=${limit}&rformat=json&encoding=utf8&ver=mbox&vipver=MUSIC_8.7.7.0_BCS37&plat=pc&devid=28156413&ft=playlist&pay=0&needliveshow=0`) + return httpFetch(`http://pd.musicapp.migu.cn/MIGUM2.0/v1.0/content/search_all.do?ua=Android_migu&version=5.0.1&text=${encodeURIComponent(text)}&pageNo=${page}&pageSize=${limit}&searchSwitch=%7B%22song%22%3A0%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A0%2C%22mvSong%22%3A0%2C%22bestShow%22%3A1%2C%22songlist%22%3A1%2C%22lyricSong%22%3A0%7D`, { + headers: { + 'User-Agent': 'okhttp/3.9.1', + osVersion: 'android 7.0', + }, + // family: 6, + }) + .promise.then(({ body }) => { + // console.log(body) + if (body.code != this.successCode) throw new Error('failed') + return { + list: body.songListResultData.result.map(item => { + return { + play_count: this.formatPlayCount(item.playcount), + id: item.id, + // author: item.createName, + name: item.name, + // time: item.createTime, + img: item.musicListPicUrl, + total: item.musicNum, + source: 'mg', + } + }), + limit, + total: parseInt(body.songListResultData.totalCount), + source: 'mg', + } + }) + }, } // getList diff --git a/src/utils/music/options.js b/src/utils/musicSdk/options.js similarity index 100% rename from src/utils/music/options.js rename to src/utils/musicSdk/options.js diff --git a/src/utils/music/tx/api-direct.js b/src/utils/musicSdk/tx/api-direct.js similarity index 100% rename from src/utils/music/tx/api-direct.js rename to src/utils/musicSdk/tx/api-direct.js diff --git a/src/utils/music/tx/api-test.js b/src/utils/musicSdk/tx/api-test.js similarity index 100% rename from src/utils/music/tx/api-test.js rename to src/utils/musicSdk/tx/api-test.js diff --git a/src/utils/music/tx/comment.js b/src/utils/musicSdk/tx/comment.js similarity index 100% rename from src/utils/music/tx/comment.js rename to src/utils/musicSdk/tx/comment.js diff --git a/src/utils/music/tx/hotSearch.js b/src/utils/musicSdk/tx/hotSearch.js similarity index 100% rename from src/utils/music/tx/hotSearch.js rename to src/utils/musicSdk/tx/hotSearch.js diff --git a/src/utils/music/tx/index.js b/src/utils/musicSdk/tx/index.js similarity index 100% rename from src/utils/music/tx/index.js rename to src/utils/musicSdk/tx/index.js diff --git a/src/utils/music/tx/leaderboard.js b/src/utils/musicSdk/tx/leaderboard.js similarity index 100% rename from src/utils/music/tx/leaderboard.js rename to src/utils/musicSdk/tx/leaderboard.js diff --git a/src/utils/music/tx/lyric.js b/src/utils/musicSdk/tx/lyric.js similarity index 100% rename from src/utils/music/tx/lyric.js rename to src/utils/musicSdk/tx/lyric.js diff --git a/src/utils/music/tx/musicInfo.js b/src/utils/musicSdk/tx/musicInfo.js similarity index 100% rename from src/utils/music/tx/musicInfo.js rename to src/utils/musicSdk/tx/musicInfo.js diff --git a/src/utils/music/tx/musicSearch.js b/src/utils/musicSdk/tx/musicSearch.js similarity index 99% rename from src/utils/music/tx/musicSearch.js rename to src/utils/musicSdk/tx/musicSearch.js index 15b7fbae8..044672e3b 100644 --- a/src/utils/music/tx/musicSearch.js +++ b/src/utils/musicSdk/tx/musicSearch.js @@ -118,7 +118,7 @@ export default { // console.log(list) return list }, - search(str, page = 1, { limit } = {}) { + search(str, page = 1, limit) { if (limit == null) limit = this.limit // http://newlyric.kuwo.cn/newlyric.lrc?62355680 return this.musicSearch(str, page, limit).then(({ body, meta }) => { diff --git a/src/utils/music/tx/songList.js b/src/utils/musicSdk/tx/songList.js similarity index 87% rename from src/utils/music/tx/songList.js rename to src/utils/musicSdk/tx/songList.js index d9a2a01f4..a73462dc8 100644 --- a/src/utils/music/tx/songList.js +++ b/src/utils/musicSdk/tx/songList.js @@ -1,5 +1,5 @@ import { httpFetch } from '../../request' -import { decodeName, formatPlayTime, sizeFormate } from '../../index' +import { decodeName, formatPlayTime, sizeFormate, dateFormat } from '../../index' export default { _requestObj_tags: null, @@ -120,6 +120,7 @@ export default { this._requestObj_list = httpFetch( this.getListUrl(sortId, tagId, page), ) + // console.log(this.getListUrl(sortId, tagId, page)) return this._requestObj_list.promise.then(({ body }) => { if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum) return tagId ? this.filterList2(body.playlist.data, page) : this.filterList(body.playlist.data, page) @@ -143,7 +144,7 @@ export default { id: item.tid, author: item.creator_info.nick, name: item.title, - // time: item.publish_time, + time: item.modify_time ? dateFormat(item.modify_time * 1000, 'Y-M-D') : '', img: item.cover_url_medium, // grade: item.favorcnt / 10, total: item.song_ids?.length, @@ -266,8 +267,8 @@ export default { } if (item.file.size_hires !== 0) { let size = sizeFormate(item.file.size_hires) - types.push({ type: 'flac32bit', size }) - _types.flac32bit = { + types.push({ type: 'flac24bit', size }) + _types.flac24bit = { size, } } @@ -303,6 +304,38 @@ export default { return `https://y.qq.com/n/ryqq/playlist/${id}` }, + + search(text, page, limit = 20) { + return httpFetch(`http://c.y.qq.com/soso/fcgi-bin/client_music_search_songlist?page_no=${page - 1}&num_per_page=${limit}&format=json&query=${encodeURIComponent(text)}&remoteplace=txt.yqq.playlist&inCharset=utf8&outCharset=utf-8`, { + headers: { + 'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)', + Referer: 'http://y.qq.com/portal/search.html', + }, + }) + .promise.then(({ body }) => { + if (body.code != 0) throw new Error('filed') + // console.log(body.data.list) + return { + list: body.data.list.map(item => { + return { + play_count: this.formatPlayCount(item.listennum), + id: item.dissid, + author: item.creator.name, + name: item.dissname, + time: dateFormat(item.createtime, 'Y-M-D'), + img: item.imgurl, + // grade: item.favorcnt / 10, + total: item.song_count, + desc: item.introduction, + source: 'tx', + } + }), + limit, + total: body.data.sum, + source: 'tx', + } + }) + }, } // getList diff --git a/src/utils/music/tx/tipSearch.js b/src/utils/musicSdk/tx/tipSearch.js similarity index 100% rename from src/utils/music/tx/tipSearch.js rename to src/utils/musicSdk/tx/tipSearch.js diff --git a/src/utils/music/utils.js b/src/utils/musicSdk/utils.js similarity index 90% rename from src/utils/music/utils.js rename to src/utils/musicSdk/utils.js index 84d42c440..ad83d1010 100644 --- a/src/utils/music/utils.js +++ b/src/utils/musicSdk/utils.js @@ -8,7 +8,7 @@ import crypto from 'crypto' const types = ['flac32bit', 'flac', 'wav', 'ape', '320k', '192k', '128k'] export const getMusicType = (info, type) => { - const list = global.globalObj.qualityList[info.source] + const list = global.lx.qualityList[info.source] if (!list) return '128k' if (!list.includes(type)) type = list[list.length - 1] const rangeType = types.slice(types.indexOf(type)) diff --git a/src/utils/music/wy/api-direct.js b/src/utils/musicSdk/wy/api-direct.js similarity index 100% rename from src/utils/music/wy/api-direct.js rename to src/utils/musicSdk/wy/api-direct.js diff --git a/src/utils/music/wy/api-test.js b/src/utils/musicSdk/wy/api-test.js similarity index 100% rename from src/utils/music/wy/api-test.js rename to src/utils/musicSdk/wy/api-test.js diff --git a/src/utils/music/wy/comment.js b/src/utils/musicSdk/wy/comment.js similarity index 100% rename from src/utils/music/wy/comment.js rename to src/utils/musicSdk/wy/comment.js diff --git a/src/utils/music/wy/hotSearch.js b/src/utils/musicSdk/wy/hotSearch.js similarity index 100% rename from src/utils/music/wy/hotSearch.js rename to src/utils/musicSdk/wy/hotSearch.js diff --git a/src/utils/music/wy/index.js b/src/utils/musicSdk/wy/index.js similarity index 100% rename from src/utils/music/wy/index.js rename to src/utils/musicSdk/wy/index.js diff --git a/src/utils/music/wy/leaderboard.js b/src/utils/musicSdk/wy/leaderboard.js similarity index 100% rename from src/utils/music/wy/leaderboard.js rename to src/utils/musicSdk/wy/leaderboard.js diff --git a/src/utils/music/wy/lyric.js b/src/utils/musicSdk/wy/lyric.js similarity index 100% rename from src/utils/music/wy/lyric.js rename to src/utils/musicSdk/wy/lyric.js diff --git a/src/utils/music/wy/musicDetail.js b/src/utils/musicSdk/wy/musicDetail.js similarity index 100% rename from src/utils/music/wy/musicDetail.js rename to src/utils/musicSdk/wy/musicDetail.js diff --git a/src/utils/music/wy/musicInfo.js b/src/utils/musicSdk/wy/musicInfo.js similarity index 100% rename from src/utils/music/wy/musicInfo.js rename to src/utils/musicSdk/wy/musicInfo.js diff --git a/src/utils/music/wy/musicSearch.js b/src/utils/musicSdk/wy/musicSearch.js similarity index 98% rename from src/utils/music/wy/musicSearch.js rename to src/utils/musicSdk/wy/musicSearch.js index 85e278bb9..1fccbb793 100644 --- a/src/utils/music/wy/musicSearch.js +++ b/src/utils/musicSdk/wy/musicSearch.js @@ -73,7 +73,7 @@ export default { } }) }, - search(str, page = 1, { limit } = {}, retryNum = 0) { + search(str, page = 1, limit, retryNum = 0) { if (++retryNum > 3) return Promise.reject(new Error('try max num')) if (limit == null) limit = this.limit return this.musicSearch(str, page, limit).then(result => { diff --git a/src/utils/music/wy/songList.js b/src/utils/musicSdk/wy/songList.js similarity index 92% rename from src/utils/music/wy/songList.js rename to src/utils/musicSdk/wy/songList.js index 642b0fe69..926b49750 100644 --- a/src/utils/music/wy/songList.js +++ b/src/utils/musicSdk/wy/songList.js @@ -5,8 +5,9 @@ import { weapi, linuxapi } from './utils/crypto' import { httpFetch } from '../../request' -import { formatPlayTime, sizeFormate } from '../../index' +import { formatPlayTime, sizeFormate, dateFormat } from '../../index' import musicDetailApi from './musicDetail' +import { eapiRequest } from './utils/index' export default { _requestObj_tags: null, @@ -43,7 +44,7 @@ export default { }, getSinger(singers) { let arr = [] - singers.forEach(singer => { + singers?.forEach(singer => { arr.push(singer.name) }) return arr.join('、') @@ -238,12 +239,13 @@ export default { }) }, filterList(rawData) { + // console.log(rawData) return rawData.map(item => ({ play_count: this.formatPlayCount(item.playCount), id: item.id, author: item.creator.nickname, name: item.name, - time: item.createTime, + time: item.createTime ? dateFormat(item.createTime, 'Y-M-D') : '', img: item.coverImgUrl, grade: item.grade, total: item.trackCount, @@ -320,6 +322,26 @@ export default { const { id } = await this.getListId(rawId) return `https://music.163.com/#/playlist?id=${id}` }, + + search(text, page, limit = 20) { + return eapiRequest('/api/cloudsearch/pc', { + s: text, + type: 1000, // 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频 + limit, + total: page == 1, + offset: limit * (page - 1), + }) + .promise.then(({ body }) => { + if (body.code != this.successCode) throw new Error('filed') + // console.log(body) + return { + list: this.filterList(body.result.playlists), + limit, + total: body.result.playlistCount, + source: 'wy', + } + }) + }, } // getList diff --git a/src/utils/music/wy/utils/crypto.js b/src/utils/musicSdk/wy/utils/crypto.js similarity index 97% rename from src/utils/music/wy/utils/crypto.js rename to src/utils/musicSdk/wy/utils/crypto.js index 64eac761d..ce365ddc6 100644 --- a/src/utils/music/wy/utils/crypto.js +++ b/src/utils/musicSdk/wy/utils/crypto.js @@ -19,7 +19,7 @@ const aesDecrypt = function(cipherBuffer, mode, key, iv) { const rsaEncrypt = (buffer, key) => { buffer = Buffer.concat([Buffer.alloc(128 - buffer.length), buffer]) - return publicEncrypt({ key: key, padding: 3 }, buffer) + return publicEncrypt({ key, padding: 3 }, buffer) } export const weapi = object => { diff --git a/src/utils/music/wy/utils/index.js b/src/utils/musicSdk/wy/utils/index.js similarity index 100% rename from src/utils/music/wy/utils/index.js rename to src/utils/musicSdk/wy/utils/index.js diff --git a/src/utils/music/xm.js b/src/utils/musicSdk/xm.js similarity index 100% rename from src/utils/music/xm.js rename to src/utils/musicSdk/xm.js diff --git a/src/utils/nativeModules/cache.ts b/src/utils/nativeModules/cache.ts new file mode 100644 index 000000000..985b8527f --- /dev/null +++ b/src/utils/nativeModules/cache.ts @@ -0,0 +1,6 @@ +import { NativeModules } from 'react-native' + +const { CacheModule } = NativeModules + +export const getAppCacheSize = async(): Promise<number> => CacheModule.getAppCacheSize().then((size: number) => Math.trunc(size)) +export const clearAppCache = CacheModule.clearAppCache as () => Promise<void> diff --git a/src/utils/gzip.js b/src/utils/nativeModules/gzip.ts similarity index 63% rename from src/utils/gzip.js rename to src/utils/nativeModules/gzip.ts index 72e9b0a30..07350e64d 100644 --- a/src/utils/gzip.js +++ b/src/utils/nativeModules/gzip.ts @@ -2,11 +2,11 @@ import { NativeModules } from 'react-native' const { GzipModule } = NativeModules -export const gzip = (sourceFilePath, targetFilePath) => { +export const gzip = (sourceFilePath: string, targetFilePath: string) => { console.log(sourceFilePath, targetFilePath) return GzipModule.gzip(sourceFilePath, targetFilePath, true) } -export const ungzip = (sourceFilePath, targetFilePath) => { +export const ungzip = (sourceFilePath: string, targetFilePath: string) => { return GzipModule.unGzip(sourceFilePath, targetFilePath, true) } diff --git a/src/utils/nativeModules/lyricDesktop.ts b/src/utils/nativeModules/lyricDesktop.ts new file mode 100644 index 000000000..d34ace50e --- /dev/null +++ b/src/utils/nativeModules/lyricDesktop.ts @@ -0,0 +1,242 @@ +import { NativeModules, NativeEventEmitter } from 'react-native' + +const { LyricModule } = NativeModules + +let isShowLyric = false + +// export const themes = [ +// { id: 'green', value: '#07c556' }, +// { id: 'yellow', value: '#fffa12' }, +// { id: 'blue', value: '#19b5fe' }, +// { id: 'red', value: '#ff1222' }, +// { id: 'pink', value: '#f1828d' }, +// { id: 'purple', value: '#c851d4' }, +// { id: 'orange', value: '#ffad12' }, +// { id: 'grey', value: '#bdc3c7' }, +// { id: 'black', value: '#333333' }, +// { id: 'white', value: '#ffffff' }, +// ] + +// export const textPositionX = [ +// { id: 'left', value: 'LEFT' }, +// { id: 'center', value: 'CENTER' }, +// { id: 'right', value: 'RIGHT' }, +// ] +// export const textPositionY = [ +// { id: 'top', value: 'TOP' }, +// { id: 'center', value: 'CENTER' }, +// { id: 'bottom', value: 'BOTTOM' }, +// ] + +// const getThemeColor = themeId => (themes.find(t => t.id == themeId) || themes[0]).value +// const getTextPositionX = x => (textPositionX.find(t => t.id == x) || textPositionX[0]).value +// const getTextPositionY = y => (textPositionY.find(t => t.id == y) || textPositionY[0]).value +const getAlpha = (num: number) => num / 100 +const getTextSize = (num: number) => num / 10 + + +/** + * show lyric + */ +export const showLyric = async({ + isShowToggleAnima, + isSingleLine, + width, + maxLineNum, + isLock, + unplayColor, + playedColor, + shadowColor, + opacity, + textSize, + positionX, + positionY, + textPositionX, + textPositionY, +}: { + isShowToggleAnima: boolean + isSingleLine: boolean + width: number + maxLineNum: number + isLock: boolean + unplayColor: string + playedColor: string + shadowColor: string + opacity: number + textSize: number + positionX: number + positionY: number + textPositionX: LX.AppSetting['desktopLyric.textPosition.x'] + textPositionY: LX.AppSetting['desktopLyric.textPosition.y'] +}): Promise<void> => { + if (isShowLyric) return Promise.resolve() + return LyricModule.showLyric({ + isSingleLine, + isShowToggleAnima, + isLock, + unplayColor, + playedColor, + shadowColor, + alpha: getAlpha(opacity), + textSize: getTextSize(textSize), + lyricViewX: positionX, + lyricViewY: positionY, + textX: textPositionX.toUpperCase(), + textY: textPositionY.toUpperCase(), + width, + maxLineNum, + }).then(() => { + isShowLyric = true + }) +} + +/** + * hide lyric + */ +export const hideLyric = async(): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.hideLyric().then(() => { + isShowLyric = false + }) +} + + +/** + * play lyric + * @param {Number} time play time + * @returns {Promise} Promise + */ +export const play = async(time: number): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.play(time) +} + +/** + * pause lyric + */ +export const pause = async(): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.pause() +} + +/** + * set lyric + * @param lyric lyric str + * @param translation lyric translation + * @param romalrc lyric translation + */ +export const setLyric = async(lyric: string, translation: string, romalrc: string): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.setLyric(lyric, translation || '', romalrc || '') +} + +/** + * toggle show translation + * @param isShowTranslation is show translation + */ +export const toggleTranslation = async(isShowTranslation: boolean): Promise<void> => { + // if (!isShowLyric) return Promise.resolve() + return LyricModule.toggleTranslation(isShowTranslation) +} + +/** + * toggle show roma lyric + * @param isShowRoma is show roma lyric + */ +export const toggleRoma = async(isShowRoma: boolean): Promise<void> => { + // if (!isShowLyric) return Promise.resolve() + return LyricModule.toggleRoma(isShowRoma) +} + +/** + * toggle is lock lyric window + * @param isLock is lock lyric window + */ +export const toggleLock = async(isLock: boolean): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.toggleLock(isLock) +} + +/** + * set color + * @param unplayColor + * @param playedColor + * @param shadowColor + */ +export const setColor = async(unplayColor: string, playedColor: string, shadowColor: string): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.setColor(unplayColor, playedColor, shadowColor) +} + +/** + * set text alpha + * @param alpha text alpha + */ +export const setAlpha = async(alpha: number): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.setAlpha(getAlpha(alpha)) +} + +/** + * set text size + * @param size text size + */ +export const setTextSize = async(size: any): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.setTextSize(getTextSize(size)) +} + +export const setShowToggleAnima = async(isShowToggleAnima: boolean): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.setShowToggleAnima(isShowToggleAnima) +} + +export const setSingleLine = async(isSingleLine: boolean): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.setSingleLine(isSingleLine) +} + +export const setPosition = async(x: number, y: number): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.setPosition(x, y) +} + +export const setMaxLineNum = async(maxLineNum: number): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.setMaxLineNum(maxLineNum) +} + +export const setWidth = async(width: number): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.setWidth(width) +} + +// export const fixViewPosition = async(): Promise<void> => { +// if (!isShowLyric) return Promise.resolve() +// return LyricModule.fixViewPosition() +// } + +export const setLyricTextPosition = async(textX: LX.AppSetting['desktopLyric.textPosition.x'], textY: LX.AppSetting['desktopLyric.textPosition.y']): Promise<void> => { + if (!isShowLyric) return Promise.resolve() + return LyricModule.setLyricTextPosition(textX.toUpperCase(), textY.toUpperCase()) +} + +export const checkOverlayPermission = async(): Promise<void> => { + return LyricModule.checkOverlayPermission() +} + +export const openOverlayPermissionActivity = async(): Promise<void> => { + return LyricModule.openOverlayPermissionActivity() +} + +export const onPositionChange = (callback: (position: { x: number, y: number }) => void): () => void => { + const eventEmitter = new NativeEventEmitter(LyricModule) + const eventListener = eventEmitter.addListener('set-position', event => { + callback(event) + }) + + return () => { + eventListener.remove() + } +} + diff --git a/src/utils/nativeModules/utils.ts b/src/utils/nativeModules/utils.ts new file mode 100644 index 000000000..7149cbaae --- /dev/null +++ b/src/utils/nativeModules/utils.ts @@ -0,0 +1,36 @@ +import { NativeModules } from 'react-native' + +const { UtilsModule } = NativeModules + +export const exitApp = UtilsModule.exitApp + +export const getSupportedAbis = UtilsModule.getSupportedAbis + +export const installApk = (filePath: string, fileProviderAuthority: string) => UtilsModule.installApk(filePath, fileProviderAuthority) + + +export const screenkeepAwake = () => { + if (global.lx.isScreenKeepAwake) return + global.lx.isScreenKeepAwake = true + UtilsModule.screenkeepAwake() +} +export const screenUnkeepAwake = () => { + // console.log('screenUnkeepAwake') + if (!global.lx.isScreenKeepAwake) return + global.lx.isScreenKeepAwake = false + UtilsModule.screenUnkeepAwake() +} + +export const getWIFIIPV4Address = UtilsModule.getWIFIIPV4Address as () => Promise<string> + +export const getDeviceName = async(): Promise<string> => { + return UtilsModule.getDeviceName().then((deviceName: string) => deviceName || 'Unknown') +} + +export const isNotificationsEnabled = UtilsModule.isNotificationsEnabled as () => Promise<boolean> + +export const openNotificationPermissionActivity = UtilsModule.openNotificationPermissionActivity as () => Promise<void> + +export const shareText = async(shareTitle: string, title: string, text: string): Promise<void> => { + UtilsModule.shareText(shareTitle, title, text) +} diff --git a/src/utils/permissions.js b/src/utils/permissions.js deleted file mode 100644 index d271aea21..000000000 --- a/src/utils/permissions.js +++ /dev/null @@ -1,44 +0,0 @@ -import { PermissionsAndroid } from 'react-native' - - -export const checkStoragePermissions = () => PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE) - -export const requestStoragePermission = async() => { - const isGranted = await checkStoragePermissions() - if (isGranted) return isGranted - - try { - const granted = await PermissionsAndroid.requestMultiple( - [ - PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, - PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, - ], - // { - // title: '存储读写权限申请', - // message: - // '洛雪音乐助手需要使用存储读写权限才能下载歌曲.', - // buttonNeutral: '一会再问我', - // buttonNegative: '取消', - // buttonPositive: '确定', - // }, - ) - // console.log(granted) - // console.log(Object.values(granted).every(r => r === PermissionsAndroid.RESULTS.GRANTED)) - // console.log(PermissionsAndroid.RESULTS) - const granteds = Object.values(granted) - return granteds.every(r => r === PermissionsAndroid.RESULTS.GRANTED) - ? true - : granteds.includes(PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) - ? null - : false - // if (granted === PermissionsAndroid.RESULTS.GRANTED) { - // console.log('You can use the storage') - // } else { - // console.log('Storage permission denied') - // } - } catch (err) { - console.warn(err) - return err.message - } -} - diff --git a/src/utils/pixelRatio.ts b/src/utils/pixelRatio.ts new file mode 100644 index 000000000..1c630f618 --- /dev/null +++ b/src/utils/pixelRatio.ts @@ -0,0 +1,78 @@ +/** + * Created by qianxin on 17/6/1. + * 屏幕工具类 + * ui设计基准,iphone 6 + * width:375 + * height:667 + */ +import { Dimensions, PixelRatio } from 'react-native' + +// 高保真的宽度和高度 +const designWidth = 375.0 +const designHeight = 667.0 + +// 获取屏幕的dp +let screenW = Dimensions.get('window').width +let screenH = Dimensions.get('window').height +if (screenW > screenH) { + const temp = screenW + screenW = screenH + screenH = temp +} +let fontScale = PixelRatio.getFontScale() +let pixelRatio = PixelRatio.get() +// 根据dp获取屏幕的px +let screenPxW = PixelRatio.getPixelSizeForLayoutSize(screenW) +let screenPxH = PixelRatio.getPixelSizeForLayoutSize(screenH) +// console.log(screenPxW, screenPxH) + +const scaleW = screenPxW / designWidth +const scaleH = screenPxH / designHeight +const scale = Math.min(scaleW, scaleH, 3.1) +// console.log(scale) + +/** + * 设置text + * @param size px + * @returns dp + */ +export function getTextSize(size: number) { + // console.log('screenW======' + screenW) + // console.log('screenPxW======' + screenPxW) + let scaleWidth = screenW / designWidth + let scaleHeight = screenH / designHeight + // console.log(scaleWidth, scaleHeight) + let scale = Math.min(scaleWidth, scaleHeight, 1.3) + size = Math.floor(size * scale / fontScale) + // console.log(size) + return size +} +export function setSpText(size: number) { + return getTextSize(size) * global.lx.fontSize +} + +/** + * 设置高度 + * @param size px + * @returns dp + */ +export function scaleSizeH(size: number) { + // console.log(screenPxH / designHeight) + // let scaleHeight = size * Math.min(screenPxH / designHeight, 3.1) + let scaleHeight = size * scale + size = Math.floor(scaleHeight / pixelRatio) + return size * global.lx.fontSize +} + +/** + * 设置宽度 + * @param size px + * @returns dp + */ +export function scaleSizeW(size: number) { + // console.log(screenPxW / designWidth) + // let scaleWidth = size * Math.min(screenPxW / designWidth, 3.1) + let scaleWidth = size * scale + size = Math.floor(scaleWidth / pixelRatio) + return size * global.lx.fontSize +} diff --git a/src/utils/request.js b/src/utils/request.js index 0555d13c5..5ae7ae42d 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -1,9 +1,8 @@ // import needle from 'needle' // import progress from 'request-progress' import BackgroundTimer from 'react-native-background-timer' -import { debugRequest } from './env' import { requestMsg } from './message' -import { bHh } from './music/options' +import { bHh } from './musicSdk/options' import { deflateRaw } from 'pako' const defaultHeaders = { @@ -56,7 +55,7 @@ export const httpGet = (url, options, callback) => { requestObj.request.then(resp => { callback(null, resp, resp.body) }).catch(err => { - debugRequest && console.log(JSON.stringify(err)) + // debugRequest && console.log(JSON.stringify(err)) callback(err, null, null) }) @@ -158,16 +157,16 @@ const fetchData = (url, { timeout = 15000, ...options }) => { console.log('---start---', url) const controller = new global.AbortController() - const id = BackgroundTimer.setTimeout(() => controller.abort(), timeout) + let id = BackgroundTimer.setTimeout(() => { + id = null + controller.abort() + }, timeout) return { request: handleRequestData(url, options).then(options => { return global.fetch(url, { ...options, signal: controller.signal, - }).then(response => { - BackgroundTimer.clearTimeout(id) - return response }).then(resp => resp.text().then(text => { // console.log(options, headers, text) return { @@ -186,6 +185,9 @@ const fetchData = (url, { timeout = 15000, ...options }) => { }).catch(err => { // console.log(err, err.code, err.message) return Promise.reject(err) + }).finally(() => { + if (id == null) return + BackgroundTimer.clearTimeout(id) }) }), abort() { diff --git a/src/utils/tools.js b/src/utils/tools.js deleted file mode 100644 index a2cef4143..000000000 --- a/src/utils/tools.js +++ /dev/null @@ -1,446 +0,0 @@ -import { Platform, NativeModules, ToastAndroid, BackHandler, Linking, Dimensions, Alert, Appearance } from 'react-native' -// import ExtraDimensions from 'react-native-extra-dimensions-android' -import Clipboard from '@react-native-clipboard/clipboard' -import { getData, setData, getAllKeys, removeData, removeDataMultiple, setDataMultiple, getDataMultiple } from '@/plugins/storage' -import { storageDataPrefix } from '@/config' -import { throttle } from './index' -import { gzip, ungzip } from '@/utils/gzip' -import { readFile, writeFile, temporaryDirectoryPath, unlink } from '@/utils/fs' -import { isNotificationsEnabled, openNotificationPermissionActivity, shareText } from '@/utils/utils' -import { i18n } from '@/plugins/i18n' -import music from '@/utils/music' - -const playInfoStorageKey = storageDataPrefix.playInfo -const listPositionPrefix = storageDataPrefix.listPosition -const syncAuthKeyPrefix = storageDataPrefix.syncAuthKey -const syncHostPrefix = storageDataPrefix.syncHost -const syncHostHistoryPrefix = storageDataPrefix.syncHostHistory -const listPrefix = storageDataPrefix.list -const listSortPrefix = storageDataPrefix.listSort -const defaultListKey = listPrefix + 'default' -const loveListKey = listPrefix + 'love' -const notificationTipEnableKey = storageDataPrefix.notificationTipEnable - - -// https://stackoverflow.com/a/47349998 -let deviceLanguage = Platform.OS === 'ios' - ? NativeModules.SettingsManager.settings.AppleLocale || - NativeModules.SettingsManager.settings.AppleLanguages[0] // iOS 13 - : NativeModules.I18nManager.localeIdentifier -deviceLanguage = typeof deviceLanguage === 'string' ? deviceLanguage.substring(0, 5).toLocaleLowerCase() : '' - -export const isAndroid = Platform.OS === 'android' -export const osVer = Platform.constants.Release - -const handleSaveListScrollPosition = throttle(data => { - setData(listPositionPrefix, data) -}, 1000) - - -// fix https://github.com/facebook/react-native/issues/4934 -export const getWindowSise = windowDimensions => { - if (!windowDimensions) windowDimensions = Dimensions.get('window') - // if (Platform.OS === 'ios') return windowDimensions - return windowDimensions - // const windowSize = { - // width: ExtraDimensions.getRealWindowWidth(), - // height: ExtraDimensions.getRealWindowHeight(), - // } - // if ( - // (windowDimensions.height > windowDimensions.width && windowSize.height < windowSize.width) || - // (windowDimensions.width > windowDimensions.height && windowSize.width < windowSize.height) - // ) { - // windowSize.height = windowSize.width - // } - // windowSize.width = windowDimensions.width - - // if (ExtraDimensions.isSoftMenuBarEnabled()) { - // windowSize.height -= ExtraDimensions.getSoftMenuBarHeight() - // } - // return windowSize -} - - -/** - * 显示toast - * @param {String} message 消息 - * @param {String} duration 时长,可用值:long、short - * @param {String} position 位置,可用值:top、center、bottom - */ -export const toast = (message, duration = 'short', position = 'bottom') => { - switch (duration) { - case 'long': - duration = ToastAndroid.LONG - break - case 'short': - default: - duration = ToastAndroid.SHORT - break - } - switch (position) { - case 'top': - position = ToastAndroid.TOP - break - case 'center': - position = ToastAndroid.CENTER - break - case 'bottom': - default: - position = ToastAndroid.BOTTOM - break - } - ToastAndroid.show(message, duration, position) -} - -export const openUrl = url => Linking.canOpenURL(url).then(() => Linking.openURL(url)) - -export const assertApiSupport = source => global.globalObj.qualityList[source] != undefined - -// const handleRemoveDataMultiple = async keys => { -// await removeDataMultiple(keys.splice(0, 500)) -// if (keys.length) return handleRemoveDataMultiple(keys) -// } - - -export const getAllListData = async() => { - let defaultList - let loveList - let userList = [] - let keys = await getAllKeys() - const listKeys = [] - for (const key of keys) { - if (key.startsWith(listPrefix)) { - listKeys.push(key) - } - } - const listData = await getDataMultiple(listKeys) - for (const { key, value } of listData) { - switch (key) { - case defaultListKey: - defaultList = value - break - case loveListKey: - loveList = value - break - default: - userList.push(value) - break - } - } - const listPositionData = await getData(listPositionPrefix) || {} - const listPosition = {} - for (const [key, value] of Object.entries(listPositionData)) { - listPosition[key] = value - } - const listSortData = await getData(listSortPrefix) || {} - return { - defaultList, - loveList, - userList, - listPosition, - listSort: listSortData, - } -} - -export const saveList = async listData => { - if (Array.isArray(listData)) { - await setDataMultiple(listData.map(list => ({ key: listPrefix + list.id, value: list }))) - } else { - await setData(listPrefix + listData.id, listData) - } -} -export const removeList = async listId => { - if (Array.isArray(listId)) { - await removeDataMultiple(listId.map(id => { - delete global.listScrollPosition[id] - delete global.listSort[id] - return listPrefix + id - })) - } else { - await removeData(listPrefix + listId) - } - await setData(listSortPrefix, global.listSort) - handleSaveListScrollPosition(global.listScrollPosition) -} - - -export const saveListAllSort = async listSort => { - global.listSort = listSort - await setData(listSortPrefix, listSort) -} -export const saveListSort = (listId, index) => { - global.listSort[listId] = index - setData(listSortPrefix, global.listSort) -} -export const removeListSort = async listIds => { - for (const id of listIds) { - delete global.listSort[id] - } - setData(listSortPrefix, global.listSort) -} - -export const getMusicUrl = (musicInfo, type) => getData(`${storageDataPrefix.musicUrl}${musicInfo.source}_${musicInfo.songmid}_${type}`).then(url => url || '') -export const saveMusicUrl = (musicInfo, type, url) => setData(`${storageDataPrefix.musicUrl}${musicInfo.source}_${musicInfo.songmid}_${type}`, url) -export const clearMusicUrl = async() => { - let keys = (await getAllKeys()).filter(key => key.startsWith(storageDataPrefix.musicUrl)) - await removeDataMultiple(keys) -} - -export const getLyric = musicInfo => getData(`${storageDataPrefix.lyric}${musicInfo.source}_${musicInfo.songmid}`).then(lrcInfo => lrcInfo || {}) -export const saveLyric = (musicInfo, { lyric, tlyric, rlyric, lxlyric }) => setData(`${storageDataPrefix.lyric}${musicInfo.source}_${musicInfo.songmid}`, { lyric, tlyric, rlyric, lxlyric }) -export const clearLyric = async() => { - let keys = (await getAllKeys()).filter(key => key.startsWith(storageDataPrefix.lyric)) - await removeDataMultiple(keys) -} - -export const clearMusicUrlAndLyric = async() => { - let keys = (await getAllKeys()).filter(key => key.startsWith(storageDataPrefix.musicUrl) || key.startsWith(storageDataPrefix.lyric)) - await removeDataMultiple(keys) -} - -export const delaySavePlayInfo = throttle(n => { - setData(playInfoStorageKey, n) -}, 2000) -export const savePlayInfo = (info, isDelay) => { - isDelay - ? delaySavePlayInfo(info) - : setData(playInfoStorageKey, info) -} -export const getPlayInfo = () => getData(playInfoStorageKey) - - -export const saveListScrollPosition = (listId, position) => { - global.listScrollPosition[listId] = position - handleSaveListScrollPosition(global.listScrollPosition) -} -export const getListScrollPosition = listId => { - return global.listScrollPosition[listId] || 0 -} -export const removeListScrollPosition = async listIds => { - for (const id of listIds) { - delete global.listScrollPosition[id] - } - handleSaveListScrollPosition(global.listScrollPosition) -} - -export const getSyncAuthKey = async serverId => { - const keys = await getData(syncAuthKeyPrefix) - if (!keys) return null - return keys[serverId] || null -} - -export const setSyncAuthKey = async(serverId, key) => { - let keys = await getData(syncAuthKeyPrefix) || {} - keys[serverId] = key - await setData(syncAuthKeyPrefix, keys) -} - -let syncHostInfo -export const getSyncHost = async() => { - if (syncHostInfo === undefined) { - syncHostInfo = await getData(syncHostPrefix) || { host: '', port: '23332' } - } - return { ...syncHostInfo } -} -export const setSyncHost = async({ host, port }) => { - // let hostInfo = await getData(syncHostPrefix) || {} - // hostInfo.host = host - // hostInfo.port = port - syncHostInfo.host = host - syncHostInfo.port = port - await setData(syncHostPrefix, syncHostInfo) -} -let syncHostHistory -export const getSyncHostHistory = async() => { - if (syncHostHistory === undefined) { - syncHostHistory = await getData(syncHostHistoryPrefix) || [] - } - return syncHostHistory -} -export const addSyncHostHistory = async(host, port) => { - let syncHostHistory = await getSyncHostHistory() - if (syncHostHistory.some(h => h.host == host && h.port == port)) return - syncHostHistory.unshift({ host, port }) - if (syncHostHistory.length > 20) syncHostHistory = syncHostHistory.slice(0, 20) // 最多存储20个 - await setData(syncHostHistoryPrefix, syncHostHistory) -} -export const removeSyncHostHistory = async index => { - syncHostHistory.splice(index, 1) - await setData(syncHostHistoryPrefix, syncHostHistory) -} - -export const exitApp = BackHandler.exitApp - -export const handleSaveFile = async(path, data) => { - // if (!path.endsWith('.json')) path += '.json' - // const buffer = gzip(data) - const tempFilePath = `${temporaryDirectoryPath}/tempFile.json` - await writeFile(tempFilePath, JSON.stringify(data), 'utf8') - await gzip(tempFilePath, path) - await unlink(tempFilePath) -} -export const handleReadFile = async(path) => { - let isJSON = path.endsWith('.json') - let data - if (isJSON) { - data = await readFile(path, 'utf8') - } else { - const tempFilePath = `${temporaryDirectoryPath}/tempFile.json` - await ungzip(path, tempFilePath) - data = await readFile(tempFilePath, 'utf8') - await unlink(tempFilePath) - } - return JSON.parse(data) -} - -export const confirmDialog = ({ - message = '', - cancelButtonText = global.i18n.t('dialog_cancel'), - confirmButtonText = global.i18n.t('dialog_confirm'), - bgClose = true, -}) => { - return new Promise(resolve => { - Alert.alert(null, message, [ - { - text: cancelButtonText, - onPress() { - resolve(false) - }, - }, - { - text: confirmButtonText, - onPress() { - resolve(true) - }, - }, - ], { - cancelable: bgClose, - onDismiss() { - resolve(false) - }, - }) - }) -} - -export const clipboardWriteText = str => { - Clipboard.setString(str) -} - -export const checkNotificationPermission = async() => { - const isHide = await getData(notificationTipEnableKey) - if (isHide != null) return - const enabled = await isNotificationsEnabled() - if (enabled) return - Alert.alert( - i18n.t('notifications_check_title'), - i18n.t('notifications_check_tip'), - [ - { - text: i18n.t('never_show'), - onPress: () => { - setData(notificationTipEnableKey, '1') - toast(i18n.t('disagree_tip')) - }, - }, - { - text: i18n.t('disagree'), - onPress: () => { - toast(i18n.t('disagree_tip')) - }, - }, - { - text: i18n.t('agree_go'), - onPress: () => { - openNotificationPermissionActivity() - }, - }, - ], - ) -} -export const resetNotificationPermissionCheck = () => { - return removeData(notificationTipEnableKey) -} - -export const shareMusic = (shareType, downloadFileName, musicInfo) => { - const name = musicInfo.name - const singer = musicInfo.singer - const detailUrl = music[musicInfo.source]?.getMusicDetailPageUrl(musicInfo) ?? '' - const musicTitle = downloadFileName.replace('歌名', name).replace('歌手', singer) - switch (shareType) { - case 'system': - shareText(i18n.t('share_card_title_music', { name }), i18n.t('share_title_music'), `${musicTitle.replace(/\s/g, '')} \n${detailUrl}`) - break - case 'clipboard': - clipboardWriteText(`${musicTitle} ${detailUrl}`) - toast(i18n.t('copy_name_tip')) - break - } -} - -export const getAppearance = () => { - return Appearance.getColorScheme() -} - -export const onAppearanceChange = callback => { - return Appearance.addChangeListener(({ colorScheme }) => { - callback(colorScheme) - }) -} - -let isSupportedAutoTheme = null -export const getIsSupportedAutoTheme = () => { - if (isSupportedAutoTheme == null) { - const osVerNum = parseInt(osVer) - isSupportedAutoTheme = isAndroid - ? osVerNum >= 10 - : osVerNum >= 13 - } - return isSupportedAutoTheme -} - - -export const deduplicationList = list => { - const ids = new Set() - return list.filter(s => { - if (ids.has(s.songmid)) return false - ids.add(s.songmid) - return true - }) -} - -export const showImportTip = type => { - let message - switch (type) { - case 'defautlList': - case 'playList': - message = i18n.t('list_import_tip__playlist') - break - case 'setting': - message = i18n.t('list_import_tip__setting') - break - case 'allData': - message = i18n.t('list_import_tip__alldata') - break - case 'playListPart': - message = i18n.t('list_import_tip__playlist_part') - break - - default: - message = i18n.t('list_import_tip__unknown') - break - } - Alert.alert( - i18n.t('list_import_tip__failed'), - message, - [ - { - text: i18n.t('ok'), - }, - ], - ) -} - - -export { - deviceLanguage, -} diff --git a/src/utils/tools.ts b/src/utils/tools.ts new file mode 100644 index 000000000..e497270d2 --- /dev/null +++ b/src/utils/tools.ts @@ -0,0 +1,421 @@ +import { Platform, NativeModules, ToastAndroid, BackHandler, Linking, Dimensions, Alert, Appearance, PermissionsAndroid, AppState, StyleSheet, type ScaledSize } from 'react-native' +// import ExtraDimensions from 'react-native-extra-dimensions-android' +import Clipboard from '@react-native-clipboard/clipboard' +import { storageDataPrefix } from '@/config/constant' +import { gzip, ungzip } from '@/utils/nativeModules/gzip' +import { readFile, writeFile, temporaryDirectoryPath, unlink } from '@/utils/fs' +import { isNotificationsEnabled, openNotificationPermissionActivity, shareText } from '@/utils/nativeModules/utils' +import musicSdk from '@/utils/musicSdk' +import { getData, removeData, saveData } from '@/plugins/storage' +import BackgroundTimer from 'react-native-background-timer' +import { scaleSizeH, scaleSizeW, setSpText } from './pixelRatio' + + +// https://stackoverflow.com/a/47349998 +let deviceLanguage = Platform.OS === 'ios' + ? NativeModules.SettingsManager.settings.AppleLocale || + NativeModules.SettingsManager.settings.AppleLanguages[0] // iOS 13 + : NativeModules.I18nManager.localeIdentifier +deviceLanguage = typeof deviceLanguage === 'string' ? deviceLanguage.substring(0, 5).toLocaleLowerCase() : '' + +export const isAndroid = Platform.OS === 'android' +// @ts-expect-error +export const osVer = Platform.constants.Release as string + +export const isActive = () => AppState.currentState == 'active' + + +// fix https://github.com/facebook/react-native/issues/4934 +export const getWindowSise = (windowDimensions?: ReturnType<(typeof Dimensions)['get']>) => { + windowDimensions ??= Dimensions.get('window') + // if (Platform.OS === 'ios') return windowDimensions + return windowDimensions + // const windowSize = { + // width: ExtraDimensions.getRealWindowWidth(), + // height: ExtraDimensions.getRealWindowHeight(), + // } + // if ( + // (windowDimensions.height > windowDimensions.width && windowSize.height < windowSize.width) || + // (windowDimensions.width > windowDimensions.height && windowSize.width < windowSize.height) + // ) { + // windowSize.height = windowSize.width + // } + // windowSize.width = windowDimensions.width + + // if (ExtraDimensions.isSoftMenuBarEnabled()) { + // windowSize.height -= ExtraDimensions.getSoftMenuBarHeight() + // } + // return windowSize +} + +export const checkStoragePermissions = async() => PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE) + +export const requestStoragePermission = async() => { + const isGranted = await checkStoragePermissions() + if (isGranted) return isGranted + + try { + const granted = await PermissionsAndroid.requestMultiple( + [ + PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, + PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, + ], + // { + // title: '存储读写权限申请', + // message: + // '洛雪音乐助手需要使用存储读写权限才能下载歌曲.', + // buttonNeutral: '一会再问我', + // buttonNegative: '取消', + // buttonPositive: '确定', + // }, + ) + // console.log(granted) + // console.log(Object.values(granted).every(r => r === PermissionsAndroid.RESULTS.GRANTED)) + // console.log(PermissionsAndroid.RESULTS) + const granteds = Object.values(granted) + return granteds.every(r => r === PermissionsAndroid.RESULTS.GRANTED) + ? true + : granteds.includes(PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) + ? null + : false + // if (granted === PermissionsAndroid.RESULTS.GRANTED) { + // console.log('You can use the storage') + // } else { + // console.log('Storage permission denied') + // } + } catch (err: any) { + // console.warn(err) + return false + } +} + + +/** + * 显示toast + * @param message 消息 + * @param duration 时长 + * @param position 位置 + */ +export const toast = (message: string, duration: 'long' | 'short' = 'short', position: 'top' | 'center' | 'bottom' = 'bottom') => { + let _duration + switch (duration) { + case 'long': + _duration = ToastAndroid.LONG + break + case 'short': + default: + _duration = ToastAndroid.SHORT + break + } + let _position + switch (position) { + case 'top': + _position = ToastAndroid.TOP + break + case 'center': + _position = ToastAndroid.CENTER + break + case 'bottom': + default: + _position = ToastAndroid.BOTTOM + break + } + ToastAndroid.showWithGravity(message, _duration, _position) +} + +export const openUrl = async(url: string): Promise<void> => Linking.canOpenURL(url).then(async() => Linking.openURL(url)) + +export const assertApiSupport = (source: LX.Source): boolean => { + return source == 'local' || global.lx.qualityList[source] != null +} + +// const handleRemoveDataMultiple = async keys => { +// await removeDataMultiple(keys.splice(0, 500)) +// if (keys.length) return handleRemoveDataMultiple(keys) +// } + +export const exitApp = BackHandler.exitApp + +export const handleSaveFile = async(path: string, data: any) => { + // if (!path.endsWith('.json')) path += '.json' + // const buffer = gzip(data) + const tempFilePath = `${temporaryDirectoryPath}/tempFile.json` + await writeFile(tempFilePath, JSON.stringify(data), 'utf8') + await gzip(tempFilePath, path) + await unlink(tempFilePath) +} +export const handleReadFile = async<T = unknown>(path: string): Promise<T> => { + let isJSON = path.endsWith('.json') + let data + if (isJSON) { + data = await readFile(path, 'utf8') + } else { + const tempFilePath = `${temporaryDirectoryPath}/tempFile.json` + await ungzip(path, tempFilePath) + data = await readFile(tempFilePath, 'utf8') + await unlink(tempFilePath) + } + return JSON.parse(data) +} + +export const confirmDialog = async({ + message = '', + cancelButtonText = global.i18n.t('dialog_cancel'), + confirmButtonText = global.i18n.t('dialog_confirm'), + bgClose = true, +}) => { + return new Promise(resolve => { + Alert.alert('', message, [ + { + text: cancelButtonText, + onPress() { + resolve(false) + }, + }, + { + text: confirmButtonText, + onPress() { + resolve(true) + }, + }, + ], { + cancelable: bgClose, + onDismiss() { + resolve(false) + }, + }) + }) +} + +export const clipboardWriteText = (str: string) => { + Clipboard.setString(str) +} + + +export const checkNotificationPermission = async() => { + const isHide = await getData(storageDataPrefix.notificationTipEnable) + if (isHide != null) return + const enabled = await isNotificationsEnabled() + if (enabled) return + Alert.alert( + global.i18n.t('notifications_check_title'), + global.i18n.t('notifications_check_tip'), + [ + { + text: global.i18n.t('never_show'), + onPress: () => { + void saveData(storageDataPrefix.notificationTipEnable, '1') + toast(global.i18n.t('disagree_tip')) + }, + }, + { + text: global.i18n.t('disagree'), + onPress: () => { + toast(global.i18n.t('disagree_tip')) + }, + }, + { + text: global.i18n.t('agree_go'), + onPress: () => { + void openNotificationPermissionActivity() + }, + }, + ], + ) +} +export const resetNotificationPermissionCheck = async() => { + return removeData(storageDataPrefix.notificationTipEnable) +} + +export const shareMusic = (shareType: LX.ShareType, downloadFileName: LX.AppSetting['download.fileName'], musicInfo: LX.Music.MusicInfo) => { + const name = musicInfo.name + const singer = musicInfo.singer + const detailUrl = musicInfo.source == 'local' ? '' : musicSdk[musicInfo.source]?.getMusicDetailPageUrl(musicInfo) ?? '' + const musicTitle = downloadFileName.replace('歌名', name).replace('歌手', singer) + switch (shareType) { + case 'system': + void shareText(global.i18n.t('share_card_title_music', { name }), global.i18n.t('share_title_music'), `${musicTitle.replace(/\s/g, '')}${detailUrl ? '\n' + detailUrl : ''}`) + break + case 'clipboard': + clipboardWriteText(`${musicTitle}${detailUrl ? '\n' + detailUrl : ''}`) + toast(global.i18n.t('copy_name_tip')) + break + } +} + +export const onDimensionChange = (handler: (info: { window: ScaledSize, screen: ScaledSize }) => void) => { + return Dimensions.addEventListener('change', handler) +} + + +export const getAppearance = () => { + return Appearance.getColorScheme() ?? 'light' +} + +export const onAppearanceChange = (callback: (colorScheme: Parameters<Parameters<typeof Appearance['addChangeListener']>[0]>[0]['colorScheme']) => void) => { + return Appearance.addChangeListener(({ colorScheme }) => { + callback(colorScheme) + }) +} + +let isSupportedAutoTheme: boolean | null = null +export const getIsSupportedAutoTheme = () => { + if (isSupportedAutoTheme == null) { + const osVerNum = parseInt(osVer) + isSupportedAutoTheme = isAndroid + ? osVerNum >= 10 + : osVerNum >= 13 + } + return isSupportedAutoTheme +} + + +export const showImportTip = (type: string) => { + let message + switch (type) { + case 'defautlList': + case 'playList': + case 'playList_v2': + message = global.i18n.t('list_import_tip__playlist') + break + case 'setting': + case 'setting_v2': + message = global.i18n.t('list_import_tip__setting') + break + case 'allData': + case 'allData_v2': + message = global.i18n.t('list_import_tip__alldata') + break + case 'playListPart': + case 'playListPart_v2': + message = global.i18n.t('list_import_tip__playlist_part') + break + + default: + message = global.i18n.t('list_import_tip__unknown') + break + } + Alert.alert( + global.i18n.t('list_import_tip__failed'), + message, + [ + { + text: global.i18n.t('ok'), + }, + ], + ) +} + + +/** + * 生成节流函数 + * @param fn 回调 + * @param delay 延迟 + * @returns + */ +export function throttleBackgroundTimer<Args extends any[]>(fn: (...args: Args) => void | Promise<void>, delay = 100) { + let timer: number | null = null + let _args: Args + return (...args: Args) => { + _args = args + if (timer) return + timer = BackgroundTimer.setTimeout(() => { + timer = null + void fn(..._args) + }, delay) + } +} + +/** + * 生成防抖函数 + * @param fn 回调 + * @param delay 延迟 + * @returns + */ +export function debounceBackgroundTimer<Args extends any[]>(fn: (...args: Args) => void | Promise<void>, delay = 100) { + let timer: number | null = null + let _args: Args + return (...args: Args) => { + _args = args + if (timer) BackgroundTimer.clearTimeout(timer) + timer = BackgroundTimer.setTimeout(() => { + timer = null + void fn(..._args) + }, delay) + } +} + +// eslint-disable-next-line @typescript-eslint/ban-types +type Styles = StyleSheet.NamedStyles<Record<string, {}>> +type Style = Styles[keyof Styles] +const trasformeProps: Array<keyof Style> = [ + // @ts-expect-error + 'fontSize', + // @ts-expect-error + 'lineHeight', + // 'margin', + // 'marginLeft', + // 'marginRight', + // 'marginTop', + // 'marginBottom', + // 'padding', + // 'paddingLeft', + // 'paddingRight', + // 'paddingTop', + // 'paddingBottom', + 'left', + 'right', + 'top', + 'bottom', +] +export const trasformeStyle = <T extends Style>(styles: T): T => { + const newStyle: T = { ...styles } + + for (const [p, v] of Object.entries(newStyle) as Array<[keyof Style, Style[keyof Style]]>) { + if (typeof v != 'number') continue + switch (p) { + case 'height': + case 'minHeight': + case 'marginTop': + case 'marginBottom': + case 'paddingTop': + case 'paddingBottom': + newStyle[p] = scaleSizeH(v) + break + case 'width': + case 'minWidth': + case 'marginLeft': + case 'marginRight': + case 'paddingLeft': + case 'paddingRight': + newStyle[p] = scaleSizeW(v) + break + case 'padding': + newStyle.paddingRight = newStyle.paddingLeft = scaleSizeW(v) + newStyle.paddingBottom = newStyle.paddingTop = scaleSizeH(v) + break + case 'margin': + newStyle.marginRight = newStyle.marginLeft = scaleSizeW(v) + newStyle.marginBottom = newStyle.marginTop = scaleSizeH(v) + break + default: + // @ts-expect-error + if (trasformeProps.includes(p)) newStyle[p] = setSpText(v) + break + } + } + return newStyle +} + +export const createStyle = <T extends StyleSheet.NamedStyles<T>>(styles: T | StyleSheet.NamedStyles<T>): T => { + const newStyle: Record<string, Style> = { ...styles } + for (const [n, s] of Object.entries(newStyle)) { + newStyle[n] = trasformeStyle(s) + } + return StyleSheet.create(newStyle as StyleSheet.NamedStyles<T>) +} + + +export { + deviceLanguage, +} diff --git a/src/utils/utils.js b/src/utils/utils.js deleted file mode 100644 index 6fe286539..000000000 --- a/src/utils/utils.js +++ /dev/null @@ -1,36 +0,0 @@ -import { NativeModules } from 'react-native' - -const { UtilsModule } = NativeModules - -export const exitApp = UtilsModule.exitApp - -export const getSupportedAbis = UtilsModule.getSupportedAbis - -export const installApk = (filePath, fileProviderAuthority) => UtilsModule.installApk(filePath, fileProviderAuthority) - - -export const screenkeepAwake = () => { - if (global.isScreenKeepAwake) return - global.isScreenKeepAwake = true - UtilsModule.screenkeepAwake() -} -export const screenUnkeepAwake = () => { - // console.log('screenUnkeepAwake') - if (!global.isScreenKeepAwake) return - global.isScreenKeepAwake = false - UtilsModule.screenUnkeepAwake() -} - -export const getWIFIIPV4Address = UtilsModule.getWIFIIPV4Address - -export const getDeviceName = () => { - return UtilsModule.getDeviceName().then(deviceName => deviceName || 'Unknown') -} - -export const isNotificationsEnabled = UtilsModule.isNotificationsEnabled - -export const openNotificationPermissionActivity = UtilsModule.openNotificationPermissionActivity - -export const shareText = (shareTitle, title, text) => { - UtilsModule.shareText(shareTitle, title, text) -} diff --git a/src/utils/version.js b/src/utils/version.js index 788b9cae5..ececd30a0 100644 --- a/src/utils/version.js +++ b/src/utils/version.js @@ -1,9 +1,8 @@ import { httpGet } from '@/utils/request' import { author, name } from '../../package.json' import { downloadFile, stopDownload, temporaryDirectoryPath } from '@/utils/fs' -import { getSupportedAbis, installApk } from '@/utils/utils' +import { getSupportedAbis, installApk } from '@/utils/nativeModules/utils' import { APP_PROVIDER_NAME } from '@/config/constant' -import { toast } from './tools' const abis = [ 'arm64-v8a', @@ -67,7 +66,7 @@ const getTargetAbi = async() => { return abis[abis.length - 1] } let downloadJobId = null -const noop = () => {} +const noop = (total, download) => {} let apkSavePath export const downloadNewVersion = async(version, onDownload = noop) => { @@ -75,7 +74,7 @@ export const downloadNewVersion = async(version, onDownload = noop) => { const url = `https://github.com/${author.name}/${name}/releases/download/v${version}/${name}-v${version}-${abi}.apk` let savePath = temporaryDirectoryPath + '/lx-music-mobile.apk' - if (downloadJobId) await stopDownload(downloadJobId) + if (downloadJobId) stopDownload(downloadJobId) const { jobId, promise } = downloadFile(url, savePath, { progressInterval: 500, diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..0042dc929 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +// prettier-ignore +{ + "extends": "@tsconfig/react-native/tsconfig.json", /* Recommended React Native TSConfig base */ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + "types": ["react-native"], + /* Completeness */ + "skipLibCheck": true, /* Skip type checking all .d.ts files. */ + + "baseUrl": "./", + "paths": { + "@/*": ["src/*"], + // "@config": ["src/config"], + // "@store": ["src/store"], + // "@components": ["src/components"], + // "@navigation": ["src/navigation"], + // "@screens": ["src/screens"], + // "@theme": ["src/theme"], + // "@utils": ["src/utils"], + } + }, + "exclude": ["node_modules", "build", "dist", ".eslintrc.js"] +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..c898f306a --- /dev/null +++ b/yarn.lock @@ -0,0 +1,6455 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + "integrity" "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==" + "resolved" "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" + "version" "2.2.0" + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6": + "integrity" "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==" + "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5": + "integrity" "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==" + "resolved" "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz" + "version" "7.20.14" + +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.12.0", "@babel/core@^7.13.0", "@babel/core@^7.13.16", "@babel/core@^7.14.0", "@babel/core@^7.20.12", "@babel/core@^7.4.0-0": + "integrity" "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==" + "resolved" "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz" + "version" "7.20.12" + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.20.7" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helpers" "^7.20.7" + "@babel/parser" "^7.20.7" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.12" + "@babel/types" "^7.20.7" + "convert-source-map" "^1.7.0" + "debug" "^4.1.0" + "gensync" "^1.0.0-beta.2" + "json5" "^2.2.2" + "semver" "^6.3.0" + +"@babel/generator@^7.14.0", "@babel/generator@^7.20.7": + "integrity" "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==" + "resolved" "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz" + "version" "7.20.14" + dependencies: + "@babel/types" "^7.20.7" + "@jridgewell/gen-mapping" "^0.3.2" + "jsesc" "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.18.6": + "integrity" "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==" + "resolved" "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": + "integrity" "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==" + "resolved" "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-explode-assignable-expression" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.0", "@babel/helper-compilation-targets@^7.20.7": + "integrity" "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==" + "resolved" "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz" + "version" "7.20.7" + dependencies: + "@babel/compat-data" "^7.20.5" + "@babel/helper-validator-option" "^7.18.6" + "browserslist" "^4.21.3" + "lru-cache" "^5.1.1" + "semver" "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.20.2": + "integrity" "sha512-k22GoYRAHPYr9I+Gvy2ZQlAe5mGy8BqWst2wRt8cwIufWTxrsVshhIBvYNqC80N0GSFWTsqRVexOtfzlgOEDvA==" + "resolved" "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.2.tgz" + "version" "7.20.2" + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.19.1" + "@babel/helper-split-export-declaration" "^7.18.6" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.19.0": + "integrity" "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==" + "resolved" "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "regexpu-core" "^5.1.0" + +"@babel/helper-define-polyfill-provider@^0.3.3": + "integrity" "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==" + "resolved" "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz" + "version" "0.3.3" + dependencies: + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + "debug" "^4.1.1" + "lodash.debounce" "^4.0.8" + "resolve" "^1.14.2" + "semver" "^6.1.2" + +"@babel/helper-environment-visitor@^7.18.9": + "integrity" "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + "resolved" "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" + "version" "7.18.9" + +"@babel/helper-explode-assignable-expression@^7.18.6": + "integrity" "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==" + "resolved" "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0": + "integrity" "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==" + "resolved" "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/template" "^7.18.10" + "@babel/types" "^7.19.0" + +"@babel/helper-hoist-variables@^7.18.6": + "integrity" "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==" + "resolved" "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-member-expression-to-functions@^7.18.9": + "integrity" "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==" + "resolved" "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-module-imports@^7.18.6": + "integrity" "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.19.6", "@babel/helper-module-transforms@^7.20.11": + "integrity" "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz" + "version" "7.20.11" + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.20.2" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.10" + "@babel/types" "^7.20.7" + +"@babel/helper-optimise-call-expression@^7.18.6": + "integrity" "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==" + "resolved" "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + "integrity" "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==" + "resolved" "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz" + "version" "7.20.2" + +"@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9": + "integrity" "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==" + "resolved" "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-wrap-function" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.19.1": + "integrity" "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==" + "resolved" "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz" + "version" "7.19.1" + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/traverse" "^7.19.1" + "@babel/types" "^7.19.0" + +"@babel/helper-simple-access@^7.19.4", "@babel/helper-simple-access@^7.20.2": + "integrity" "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==" + "resolved" "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz" + "version" "7.20.2" + dependencies: + "@babel/types" "^7.20.2" + +"@babel/helper-skip-transparent-expression-wrappers@^7.18.9": + "integrity" "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==" + "resolved" "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz" + "version" "7.20.0" + dependencies: + "@babel/types" "^7.20.0" + +"@babel/helper-split-export-declaration@^7.18.6": + "integrity" "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==" + "resolved" "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.19.4": + "integrity" "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + "resolved" "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz" + "version" "7.19.4" + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + "integrity" "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz" + "version" "7.19.1" + +"@babel/helper-validator-option@^7.18.6": + "integrity" "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" + "version" "7.18.6" + +"@babel/helper-wrap-function@^7.18.9": + "integrity" "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==" + "resolved" "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/helper-function-name" "^7.19.0" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.0" + "@babel/types" "^7.19.0" + +"@babel/helpers@^7.20.7": + "integrity" "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==" + "resolved" "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz" + "version" "7.20.13" + dependencies: + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.13" + "@babel/types" "^7.20.7" + +"@babel/highlight@^7.18.6": + "integrity" "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==" + "resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + "chalk" "^2.0.0" + "js-tokens" "^4.0.0" + +"@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.20.13", "@babel/parser@^7.20.7": + "integrity" "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==" + "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz" + "version" "7.20.15" + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": + "integrity" "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": + "integrity" "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/plugin-proposal-optional-chaining" "^7.18.9" + +"@babel/plugin-proposal-async-generator-functions@^7.0.0", "@babel/plugin-proposal-async-generator-functions@^7.20.1": + "integrity" "sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz" + "version" "7.20.1" + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-remap-async-to-generator" "^7.18.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.13.0", "@babel/plugin-proposal-class-properties@^7.18.6": + "integrity" "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-class-static-block@^7.18.6": + "integrity" "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-dynamic-import@^7.18.6": + "integrity" "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-default-from@^7.0.0": + "integrity" "sha512-5H2N3R2aQFxkV4PIBUR/i7PUSwgTZjouJKzI8eKswfIjT0PhvzkPn0t0wIS5zn6maQuvtT0t1oHtMUz61LOuow==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.18.10.tgz" + "version" "7.18.10" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-export-default-from" "^7.18.6" + +"@babel/plugin-proposal-export-namespace-from@^7.18.9": + "integrity" "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.18.6": + "integrity" "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.18.9": + "integrity" "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.0.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.13.8", "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": + "integrity" "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.18.6": + "integrity" "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.20.2": + "integrity" "sha512-Ks6uej9WFK+fvIMesSqbAto5dD8Dz4VuuFvGJFKgIGSkJuRGcrwGECPA1fDgQK3/DbExBJpEkTeYeB8geIFCSQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.2.tgz" + "version" "7.20.2" + dependencies: + "@babel/compat-data" "^7.20.1" + "@babel/helper-compilation-targets" "^7.20.0" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.20.1" + +"@babel/plugin-proposal-optional-catch-binding@^7.0.0", "@babel/plugin-proposal-optional-catch-binding@^7.18.6": + "integrity" "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.0.0", "@babel/plugin-proposal-optional-chaining@^7.13.12", "@babel/plugin-proposal-optional-chaining@^7.18.9": + "integrity" "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.18.6": + "integrity" "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-private-property-in-object@^7.18.6": + "integrity" "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + "integrity" "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-async-generators@^7.8.4": + "integrity" "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" + "version" "7.8.4" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.0.0", "@babel/plugin-syntax-class-properties@^7.12.13": + "integrity" "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" + "version" "7.12.13" + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + "integrity" "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz" + "version" "7.14.5" + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.0.0", "@babel/plugin-syntax-dynamic-import@^7.8.3": + "integrity" "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-default-from@^7.0.0", "@babel/plugin-syntax-export-default-from@^7.18.6": + "integrity" "sha512-Kr//z3ujSVNx6E9z9ih5xXXMqK07VVTuqPmqGe6Mss/zW5XPeLZeSDZoP9ab/hT4wPKqAgjl2PnhPrcpk8Seew==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + "integrity" "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.18.6", "@babel/plugin-syntax-flow@^7.2.0": + "integrity" "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-import-assertions@^7.20.0": + "integrity" "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz" + "version" "7.20.0" + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-syntax-json-strings@^7.8.3": + "integrity" "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.18.6": + "integrity" "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + "integrity" "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" + "version" "7.10.4" + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.0.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + "integrity" "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + "integrity" "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" + "version" "7.10.4" + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": + "integrity" "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + "integrity" "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.0.0", "@babel/plugin-syntax-optional-chaining@^7.8.3": + "integrity" "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + "integrity" "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz" + "version" "7.14.5" + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + "integrity" "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" + "version" "7.14.5" + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.20.0": + "integrity" "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz" + "version" "7.20.0" + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-transform-arrow-functions@^7.0.0", "@babel/plugin-transform-arrow-functions@^7.18.6": + "integrity" "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-async-to-generator@^7.0.0", "@babel/plugin-transform-async-to-generator@^7.18.6": + "integrity" "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-remap-async-to-generator" "^7.18.6" + +"@babel/plugin-transform-block-scoped-functions@^7.0.0", "@babel/plugin-transform-block-scoped-functions@^7.18.6": + "integrity" "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-block-scoping@^7.0.0", "@babel/plugin-transform-block-scoping@^7.20.2": + "integrity" "sha512-y5V15+04ry69OV2wULmwhEA6jwSWXO1TwAtIwiPXcvHcoOQUqpyMVd2bDsQJMW8AurjulIyUV8kDqtjSwHy1uQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.2.tgz" + "version" "7.20.2" + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-classes@^7.0.0", "@babel/plugin-transform-classes@^7.20.2": + "integrity" "sha512-9rbPp0lCVVoagvtEyQKSo5L8oo0nQS/iif+lwlAz29MccX2642vWDlSZK+2T2buxbopotId2ld7zZAzRfz9j1g==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.2.tgz" + "version" "7.20.2" + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-compilation-targets" "^7.20.0" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-replace-supers" "^7.19.1" + "@babel/helper-split-export-declaration" "^7.18.6" + "globals" "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.0.0", "@babel/plugin-transform-computed-properties@^7.18.9": + "integrity" "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-destructuring@^7.0.0", "@babel/plugin-transform-destructuring@^7.20.2": + "integrity" "sha512-mENM+ZHrvEgxLTBXUiQ621rRXZes3KWUv6NdQlrnr1TkWVw+hUjQBZuP2X32qKlrlG2BzgR95gkuCRSkJl8vIw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.2.tgz" + "version" "7.20.2" + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": + "integrity" "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-duplicate-keys@^7.18.9": + "integrity" "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-exponentiation-operator@^7.0.0", "@babel/plugin-transform-exponentiation-operator@^7.18.6": + "integrity" "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-flow-strip-types@^7.0.0", "@babel/plugin-transform-flow-strip-types@^7.18.6": + "integrity" "sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/plugin-syntax-flow" "^7.18.6" + +"@babel/plugin-transform-for-of@^7.0.0", "@babel/plugin-transform-for-of@^7.18.8": + "integrity" "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz" + "version" "7.18.8" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-function-name@^7.0.0", "@babel/plugin-transform-function-name@^7.18.9": + "integrity" "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-literals@^7.0.0", "@babel/plugin-transform-literals@^7.18.9": + "integrity" "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-member-expression-literals@^7.0.0", "@babel/plugin-transform-member-expression-literals@^7.18.6": + "integrity" "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-modules-amd@^7.19.6": + "integrity" "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/helper-module-transforms" "^7.19.6" + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-transform-modules-commonjs@^7.0.0", "@babel/plugin-transform-modules-commonjs@^7.13.8", "@babel/plugin-transform-modules-commonjs@^7.19.6": + "integrity" "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/helper-module-transforms" "^7.19.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-simple-access" "^7.19.4" + +"@babel/plugin-transform-modules-systemjs@^7.19.6": + "integrity" "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-module-transforms" "^7.19.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-validator-identifier" "^7.19.1" + +"@babel/plugin-transform-modules-umd@^7.18.6": + "integrity" "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.0.0", "@babel/plugin-transform-named-capturing-groups-regex@^7.19.1": + "integrity" "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz" + "version" "7.19.1" + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.19.0" + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-transform-new-target@^7.18.6": + "integrity" "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-object-super@^7.0.0", "@babel/plugin-transform-object-super@^7.18.6": + "integrity" "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + +"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.20.1": + "integrity" "sha512-oZg/Fpx0YDrj13KsLyO8I/CX3Zdw7z0O9qOd95SqcoIzuqy/WTGWvePeHAnZCN54SfdyjHcb1S30gc8zlzlHcA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.3.tgz" + "version" "7.20.3" + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-property-literals@^7.0.0", "@babel/plugin-transform-property-literals@^7.18.6": + "integrity" "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-display-name@^7.0.0": + "integrity" "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-self@^7.0.0": + "integrity" "sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-source@^7.0.0": + "integrity" "sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-transform-react-jsx@^7.0.0": + "integrity" "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/plugin-syntax-jsx" "^7.18.6" + "@babel/types" "^7.19.0" + +"@babel/plugin-transform-regenerator@^7.18.6": + "integrity" "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "regenerator-transform" "^0.15.0" + +"@babel/plugin-transform-reserved-words@^7.18.6": + "integrity" "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-runtime@^7.0.0": + "integrity" "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.19.0" + "babel-plugin-polyfill-corejs2" "^0.3.3" + "babel-plugin-polyfill-corejs3" "^0.6.0" + "babel-plugin-polyfill-regenerator" "^0.4.1" + "semver" "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.0.0", "@babel/plugin-transform-shorthand-properties@^7.18.6": + "integrity" "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-spread@^7.0.0", "@babel/plugin-transform-spread@^7.19.0": + "integrity" "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + +"@babel/plugin-transform-sticky-regex@^7.0.0", "@babel/plugin-transform-sticky-regex@^7.18.6": + "integrity" "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-template-literals@^7.0.0", "@babel/plugin-transform-template-literals@^7.18.9": + "integrity" "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typeof-symbol@^7.18.9": + "integrity" "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typescript@^7.18.6", "@babel/plugin-transform-typescript@^7.5.0": + "integrity" "sha512-jvS+ngBfrnTUBfOQq8NfGnSbF9BrqlR6hjJ2yVxMkmO5nL/cdifNbI30EfjRlN4g5wYWNnMPyj5Sa6R1pbLeag==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.2.tgz" + "version" "7.20.2" + dependencies: + "@babel/helper-create-class-features-plugin" "^7.20.2" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-typescript" "^7.20.0" + +"@babel/plugin-transform-unicode-escapes@^7.18.10": + "integrity" "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz" + "version" "7.18.10" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-unicode-regex@^7.0.0", "@babel/plugin-transform-unicode-regex@^7.18.6": + "integrity" "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/preset-env@^7.1.6": + "integrity" "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==" + "resolved" "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz" + "version" "7.20.2" + dependencies: + "@babel/compat-data" "^7.20.1" + "@babel/helper-compilation-targets" "^7.20.0" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-async-generator-functions" "^7.20.1" + "@babel/plugin-proposal-class-properties" "^7.18.6" + "@babel/plugin-proposal-class-static-block" "^7.18.6" + "@babel/plugin-proposal-dynamic-import" "^7.18.6" + "@babel/plugin-proposal-export-namespace-from" "^7.18.9" + "@babel/plugin-proposal-json-strings" "^7.18.6" + "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" + "@babel/plugin-proposal-numeric-separator" "^7.18.6" + "@babel/plugin-proposal-object-rest-spread" "^7.20.2" + "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" + "@babel/plugin-proposal-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-private-methods" "^7.18.6" + "@babel/plugin-proposal-private-property-in-object" "^7.18.6" + "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.20.0" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.18.6" + "@babel/plugin-transform-async-to-generator" "^7.18.6" + "@babel/plugin-transform-block-scoped-functions" "^7.18.6" + "@babel/plugin-transform-block-scoping" "^7.20.2" + "@babel/plugin-transform-classes" "^7.20.2" + "@babel/plugin-transform-computed-properties" "^7.18.9" + "@babel/plugin-transform-destructuring" "^7.20.2" + "@babel/plugin-transform-dotall-regex" "^7.18.6" + "@babel/plugin-transform-duplicate-keys" "^7.18.9" + "@babel/plugin-transform-exponentiation-operator" "^7.18.6" + "@babel/plugin-transform-for-of" "^7.18.8" + "@babel/plugin-transform-function-name" "^7.18.9" + "@babel/plugin-transform-literals" "^7.18.9" + "@babel/plugin-transform-member-expression-literals" "^7.18.6" + "@babel/plugin-transform-modules-amd" "^7.19.6" + "@babel/plugin-transform-modules-commonjs" "^7.19.6" + "@babel/plugin-transform-modules-systemjs" "^7.19.6" + "@babel/plugin-transform-modules-umd" "^7.18.6" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1" + "@babel/plugin-transform-new-target" "^7.18.6" + "@babel/plugin-transform-object-super" "^7.18.6" + "@babel/plugin-transform-parameters" "^7.20.1" + "@babel/plugin-transform-property-literals" "^7.18.6" + "@babel/plugin-transform-regenerator" "^7.18.6" + "@babel/plugin-transform-reserved-words" "^7.18.6" + "@babel/plugin-transform-shorthand-properties" "^7.18.6" + "@babel/plugin-transform-spread" "^7.19.0" + "@babel/plugin-transform-sticky-regex" "^7.18.6" + "@babel/plugin-transform-template-literals" "^7.18.9" + "@babel/plugin-transform-typeof-symbol" "^7.18.9" + "@babel/plugin-transform-unicode-escapes" "^7.18.10" + "@babel/plugin-transform-unicode-regex" "^7.18.6" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.20.2" + "babel-plugin-polyfill-corejs2" "^0.3.3" + "babel-plugin-polyfill-corejs3" "^0.6.0" + "babel-plugin-polyfill-regenerator" "^0.4.1" + "core-js-compat" "^3.25.1" + "semver" "^6.3.0" + +"@babel/preset-flow@^7.13.13": + "integrity" "sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ==" + "resolved" "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-flow-strip-types" "^7.18.6" + +"@babel/preset-modules@^0.1.5": + "integrity" "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==" + "resolved" "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz" + "version" "0.1.5" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + "esutils" "^2.0.2" + +"@babel/preset-typescript@^7.13.0": + "integrity" "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==" + "resolved" "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-typescript" "^7.18.6" + +"@babel/register@^7.13.16": + "integrity" "sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw==" + "resolved" "https://registry.npmjs.org/@babel/register/-/register-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "clone-deep" "^4.0.1" + "find-cache-dir" "^2.0.0" + "make-dir" "^2.1.0" + "pirates" "^4.0.5" + "source-map-support" "^0.5.16" + +"@babel/runtime@^7.0.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.8.4": + "integrity" "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==" + "resolved" "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz" + "version" "7.20.13" + dependencies: + "regenerator-runtime" "^0.13.11" + +"@babel/template@^7.0.0", "@babel/template@^7.18.10", "@babel/template@^7.20.7": + "integrity" "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==" + "resolved" "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz" + "version" "7.20.7" + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/traverse@^7.14.0", "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.10", "@babel/traverse@^7.20.12", "@babel/traverse@^7.20.13": + "integrity" "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==" + "resolved" "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz" + "version" "7.20.13" + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.20.7" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.20.13" + "@babel/types" "^7.20.7" + "debug" "^4.1.0" + "globals" "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.4.4": + "integrity" "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==" + "resolved" "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz" + "version" "7.20.7" + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + "to-fast-properties" "^2.0.0" + +"@craftzdog/react-native-buffer@^6.0.4", "@craftzdog/react-native-buffer@^6.0.5": + "integrity" "sha512-Av+YqfwA9e7jhgI9GFE/gTpwl/H+dRRLmZyJPOpKTy107j9Oj7oXlm3/YiMNz+C/CEGqcKAOqnXDLs4OL6AAFw==" + "resolved" "https://registry.npmjs.org/@craftzdog/react-native-buffer/-/react-native-buffer-6.0.5.tgz" + "version" "6.0.5" + dependencies: + "ieee754" "^1.2.1" + "react-native-quick-base64" "^2.0.5" + +"@eslint/eslintrc@^1.3.3": + "integrity" "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==" + "resolved" "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz" + "version" "1.3.3" + dependencies: + "ajv" "^6.12.4" + "debug" "^4.3.2" + "espree" "^9.4.0" + "globals" "^13.15.0" + "ignore" "^5.2.0" + "import-fresh" "^3.2.1" + "js-yaml" "^4.1.0" + "minimatch" "^3.1.2" + "strip-json-comments" "^3.1.1" + +"@hapi/hoek@^9.0.0": + "integrity" "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + "resolved" "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz" + "version" "9.3.0" + +"@hapi/topo@^5.0.0": + "integrity" "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==" + "resolved" "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz" + "version" "5.1.0" + dependencies: + "@hapi/hoek" "^9.0.0" + +"@humanwhocodes/config-array@^0.11.6": + "integrity" "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==" + "resolved" "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz" + "version" "0.11.7" + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + "debug" "^4.1.1" + "minimatch" "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + "integrity" "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" + "resolved" "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + "version" "1.0.1" + +"@humanwhocodes/object-schema@^1.2.1": + "integrity" "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "resolved" "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" + "version" "1.2.1" + +"@jest/create-cache-key-function@^27.0.1": + "integrity" "sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==" + "resolved" "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz" + "version" "27.5.1" + dependencies: + "@jest/types" "^27.5.1" + +"@jest/types@^26.6.2": + "integrity" "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==" + "resolved" "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz" + "version" "26.6.2" + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + "chalk" "^4.0.0" + +"@jest/types@^27.5.1": + "integrity" "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==" + "resolved" "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz" + "version" "27.5.1" + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + "chalk" "^4.0.0" + +"@jridgewell/gen-mapping@^0.1.0": + "integrity" "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==" + "resolved" "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" + "version" "0.1.1" + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.2": + "integrity" "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==" + "resolved" "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" + "version" "0.3.2" + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + "integrity" "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + "resolved" "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" + "version" "3.1.0" + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + "integrity" "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + "resolved" "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + "version" "1.1.2" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@1.4.14": + "integrity" "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + "resolved" "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + "version" "1.4.14" + +"@jridgewell/trace-mapping@^0.3.9": + "integrity" "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==" + "resolved" "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz" + "version" "0.3.17" + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@nodelib/fs.scandir@2.1.5": + "integrity" "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + "version" "2.1.5" + dependencies: + "@nodelib/fs.stat" "2.0.5" + "run-parallel" "^1.1.9" + +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": + "integrity" "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + "version" "2.0.5" + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + "integrity" "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + "version" "1.2.8" + dependencies: + "@nodelib/fs.scandir" "2.1.5" + "fastq" "^1.6.0" + +"@react-native-async-storage/async-storage@^1.17.11": + "integrity" "sha512-bzs45n5HNcDq6mxXnSsOHysZWn1SbbebNxldBXCQs8dSvF8Aor9KCdpm+TpnnGweK3R6diqsT8lFhX77VX0NFw==" + "resolved" "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.17.11.tgz" + "version" "1.17.11" + dependencies: + "merge-options" "^3.0.4" + +"@react-native-clipboard/clipboard@^1.11.1": + "integrity" "sha512-nvSIIHzybVWqYxcJE5hpT17ekxAAg383Ggzw5WrYHtkKX61N1AwaKSNmXs5xHV7pmKSOe/yWjtSwxIzfW51I5Q==" + "resolved" "https://registry.npmjs.org/@react-native-clipboard/clipboard/-/clipboard-1.11.1.tgz" + "version" "1.11.1" + +"@react-native-community/checkbox@^0.5.14": + "integrity" "sha512-UmGf3wBpoCXLmVRKIDZyzOG+QR1fOhm0FOw4KzxHTCXpsBvZgIn5wbJ+MWk4io5RohQdY8GSX2MYFmkPJeJpeA==" + "resolved" "https://registry.npmjs.org/@react-native-community/checkbox/-/checkbox-0.5.14.tgz" + "version" "0.5.14" + +"@react-native-community/cli-clean@^9.2.1": + "integrity" "sha512-dyNWFrqRe31UEvNO+OFWmQ4hmqA07bR9Ief/6NnGwx67IO9q83D5PEAf/o96ML6jhSbDwCmpPKhPwwBbsyM3mQ==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-9.2.1.tgz" + "version" "9.2.1" + dependencies: + "@react-native-community/cli-tools" "^9.2.1" + "chalk" "^4.1.2" + "execa" "^1.0.0" + "prompts" "^2.4.0" + +"@react-native-community/cli-config@^9.2.1": + "integrity" "sha512-gHJlBBXUgDN9vrr3aWkRqnYrPXZLztBDQoY97Mm5Yo6MidsEpYo2JIP6FH4N/N2p1TdjxJL4EFtdd/mBpiR2MQ==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-9.2.1.tgz" + "version" "9.2.1" + dependencies: + "@react-native-community/cli-tools" "^9.2.1" + "cosmiconfig" "^5.1.0" + "deepmerge" "^3.2.0" + "glob" "^7.1.3" + "joi" "^17.2.1" + +"@react-native-community/cli-debugger-ui@^9.0.0": + "integrity" "sha512-7hH05ZwU9Tp0yS6xJW0bqcZPVt0YCK7gwj7gnRu1jDNN2kughf6Lg0Ys29rAvtZ7VO1PK5c1O+zs7yFnylQDUA==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-9.0.0.tgz" + "version" "9.0.0" + dependencies: + "serve-static" "^1.13.1" + +"@react-native-community/cli-doctor@^9.3.0": + "integrity" "sha512-/fiuG2eDGC2/OrXMOWI5ifq4X1gdYTQhvW2m0TT5Lk1LuFiZsbTCp1lR+XILKekuTvmYNjEGdVpeDpdIWlXdEA==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-9.3.0.tgz" + "version" "9.3.0" + dependencies: + "@react-native-community/cli-config" "^9.2.1" + "@react-native-community/cli-platform-ios" "^9.3.0" + "@react-native-community/cli-tools" "^9.2.1" + "chalk" "^4.1.2" + "command-exists" "^1.2.8" + "envinfo" "^7.7.2" + "execa" "^1.0.0" + "hermes-profile-transformer" "^0.0.6" + "ip" "^1.1.5" + "node-stream-zip" "^1.9.1" + "ora" "^5.4.1" + "prompts" "^2.4.0" + "semver" "^6.3.0" + "strip-ansi" "^5.2.0" + "sudo-prompt" "^9.0.0" + "wcwidth" "^1.0.1" + +"@react-native-community/cli-hermes@^9.3.1": + "integrity" "sha512-Mq4PK8m5YqIdaVq5IdRfp4qK09aVO+aiCtd6vjzjNUgk1+1X5cgUqV6L65h4N+TFJYJHcp2AnB+ik1FAYXvYPQ==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-9.3.1.tgz" + "version" "9.3.1" + dependencies: + "@react-native-community/cli-platform-android" "^9.3.1" + "@react-native-community/cli-tools" "^9.2.1" + "chalk" "^4.1.2" + "hermes-profile-transformer" "^0.0.6" + "ip" "^1.1.5" + +"@react-native-community/cli-platform-android@^9.3.1", "@react-native-community/cli-platform-android@9.3.1": + "integrity" "sha512-m0bQ6Twewl7OEZoVf79I2GZmsDqh+Gh0bxfxWgwxobsKDxLx8/RNItAo1lVtTCgzuCR75cX4EEO8idIF9jYhew==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-9.3.1.tgz" + "version" "9.3.1" + dependencies: + "@react-native-community/cli-tools" "^9.2.1" + "chalk" "^4.1.2" + "execa" "^1.0.0" + "fs-extra" "^8.1.0" + "glob" "^7.1.3" + "logkitty" "^0.7.1" + "slash" "^3.0.0" + +"@react-native-community/cli-platform-ios@^9.3.0", "@react-native-community/cli-platform-ios@9.3.0": + "integrity" "sha512-nihTX53BhF2Q8p4B67oG3RGe1XwggoGBrMb6vXdcu2aN0WeXJOXdBLgR900DAA1O8g7oy1Sudu6we+JsVTKnjw==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-9.3.0.tgz" + "version" "9.3.0" + dependencies: + "@react-native-community/cli-tools" "^9.2.1" + "chalk" "^4.1.2" + "execa" "^1.0.0" + "glob" "^7.1.3" + "ora" "^5.4.1" + +"@react-native-community/cli-plugin-metro@^9.2.1": + "integrity" "sha512-byBGBH6jDfUvcHGFA45W/sDwMlliv7flJ8Ns9foCh3VsIeYYPoDjjK7SawE9cPqRdMAD4SY7EVwqJnOtRbwLiQ==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-9.2.1.tgz" + "version" "9.2.1" + dependencies: + "@react-native-community/cli-server-api" "^9.2.1" + "@react-native-community/cli-tools" "^9.2.1" + "chalk" "^4.1.2" + "metro" "0.72.3" + "metro-config" "0.72.3" + "metro-core" "0.72.3" + "metro-react-native-babel-transformer" "0.72.3" + "metro-resolver" "0.72.3" + "metro-runtime" "0.72.3" + "readline" "^1.3.0" + +"@react-native-community/cli-server-api@^9.2.1": + "integrity" "sha512-EI+9MUxEbWBQhWw2PkhejXfkcRqPl+58+whlXJvKHiiUd7oVbewFs0uLW0yZffUutt4FGx6Uh88JWEgwOzAdkw==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-9.2.1.tgz" + "version" "9.2.1" + dependencies: + "@react-native-community/cli-debugger-ui" "^9.0.0" + "@react-native-community/cli-tools" "^9.2.1" + "compression" "^1.7.1" + "connect" "^3.6.5" + "errorhandler" "^1.5.0" + "nocache" "^3.0.1" + "pretty-format" "^26.6.2" + "serve-static" "^1.13.1" + "ws" "^7.5.1" + +"@react-native-community/cli-tools@^9.2.1": + "integrity" "sha512-bHmL/wrKmBphz25eMtoJQgwwmeCylbPxqFJnFSbkqJPXQz3ManQ6q/gVVMqFyz7D3v+riaus/VXz3sEDa97uiQ==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-9.2.1.tgz" + "version" "9.2.1" + dependencies: + "appdirsjs" "^1.2.4" + "chalk" "^4.1.2" + "find-up" "^5.0.0" + "mime" "^2.4.1" + "node-fetch" "^2.6.0" + "open" "^6.2.0" + "ora" "^5.4.1" + "semver" "^6.3.0" + "shell-quote" "^1.7.3" + +"@react-native-community/cli-types@^9.1.0": + "integrity" "sha512-KDybF9XHvafLEILsbiKwz5Iobd+gxRaPyn4zSaAerBxedug4er5VUWa8Szy+2GeYKZzMh/gsb1o9lCToUwdT/g==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-9.1.0.tgz" + "version" "9.1.0" + dependencies: + "joi" "^17.2.1" + +"@react-native-community/cli@9.3.2": + "integrity" "sha512-IAW4X0vmX/xozNpp/JVZaX7MrC85KV0OP2DF4o7lNGOfpUhzJAEWqTfkxFYS+VsRjZHDve4wSTiGIuXwE7FG1w==" + "resolved" "https://registry.npmjs.org/@react-native-community/cli/-/cli-9.3.2.tgz" + "version" "9.3.2" + dependencies: + "@react-native-community/cli-clean" "^9.2.1" + "@react-native-community/cli-config" "^9.2.1" + "@react-native-community/cli-debugger-ui" "^9.0.0" + "@react-native-community/cli-doctor" "^9.3.0" + "@react-native-community/cli-hermes" "^9.3.1" + "@react-native-community/cli-plugin-metro" "^9.2.1" + "@react-native-community/cli-server-api" "^9.2.1" + "@react-native-community/cli-tools" "^9.2.1" + "@react-native-community/cli-types" "^9.1.0" + "chalk" "^4.1.2" + "commander" "^9.4.0" + "execa" "^1.0.0" + "find-up" "^4.1.0" + "fs-extra" "^8.1.0" + "graceful-fs" "^4.1.3" + "prompts" "^2.4.0" + "semver" "^6.3.0" + +"@react-native-community/slider@^4.4.2": + "integrity" "sha512-D9bv+3Vd2gairAhnRPAghwccgEmoM7g562pm8i4qB3Esrms5mggF81G3UvCyc0w3jjtFHh8dpQkfEoKiP0NW/Q==" + "resolved" "https://registry.npmjs.org/@react-native-community/slider/-/slider-4.4.2.tgz" + "version" "4.4.2" + +"@react-native/assets@1.0.0": + "integrity" "sha512-KrwSpS1tKI70wuKl68DwJZYEvXktDHdZMG0k2AXD/rJVSlB23/X2CB2cutVR0HwNMJIal9HOUOBB2rVfa6UGtQ==" + "resolved" "https://registry.npmjs.org/@react-native/assets/-/assets-1.0.0.tgz" + "version" "1.0.0" + +"@react-native/normalize-color@2.0.0": + "integrity" "sha512-Wip/xsc5lw8vsBlmY2MO/gFLp3MvuZ2baBZjDeTjjndMgM0h5sxz7AZR62RDPGgstp8Np7JzjvVqVT7tpFZqsw==" + "resolved" "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.0.0.tgz" + "version" "2.0.0" + +"@react-native/polyfills@2.0.0": + "integrity" "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==" + "resolved" "https://registry.npmjs.org/@react-native/polyfills/-/polyfills-2.0.0.tgz" + "version" "2.0.0" + +"@sideway/address@^4.1.3": + "integrity" "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==" + "resolved" "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz" + "version" "4.1.4" + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.0": + "integrity" "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" + "resolved" "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz" + "version" "3.0.1" + +"@sideway/pinpoint@^2.0.0": + "integrity" "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + "resolved" "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz" + "version" "2.0.0" + +"@socket.io/component-emitter@~3.1.0": + "integrity" "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + "resolved" "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz" + "version" "3.1.0" + +"@tsconfig/react-native@^2.0.3": + "integrity" "sha512-jE58snEKBd9DXfyR4+ssZmYJ/W2mOSnNrvljR0aLyQJL9JKX6vlWELHkRjb3HBbcM9Uy0hZGijXbqEAjOERW2A==" + "resolved" "https://registry.npmjs.org/@tsconfig/react-native/-/react-native-2.0.3.tgz" + "version" "2.0.3" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + "integrity" "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + "resolved" "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" + "version" "2.0.4" + +"@types/istanbul-lib-report@*": + "integrity" "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==" + "resolved" "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + "integrity" "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==" + "resolved" "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz" + "version" "3.0.1" + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/json-schema@^7.0.9": + "integrity" "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + "resolved" "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz" + "version" "7.0.11" + +"@types/json5@^0.0.29": + "integrity" "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" + "resolved" "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" + "version" "0.0.29" + +"@types/node@*": + "integrity" "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==" + "resolved" "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz" + "version" "18.11.17" + +"@types/node@^17.0.31": + "integrity" "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + "resolved" "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz" + "version" "17.0.45" + +"@types/prop-types@*": + "integrity" "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "resolved" "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz" + "version" "15.7.5" + +"@types/react-native-background-timer@^2.0.0": + "integrity" "sha512-y5VW82dL/ESOLg+5QQHyBdsFVA4ZklENxmOyxv8o06T+3HBG2JOSuz/CIPz1vKdB7dmWDGPZNuPosdtnp+xv2A==" + "resolved" "https://registry.npmjs.org/@types/react-native-background-timer/-/react-native-background-timer-2.0.0.tgz" + "version" "2.0.0" + +"@types/react-native-vector-icons@^6.4.13": + "integrity" "sha512-1PqFoKuXTSzMHwGMAr+REdYJBQAbe9xrww3ecZR0FsHcD1K+vGS/rxuAriL4rsI6+p69sZQjDzpEVAbDQcjSwA==" + "resolved" "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.13.tgz" + "version" "6.4.13" + dependencies: + "@types/react" "*" + "@types/react-native" "^0.70" + +"@types/react-native@^0.70", "@types/react-native@^0.70.11": + "integrity" "sha512-FobPtzoNPNHugBKMfzs4Li0Q9ei4tgU8SI1M5Ayg7+t5/+noCm2sknI8uwij22wMkcHcefv8RFx4q28nNVJtCQ==" + "resolved" "https://registry.npmjs.org/@types/react-native/-/react-native-0.70.11.tgz" + "version" "0.70.11" + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^18.0.28": + "integrity" "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==" + "resolved" "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz" + "version" "18.0.28" + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + "csstype" "^3.0.2" + +"@types/scheduler@*": + "integrity" "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + "resolved" "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" + "version" "0.16.2" + +"@types/semver@^7.3.12": + "integrity" "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==" + "resolved" "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz" + "version" "7.3.13" + +"@types/yargs-parser@*": + "integrity" "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" + "resolved" "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" + "version" "21.0.0" + +"@types/yargs@^15.0.0": + "integrity" "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==" + "resolved" "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz" + "version" "15.0.14" + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs@^16.0.0": + "integrity" "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==" + "resolved" "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz" + "version" "16.0.4" + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^5.0.0": + "integrity" "sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/scope-manager" "5.51.0" + "@typescript-eslint/type-utils" "5.51.0" + "@typescript-eslint/utils" "5.51.0" + "debug" "^4.3.4" + "grapheme-splitter" "^1.0.4" + "ignore" "^5.2.0" + "natural-compare-lite" "^1.4.0" + "regexpp" "^3.2.0" + "semver" "^7.3.7" + "tsutils" "^3.21.0" + +"@typescript-eslint/parser@^5.0.0": + "integrity" "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/scope-manager" "5.51.0" + "@typescript-eslint/types" "5.51.0" + "@typescript-eslint/typescript-estree" "5.51.0" + "debug" "^4.3.4" + +"@typescript-eslint/scope-manager@5.51.0": + "integrity" "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/types" "5.51.0" + "@typescript-eslint/visitor-keys" "5.51.0" + +"@typescript-eslint/type-utils@5.51.0": + "integrity" "sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/typescript-estree" "5.51.0" + "@typescript-eslint/utils" "5.51.0" + "debug" "^4.3.4" + "tsutils" "^3.21.0" + +"@typescript-eslint/types@5.51.0": + "integrity" "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz" + "version" "5.51.0" + +"@typescript-eslint/typescript-estree@5.51.0": + "integrity" "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/types" "5.51.0" + "@typescript-eslint/visitor-keys" "5.51.0" + "debug" "^4.3.4" + "globby" "^11.1.0" + "is-glob" "^4.0.3" + "semver" "^7.3.7" + "tsutils" "^3.21.0" + +"@typescript-eslint/utils@5.51.0": + "integrity" "sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.51.0" + "@typescript-eslint/types" "5.51.0" + "@typescript-eslint/typescript-estree" "5.51.0" + "eslint-scope" "^5.1.1" + "eslint-utils" "^3.0.0" + "semver" "^7.3.7" + +"@typescript-eslint/visitor-keys@5.51.0": + "integrity" "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/types" "5.51.0" + "eslint-visitor-keys" "^3.3.0" + +"abort-controller@^3.0.0": + "integrity" "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==" + "resolved" "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "event-target-shim" "^5.0.0" + +"absolute-path@^0.0.0": + "integrity" "sha512-HQiug4c+/s3WOvEnDRxXVmNtSG5s2gJM9r19BTcqjp7BWcE48PB+Y2G6jE65kqI0LpsQeMZygt/b60Gi4KxGyA==" + "resolved" "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz" + "version" "0.0.0" + +"accepts@^1.3.7", "accepts@~1.3.5", "accepts@~1.3.7": + "integrity" "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==" + "resolved" "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" + "version" "1.3.8" + dependencies: + "mime-types" "~2.1.34" + "negotiator" "0.6.3" + +"acorn-jsx@^5.3.2": + "integrity" "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" + "resolved" "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + "version" "5.3.2" + +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", "acorn@^8.8.0": + "integrity" "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==" + "resolved" "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz" + "version" "8.8.1" + +"ajv@^6.10.0", "ajv@^6.12.4": + "integrity" "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==" + "resolved" "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + "version" "6.12.6" + dependencies: + "fast-deep-equal" "^3.1.1" + "fast-json-stable-stringify" "^2.0.0" + "json-schema-traverse" "^0.4.1" + "uri-js" "^4.2.2" + +"anser@^1.4.9": + "integrity" "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==" + "resolved" "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz" + "version" "1.4.10" + +"ansi-fragments@^0.2.1": + "integrity" "sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==" + "resolved" "https://registry.npmjs.org/ansi-fragments/-/ansi-fragments-0.2.1.tgz" + "version" "0.2.1" + dependencies: + "colorette" "^1.0.7" + "slice-ansi" "^2.0.0" + "strip-ansi" "^5.0.0" + +"ansi-regex@^4.1.0": + "integrity" "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz" + "version" "4.1.1" + +"ansi-regex@^5.0.0", "ansi-regex@^5.0.1": + "integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + "version" "5.0.1" + +"ansi-styles@^3.2.0", "ansi-styles@^3.2.1": + "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + "version" "3.2.1" + dependencies: + "color-convert" "^1.9.0" + +"ansi-styles@^4.0.0", "ansi-styles@^4.1.0": + "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + "version" "4.3.0" + dependencies: + "color-convert" "^2.0.1" + +"anymatch@^3.0.3": + "integrity" "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==" + "resolved" "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + "version" "3.1.3" + dependencies: + "normalize-path" "^3.0.0" + "picomatch" "^2.0.4" + +"appdirsjs@^1.2.4": + "integrity" "sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==" + "resolved" "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.7.tgz" + "version" "1.2.7" + +"argparse@^1.0.7": + "integrity" "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==" + "resolved" "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + "version" "1.0.10" + dependencies: + "sprintf-js" "~1.0.2" + +"argparse@^2.0.1": + "integrity" "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "resolved" "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + "version" "2.0.1" + +"arr-diff@^4.0.0": + "integrity" "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==" + "resolved" "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz" + "version" "4.0.0" + +"arr-flatten@^1.1.0": + "integrity" "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + "resolved" "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz" + "version" "1.1.0" + +"arr-union@^3.1.0": + "integrity" "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==" + "resolved" "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz" + "version" "3.1.0" + +"array-includes@^3.1.5", "array-includes@^3.1.6": + "integrity" "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==" + "resolved" "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz" + "version" "3.1.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + "get-intrinsic" "^1.1.3" + "is-string" "^1.0.7" + +"array-union@^2.1.0": + "integrity" "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + "resolved" "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + "version" "2.1.0" + +"array-unique@^0.3.2": + "integrity" "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==" + "resolved" "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz" + "version" "0.3.2" + +"array.prototype.flat@^1.3.1": + "integrity" "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==" + "resolved" "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz" + "version" "1.3.1" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + "es-shim-unscopables" "^1.0.0" + +"array.prototype.flatmap@^1.3.1": + "integrity" "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==" + "resolved" "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz" + "version" "1.3.1" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + "es-shim-unscopables" "^1.0.0" + +"array.prototype.tosorted@^1.1.1": + "integrity" "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==" + "resolved" "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz" + "version" "1.1.1" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + "es-shim-unscopables" "^1.0.0" + "get-intrinsic" "^1.1.3" + +"asap@~2.0.6": + "integrity" "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + "resolved" "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz" + "version" "2.0.6" + +"asn1.js@^5.2.0": + "integrity" "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==" + "resolved" "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz" + "version" "5.4.1" + dependencies: + "bn.js" "^4.0.0" + "inherits" "^2.0.1" + "minimalistic-assert" "^1.0.0" + "safer-buffer" "^2.1.0" + +"assign-symbols@^1.0.0": + "integrity" "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==" + "resolved" "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz" + "version" "1.0.0" + +"ast-types@0.14.2": + "integrity" "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==" + "resolved" "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz" + "version" "0.14.2" + dependencies: + "tslib" "^2.0.1" + +"astral-regex@^1.0.0": + "integrity" "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" + "resolved" "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz" + "version" "1.0.0" + +"async-limiter@~1.0.0": + "integrity" "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + "resolved" "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz" + "version" "1.0.1" + +"async@^3.2.2": + "integrity" "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + "resolved" "https://registry.npmjs.org/async/-/async-3.2.4.tgz" + "version" "3.2.4" + +"atob@^2.1.2": + "integrity" "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + "resolved" "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz" + "version" "2.1.2" + +"babel-core@^7.0.0-bridge.0": + "integrity" "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==" + "resolved" "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz" + "version" "7.0.0-bridge.0" + +"babel-plugin-module-resolver@^5.0.0": + "integrity" "sha512-g0u+/ChLSJ5+PzYwLwP8Rp8Rcfowz58TJNCe+L/ui4rpzE/mg//JVX0EWBUYoxaextqnwuGHzfGp2hh0PPV25Q==" + "resolved" "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "find-babel-config" "^2.0.0" + "glob" "^8.0.3" + "pkg-up" "^3.1.0" + "reselect" "^4.1.7" + "resolve" "^1.22.1" + +"babel-plugin-polyfill-corejs2@^0.3.3": + "integrity" "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==" + "resolved" "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz" + "version" "0.3.3" + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-define-polyfill-provider" "^0.3.3" + "semver" "^6.1.1" + +"babel-plugin-polyfill-corejs3@^0.6.0": + "integrity" "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==" + "resolved" "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz" + "version" "0.6.0" + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.3" + "core-js-compat" "^3.25.1" + +"babel-plugin-polyfill-regenerator@^0.4.1": + "integrity" "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==" + "resolved" "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz" + "version" "0.4.1" + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.3" + +"babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0": + "integrity" "sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==" + "resolved" "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz" + "version" "7.0.0-beta.0" + +"babel-preset-fbjs@^3.4.0": + "integrity" "sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow==" + "resolved" "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz" + "version" "3.4.0" + dependencies: + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-syntax-class-properties" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-block-scoped-functions" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-for-of" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-member-expression-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-object-super" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-property-literals" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + "babel-plugin-syntax-trailing-function-commas" "^7.0.0-beta.0" + +"balanced-match@^1.0.0": + "integrity" "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + "version" "1.0.2" + +"base-64@^0.1.0": + "integrity" "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + "resolved" "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz" + "version" "0.1.0" + +"base@^0.11.1": + "integrity" "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==" + "resolved" "https://registry.npmjs.org/base/-/base-0.11.2.tgz" + "version" "0.11.2" + dependencies: + "cache-base" "^1.0.1" + "class-utils" "^0.3.5" + "component-emitter" "^1.2.1" + "define-property" "^1.0.0" + "isobject" "^3.0.1" + "mixin-deep" "^1.2.0" + "pascalcase" "^0.1.1" + +"base64-js@^1.1.2", "base64-js@^1.3.1", "base64-js@^1.5.1": + "integrity" "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + "resolved" "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + "version" "1.5.1" + +"bl@^4.1.0": + "integrity" "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==" + "resolved" "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "buffer" "^5.5.0" + "inherits" "^2.0.4" + "readable-stream" "^3.4.0" + +"bn.js@^4.0.0": + "integrity" "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "resolved" "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" + "version" "4.12.0" + +"bn.js@^4.1.0": + "integrity" "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "resolved" "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" + "version" "4.12.0" + +"bn.js@^4.11.9": + "integrity" "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "resolved" "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" + "version" "4.12.0" + +"bn.js@^5.0.0", "bn.js@^5.1.1": + "integrity" "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + "resolved" "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" + "version" "5.2.1" + +"brace-expansion@^1.1.7": + "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==" + "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + "version" "1.1.11" + dependencies: + "balanced-match" "^1.0.0" + "concat-map" "0.0.1" + +"brace-expansion@^2.0.1": + "integrity" "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==" + "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "balanced-match" "^1.0.0" + +"braces@^2.3.1": + "integrity" "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==" + "resolved" "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz" + "version" "2.3.2" + dependencies: + "arr-flatten" "^1.1.0" + "array-unique" "^0.3.2" + "extend-shallow" "^2.0.1" + "fill-range" "^4.0.0" + "isobject" "^3.0.1" + "repeat-element" "^1.1.2" + "snapdragon" "^0.8.1" + "snapdragon-node" "^2.0.1" + "split-string" "^3.0.2" + "to-regex" "^3.0.1" + +"braces@^3.0.2": + "integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==" + "resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "fill-range" "^7.0.1" + +"brorand@^1.0.1", "brorand@^1.1.0": + "integrity" "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + "resolved" "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" + "version" "1.1.0" + +"browserify-aes@^1.0.0", "browserify-aes@^1.0.4": + "integrity" "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==" + "resolved" "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz" + "version" "1.2.0" + dependencies: + "buffer-xor" "^1.0.3" + "cipher-base" "^1.0.0" + "create-hash" "^1.1.0" + "evp_bytestokey" "^1.0.3" + "inherits" "^2.0.1" + "safe-buffer" "^5.0.1" + +"browserify-cipher@^1.0.0": + "integrity" "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==" + "resolved" "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "browserify-aes" "^1.0.4" + "browserify-des" "^1.0.0" + "evp_bytestokey" "^1.0.0" + +"browserify-des@^1.0.0": + "integrity" "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==" + "resolved" "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "cipher-base" "^1.0.1" + "des.js" "^1.0.0" + "inherits" "^2.0.1" + "safe-buffer" "^5.1.2" + +"browserify-rsa@^4.0.0", "browserify-rsa@^4.0.1": + "integrity" "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==" + "resolved" "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "bn.js" "^5.0.0" + "randombytes" "^2.0.1" + +"browserify-sign@^4.0.0": + "integrity" "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==" + "resolved" "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz" + "version" "4.2.1" + dependencies: + "bn.js" "^5.1.1" + "browserify-rsa" "^4.0.1" + "create-hash" "^1.2.0" + "create-hmac" "^1.1.7" + "elliptic" "^6.5.3" + "inherits" "^2.0.4" + "parse-asn1" "^5.1.5" + "readable-stream" "^3.6.0" + "safe-buffer" "^5.2.0" + +"browserslist@^4.21.3", "browserslist@^4.21.4", "browserslist@>= 4.21.0": + "integrity" "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==" + "resolved" "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz" + "version" "4.21.4" + dependencies: + "caniuse-lite" "^1.0.30001400" + "electron-to-chromium" "^1.4.251" + "node-releases" "^2.0.6" + "update-browserslist-db" "^1.0.9" + +"bser@2.1.1": + "integrity" "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==" + "resolved" "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" + "version" "2.1.1" + dependencies: + "node-int64" "^0.4.0" + +"buffer-from@^1.0.0": + "integrity" "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + "resolved" "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + "version" "1.1.2" + +"buffer-xor@^1.0.3": + "integrity" "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + "resolved" "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz" + "version" "1.0.3" + +"buffer@^5.5.0": + "integrity" "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==" + "resolved" "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" + "version" "5.7.1" + dependencies: + "base64-js" "^1.3.1" + "ieee754" "^1.1.13" + +"builtins@^5.0.1": + "integrity" "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==" + "resolved" "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz" + "version" "5.0.1" + dependencies: + "semver" "^7.0.0" + +"bytes@3.0.0": + "integrity" "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + "resolved" "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" + "version" "3.0.0" + +"cache-base@^1.0.1": + "integrity" "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==" + "resolved" "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "collection-visit" "^1.0.0" + "component-emitter" "^1.2.1" + "get-value" "^2.0.6" + "has-value" "^1.0.0" + "isobject" "^3.0.1" + "set-value" "^2.0.0" + "to-object-path" "^0.3.0" + "union-value" "^1.0.0" + "unset-value" "^1.0.0" + +"call-bind@^1.0.0", "call-bind@^1.0.2": + "integrity" "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==" + "resolved" "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "function-bind" "^1.1.1" + "get-intrinsic" "^1.0.2" + +"caller-callsite@^2.0.0": + "integrity" "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==" + "resolved" "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "callsites" "^2.0.0" + +"caller-path@^2.0.0": + "integrity" "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==" + "resolved" "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "caller-callsite" "^2.0.0" + +"callsites@^2.0.0": + "integrity" "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==" + "resolved" "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz" + "version" "2.0.0" + +"callsites@^3.0.0": + "integrity" "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + "resolved" "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + "version" "3.1.0" + +"camelcase@^5.0.0": + "integrity" "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "resolved" "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + "version" "5.3.1" + +"camelcase@^6.0.0": + "integrity" "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + "resolved" "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + "version" "6.3.0" + +"caniuse-lite@^1.0.30001400": + "integrity" "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==" + "resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz" + "version" "1.0.30001431" + +"chalk@^2.0.0": + "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + "version" "2.4.2" + dependencies: + "ansi-styles" "^3.2.1" + "escape-string-regexp" "^1.0.5" + "supports-color" "^5.3.0" + +"chalk@^4.0.0": + "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + "version" "4.1.2" + dependencies: + "ansi-styles" "^4.1.0" + "supports-color" "^7.1.0" + +"chalk@^4.1.0": + "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + "version" "4.1.2" + dependencies: + "ansi-styles" "^4.1.0" + "supports-color" "^7.1.0" + +"chalk@^4.1.2": + "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + "version" "4.1.2" + dependencies: + "ansi-styles" "^4.1.0" + "supports-color" "^7.1.0" + +"ci-info@^2.0.0": + "integrity" "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + "resolved" "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" + "version" "2.0.0" + +"ci-info@^3.2.0": + "integrity" "sha512-up5ggbaDqOqJ4UqLKZ2naVkyqSJQgJi5lwD6b6mM748ysrghDBX0bx/qJTUHzw7zu6Mq4gycviSF5hJnwceD8w==" + "resolved" "https://registry.npmjs.org/ci-info/-/ci-info-3.6.1.tgz" + "version" "3.6.1" + +"cipher-base@^1.0.0", "cipher-base@^1.0.1", "cipher-base@^1.0.3": + "integrity" "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==" + "resolved" "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "inherits" "^2.0.1" + "safe-buffer" "^5.0.1" + +"class-utils@^0.3.5": + "integrity" "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==" + "resolved" "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz" + "version" "0.3.6" + dependencies: + "arr-union" "^3.1.0" + "define-property" "^0.2.5" + "isobject" "^3.0.0" + "static-extend" "^0.1.1" + +"cli-cursor@^3.1.0": + "integrity" "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==" + "resolved" "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "restore-cursor" "^3.1.0" + +"cli-spinners@^2.5.0": + "integrity" "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==" + "resolved" "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz" + "version" "2.7.0" + +"cliui@^6.0.0": + "integrity" "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==" + "resolved" "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "string-width" "^4.2.0" + "strip-ansi" "^6.0.0" + "wrap-ansi" "^6.2.0" + +"cliui@^7.0.2": + "integrity" "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==" + "resolved" "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" + "version" "7.0.4" + dependencies: + "string-width" "^4.2.0" + "strip-ansi" "^6.0.0" + "wrap-ansi" "^7.0.0" + +"clone-deep@^4.0.1": + "integrity" "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==" + "resolved" "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz" + "version" "4.0.1" + dependencies: + "is-plain-object" "^2.0.4" + "kind-of" "^6.0.2" + "shallow-clone" "^3.0.0" + +"clone@^1.0.2": + "integrity" "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" + "resolved" "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz" + "version" "1.0.4" + +"collection-visit@^1.0.0": + "integrity" "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==" + "resolved" "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "map-visit" "^1.0.0" + "object-visit" "^1.0.0" + +"color-convert@^1.9.0": + "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + "version" "1.9.3" + dependencies: + "color-name" "1.1.3" + +"color-convert@^2.0.1": + "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "color-name" "~1.1.4" + +"color-name@~1.1.4": + "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + "version" "1.1.4" + +"color-name@1.1.3": + "integrity" "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + "version" "1.1.3" + +"colorette@^1.0.7": + "integrity" "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==" + "resolved" "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz" + "version" "1.4.0" + +"command-exists@^1.2.8": + "integrity" "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" + "resolved" "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz" + "version" "1.2.9" + +"commander@^9.4.0": + "integrity" "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==" + "resolved" "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz" + "version" "9.4.1" + +"commander@~2.13.0": + "integrity" "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==" + "resolved" "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz" + "version" "2.13.0" + +"commondir@^1.0.1": + "integrity" "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + "resolved" "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" + "version" "1.0.1" + +"component-emitter@^1.2.1": + "integrity" "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + "resolved" "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz" + "version" "1.3.0" + +"compressible@~2.0.16": + "integrity" "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==" + "resolved" "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz" + "version" "2.0.18" + dependencies: + "mime-db" ">= 1.43.0 < 2" + +"compression@^1.7.1": + "integrity" "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==" + "resolved" "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz" + "version" "1.7.4" + dependencies: + "accepts" "~1.3.5" + "bytes" "3.0.0" + "compressible" "~2.0.16" + "debug" "2.6.9" + "on-headers" "~1.0.2" + "safe-buffer" "5.1.2" + "vary" "~1.1.2" + +"concat-map@0.0.1": + "integrity" "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "version" "0.0.1" + +"connect@^3.6.5": + "integrity" "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==" + "resolved" "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz" + "version" "3.7.0" + dependencies: + "debug" "2.6.9" + "finalhandler" "1.1.2" + "parseurl" "~1.3.3" + "utils-merge" "1.0.1" + +"convert-source-map@^1.7.0": + "integrity" "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "resolved" "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" + "version" "1.9.0" + +"copy-descriptor@^0.1.0": + "integrity" "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==" + "resolved" "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz" + "version" "0.1.1" + +"core-js-compat@^3.25.1": + "integrity" "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==" + "resolved" "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz" + "version" "3.26.0" + dependencies: + "browserslist" "^4.21.4" + +"core-util-is@~1.0.0": + "integrity" "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "resolved" "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" + "version" "1.0.3" + +"cosmiconfig@^5.0.5", "cosmiconfig@^5.1.0": + "integrity" "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==" + "resolved" "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz" + "version" "5.2.1" + dependencies: + "import-fresh" "^2.0.0" + "is-directory" "^0.3.1" + "js-yaml" "^3.13.1" + "parse-json" "^4.0.0" + +"create-ecdh@^4.0.0": + "integrity" "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==" + "resolved" "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz" + "version" "4.0.4" + dependencies: + "bn.js" "^4.1.0" + "elliptic" "^6.5.3" + +"create-hash@^1.1.0", "create-hash@^1.1.2", "create-hash@^1.2.0": + "integrity" "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==" + "resolved" "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz" + "version" "1.2.0" + dependencies: + "cipher-base" "^1.0.1" + "inherits" "^2.0.1" + "md5.js" "^1.3.4" + "ripemd160" "^2.0.1" + "sha.js" "^2.4.0" + +"create-hmac@^1.1.0", "create-hmac@^1.1.4", "create-hmac@^1.1.7": + "integrity" "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==" + "resolved" "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz" + "version" "1.1.7" + dependencies: + "cipher-base" "^1.0.3" + "create-hash" "^1.1.0" + "inherits" "^2.0.1" + "ripemd160" "^2.0.0" + "safe-buffer" "^5.0.1" + "sha.js" "^2.4.8" + +"cross-spawn@^6.0.0": + "integrity" "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==" + "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz" + "version" "6.0.5" + dependencies: + "nice-try" "^1.0.4" + "path-key" "^2.0.1" + "semver" "^5.5.0" + "shebang-command" "^1.2.0" + "which" "^1.2.9" + +"cross-spawn@^7.0.2": + "integrity" "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==" + "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + "version" "7.0.3" + dependencies: + "path-key" "^3.1.0" + "shebang-command" "^2.0.0" + "which" "^2.0.1" + +"crypto-browserify@^3.12.0": + "integrity" "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==" + "resolved" "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz" + "version" "3.12.0" + dependencies: + "browserify-cipher" "^1.0.0" + "browserify-sign" "^4.0.0" + "create-ecdh" "^4.0.0" + "create-hash" "^1.1.0" + "create-hmac" "^1.1.0" + "diffie-hellman" "^5.0.0" + "inherits" "^2.0.1" + "pbkdf2" "^3.0.3" + "public-encrypt" "^4.0.0" + "randombytes" "^2.0.0" + "randomfill" "^1.0.3" + +"csstype@^3.0.2": + "integrity" "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + "resolved" "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz" + "version" "3.1.1" + +"dayjs@^1.8.15": + "integrity" "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==" + "resolved" "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz" + "version" "1.11.6" + +"debug@^2.2.0": + "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" + "resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + "version" "2.6.9" + dependencies: + "ms" "2.0.0" + +"debug@^2.3.3": + "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" + "resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + "version" "2.6.9" + dependencies: + "ms" "2.0.0" + +"debug@^3.2.7": + "integrity" "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" + "version" "3.2.7" + dependencies: + "ms" "^2.1.1" + +"debug@^4.1.0", "debug@^4.1.1", "debug@^4.3.2", "debug@^4.3.4", "debug@~4.3.1", "debug@~4.3.2": + "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + "version" "4.3.4" + dependencies: + "ms" "2.1.2" + +"debug@2.6.9": + "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" + "resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + "version" "2.6.9" + dependencies: + "ms" "2.0.0" + +"decamelize@^1.2.0": + "integrity" "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" + "resolved" "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + "version" "1.2.0" + +"decode-uri-component@^0.2.0": + "integrity" "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==" + "resolved" "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz" + "version" "0.2.2" + +"deep-is@^0.1.3": + "integrity" "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + "resolved" "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + "version" "0.1.4" + +"deepmerge@^3.2.0": + "integrity" "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==" + "resolved" "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz" + "version" "3.3.0" + +"defaults@^1.0.3": + "integrity" "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==" + "resolved" "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "clone" "^1.0.2" + +"define-properties@^1.1.3", "define-properties@^1.1.4": + "integrity" "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==" + "resolved" "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz" + "version" "1.1.4" + dependencies: + "has-property-descriptors" "^1.0.0" + "object-keys" "^1.1.1" + +"define-property@^0.2.5": + "integrity" "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==" + "resolved" "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz" + "version" "0.2.5" + dependencies: + "is-descriptor" "^0.1.0" + +"define-property@^1.0.0": + "integrity" "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==" + "resolved" "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "is-descriptor" "^1.0.0" + +"define-property@^2.0.2": + "integrity" "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==" + "resolved" "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "is-descriptor" "^1.0.2" + "isobject" "^3.0.1" + +"denodeify@^1.2.1": + "integrity" "sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==" + "resolved" "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz" + "version" "1.2.1" + +"depd@2.0.0": + "integrity" "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + "resolved" "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" + "version" "2.0.0" + +"des.js@^1.0.0": + "integrity" "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==" + "resolved" "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "inherits" "^2.0.1" + "minimalistic-assert" "^1.0.0" + +"destroy@1.2.0": + "integrity" "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + "resolved" "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" + "version" "1.2.0" + +"diffie-hellman@^5.0.0": + "integrity" "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==" + "resolved" "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz" + "version" "5.0.3" + dependencies: + "bn.js" "^4.1.0" + "miller-rabin" "^4.0.0" + "randombytes" "^2.0.0" + +"dir-glob@^3.0.1": + "integrity" "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==" + "resolved" "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + "version" "3.0.1" + dependencies: + "path-type" "^4.0.0" + +"doctrine@^2.1.0": + "integrity" "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==" + "resolved" "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "esutils" "^2.0.2" + +"doctrine@^3.0.0": + "integrity" "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==" + "resolved" "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "esutils" "^2.0.2" + +"ee-first@1.1.1": + "integrity" "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "resolved" "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" + "version" "1.1.1" + +"electron-to-chromium@^1.4.251": + "integrity" "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + "resolved" "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz" + "version" "1.4.284" + +"elliptic@^6.5.3": + "integrity" "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==" + "resolved" "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" + "version" "6.5.4" + dependencies: + "bn.js" "^4.11.9" + "brorand" "^1.1.0" + "hash.js" "^1.0.0" + "hmac-drbg" "^1.0.1" + "inherits" "^2.0.4" + "minimalistic-assert" "^1.0.1" + "minimalistic-crypto-utils" "^1.0.1" + +"emoji-regex@^8.0.0": + "integrity" "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + "version" "8.0.0" + +"encodeurl@~1.0.2": + "integrity" "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + "resolved" "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" + "version" "1.0.2" + +"end-of-stream@^1.1.0": + "integrity" "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==" + "resolved" "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" + "version" "1.4.4" + dependencies: + "once" "^1.4.0" + +"engine.io-client@~6.4.0": + "integrity" "sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==" + "resolved" "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.4.0.tgz" + "version" "6.4.0" + dependencies: + "@socket.io/component-emitter" "~3.1.0" + "debug" "~4.3.1" + "engine.io-parser" "~5.0.3" + "ws" "~8.11.0" + "xmlhttprequest-ssl" "~2.0.0" + +"engine.io-parser@~5.0.3": + "integrity" "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==" + "resolved" "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz" + "version" "5.0.6" + +"envinfo@^7.7.2": + "integrity" "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==" + "resolved" "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz" + "version" "7.8.1" + +"error-ex@^1.3.1": + "integrity" "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==" + "resolved" "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + "version" "1.3.2" + dependencies: + "is-arrayish" "^0.2.1" + +"error-stack-parser@^2.0.6": + "integrity" "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==" + "resolved" "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz" + "version" "2.1.4" + dependencies: + "stackframe" "^1.3.4" + +"errorhandler@^1.5.0": + "integrity" "sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==" + "resolved" "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.1.tgz" + "version" "1.5.1" + dependencies: + "accepts" "~1.3.7" + "escape-html" "~1.0.3" + +"es-abstract@^1.19.0", "es-abstract@^1.20.4": + "integrity" "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==" + "resolved" "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz" + "version" "1.20.4" + dependencies: + "call-bind" "^1.0.2" + "es-to-primitive" "^1.2.1" + "function-bind" "^1.1.1" + "function.prototype.name" "^1.1.5" + "get-intrinsic" "^1.1.3" + "get-symbol-description" "^1.0.0" + "has" "^1.0.3" + "has-property-descriptors" "^1.0.0" + "has-symbols" "^1.0.3" + "internal-slot" "^1.0.3" + "is-callable" "^1.2.7" + "is-negative-zero" "^2.0.2" + "is-regex" "^1.1.4" + "is-shared-array-buffer" "^1.0.2" + "is-string" "^1.0.7" + "is-weakref" "^1.0.2" + "object-inspect" "^1.12.2" + "object-keys" "^1.1.1" + "object.assign" "^4.1.4" + "regexp.prototype.flags" "^1.4.3" + "safe-regex-test" "^1.0.0" + "string.prototype.trimend" "^1.0.5" + "string.prototype.trimstart" "^1.0.5" + "unbox-primitive" "^1.0.2" + +"es-shim-unscopables@^1.0.0": + "integrity" "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==" + "resolved" "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "has" "^1.0.3" + +"es-to-primitive@^1.2.1": + "integrity" "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==" + "resolved" "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" + "version" "1.2.1" + dependencies: + "is-callable" "^1.1.4" + "is-date-object" "^1.0.1" + "is-symbol" "^1.0.2" + +"escalade@^3.1.1": + "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + "version" "3.1.1" + +"escape-html@~1.0.3": + "integrity" "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "resolved" "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" + "version" "1.0.3" + +"escape-string-regexp@^1.0.5": + "integrity" "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + "version" "1.0.5" + +"escape-string-regexp@^4.0.0": + "integrity" "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + "version" "4.0.0" + +"eslint-config-standard-with-typescript@^34.0.0": + "integrity" "sha512-zhCsI4/A0rJ1ma8sf3RLXYc0gc7yPmdTWRVXMh9dtqeUx3yBQyALH0wosHhk1uQ9QyItynLdNOtcHKNw8G7lQw==" + "resolved" "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-34.0.0.tgz" + "version" "34.0.0" + dependencies: + "@typescript-eslint/parser" "^5.0.0" + "eslint-config-standard" "17.0.0" + +"eslint-config-standard@17.0.0": + "integrity" "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==" + "resolved" "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz" + "version" "17.0.0" + +"eslint-import-resolver-node@^0.3.7": + "integrity" "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==" + "resolved" "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz" + "version" "0.3.7" + dependencies: + "debug" "^3.2.7" + "is-core-module" "^2.11.0" + "resolve" "^1.22.1" + +"eslint-module-utils@^2.7.4": + "integrity" "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==" + "resolved" "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz" + "version" "2.7.4" + dependencies: + "debug" "^3.2.7" + +"eslint-plugin-es@^4.1.0": + "integrity" "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==" + "resolved" "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "eslint-utils" "^2.0.0" + "regexpp" "^3.0.0" + +"eslint-plugin-import@^2.25.2": + "integrity" "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==" + "resolved" "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz" + "version" "2.27.5" + dependencies: + "array-includes" "^3.1.6" + "array.prototype.flat" "^1.3.1" + "array.prototype.flatmap" "^1.3.1" + "debug" "^3.2.7" + "doctrine" "^2.1.0" + "eslint-import-resolver-node" "^0.3.7" + "eslint-module-utils" "^2.7.4" + "has" "^1.0.3" + "is-core-module" "^2.11.0" + "is-glob" "^4.0.3" + "minimatch" "^3.1.2" + "object.values" "^1.1.6" + "resolve" "^1.22.1" + "semver" "^6.3.0" + "tsconfig-paths" "^3.14.1" + +"eslint-plugin-n@^15.0.0": + "integrity" "sha512-R9xw9OtCRxxaxaszTQmQAlPgM+RdGjaL1akWuY/Fv9fRAi8Wj4CUKc6iYVG8QNRjRuo8/BqVYIpfqberJUEacA==" + "resolved" "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.6.1.tgz" + "version" "15.6.1" + dependencies: + "builtins" "^5.0.1" + "eslint-plugin-es" "^4.1.0" + "eslint-utils" "^3.0.0" + "ignore" "^5.1.1" + "is-core-module" "^2.11.0" + "minimatch" "^3.1.2" + "resolve" "^1.22.1" + "semver" "^7.3.8" + +"eslint-plugin-promise@^6.0.0": + "integrity" "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==" + "resolved" "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz" + "version" "6.1.1" + +"eslint-plugin-react-hooks@^4.6.0": + "integrity" "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==" + "resolved" "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz" + "version" "4.6.0" + +"eslint-plugin-react@^7.32.2": + "integrity" "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==" + "resolved" "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz" + "version" "7.32.2" + dependencies: + "array-includes" "^3.1.6" + "array.prototype.flatmap" "^1.3.1" + "array.prototype.tosorted" "^1.1.1" + "doctrine" "^2.1.0" + "estraverse" "^5.3.0" + "jsx-ast-utils" "^2.4.1 || ^3.0.0" + "minimatch" "^3.1.2" + "object.entries" "^1.1.6" + "object.fromentries" "^2.0.6" + "object.hasown" "^1.1.2" + "object.values" "^1.1.6" + "prop-types" "^15.8.1" + "resolve" "^2.0.0-next.4" + "semver" "^6.3.0" + "string.prototype.matchall" "^4.0.8" + +"eslint-scope@^5.1.1": + "integrity" "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==" + "resolved" "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + "version" "5.1.1" + dependencies: + "esrecurse" "^4.3.0" + "estraverse" "^4.1.1" + +"eslint-scope@^7.1.1": + "integrity" "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==" + "resolved" "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz" + "version" "7.1.1" + dependencies: + "esrecurse" "^4.3.0" + "estraverse" "^5.2.0" + +"eslint-utils@^2.0.0": + "integrity" "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==" + "resolved" "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "eslint-visitor-keys" "^1.1.0" + +"eslint-utils@^3.0.0": + "integrity" "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==" + "resolved" "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "eslint-visitor-keys" "^2.0.0" + +"eslint-visitor-keys@^1.1.0": + "integrity" "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + "version" "1.3.0" + +"eslint-visitor-keys@^2.0.0": + "integrity" "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" + "version" "2.1.0" + +"eslint-visitor-keys@^3.3.0": + "integrity" "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==" + "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz" + "version" "3.3.0" + +"eslint@*", "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^7.0.0 || ^8.0.0", "eslint@^8.0.1", "eslint@>=4.19.1", "eslint@>=5", "eslint@>=7.0.0": + "integrity" "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==" + "resolved" "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz" + "version" "8.27.0" + dependencies: + "@eslint/eslintrc" "^1.3.3" + "@humanwhocodes/config-array" "^0.11.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "ajv" "^6.10.0" + "chalk" "^4.0.0" + "cross-spawn" "^7.0.2" + "debug" "^4.3.2" + "doctrine" "^3.0.0" + "escape-string-regexp" "^4.0.0" + "eslint-scope" "^7.1.1" + "eslint-utils" "^3.0.0" + "eslint-visitor-keys" "^3.3.0" + "espree" "^9.4.0" + "esquery" "^1.4.0" + "esutils" "^2.0.2" + "fast-deep-equal" "^3.1.3" + "file-entry-cache" "^6.0.1" + "find-up" "^5.0.0" + "glob-parent" "^6.0.2" + "globals" "^13.15.0" + "grapheme-splitter" "^1.0.4" + "ignore" "^5.2.0" + "import-fresh" "^3.0.0" + "imurmurhash" "^0.1.4" + "is-glob" "^4.0.0" + "is-path-inside" "^3.0.3" + "js-sdsl" "^4.1.4" + "js-yaml" "^4.1.0" + "json-stable-stringify-without-jsonify" "^1.0.1" + "levn" "^0.4.1" + "lodash.merge" "^4.6.2" + "minimatch" "^3.1.2" + "natural-compare" "^1.4.0" + "optionator" "^0.9.1" + "regexpp" "^3.2.0" + "strip-ansi" "^6.0.1" + "strip-json-comments" "^3.1.0" + "text-table" "^0.2.0" + +"espree@^9.4.0": + "integrity" "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==" + "resolved" "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz" + "version" "9.4.1" + dependencies: + "acorn" "^8.8.0" + "acorn-jsx" "^5.3.2" + "eslint-visitor-keys" "^3.3.0" + +"esprima@^4.0.0", "esprima@~4.0.0": + "integrity" "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "resolved" "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + "version" "4.0.1" + +"esquery@^1.4.0": + "integrity" "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==" + "resolved" "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "estraverse" "^5.1.0" + +"esrecurse@^4.3.0": + "integrity" "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==" + "resolved" "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + "version" "4.3.0" + dependencies: + "estraverse" "^5.2.0" + +"estraverse@^4.1.1": + "integrity" "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" + "version" "4.3.0" + +"estraverse@^5.1.0", "estraverse@^5.2.0", "estraverse@^5.3.0": + "integrity" "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + "version" "5.3.0" + +"esutils@^2.0.2": + "integrity" "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "resolved" "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + "version" "2.0.3" + +"etag@~1.8.1": + "integrity" "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + "resolved" "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" + "version" "1.8.1" + +"event-target-shim@^5.0.0", "event-target-shim@^5.0.1": + "integrity" "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + "resolved" "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz" + "version" "5.0.1" + +"events@^3.3.0": + "integrity" "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + "resolved" "https://registry.npmjs.org/events/-/events-3.3.0.tgz" + "version" "3.3.0" + +"evp_bytestokey@^1.0.0", "evp_bytestokey@^1.0.3": + "integrity" "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==" + "resolved" "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz" + "version" "1.0.3" + dependencies: + "md5.js" "^1.3.4" + "safe-buffer" "^5.1.1" + +"execa@^1.0.0": + "integrity" "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==" + "resolved" "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz" + "version" "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" + +"expand-brackets@^2.1.4": + "integrity" "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==" + "resolved" "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz" + "version" "2.1.4" + dependencies: + "debug" "^2.3.3" + "define-property" "^0.2.5" + "extend-shallow" "^2.0.1" + "posix-character-classes" "^0.1.0" + "regex-not" "^1.0.0" + "snapdragon" "^0.8.1" + "to-regex" "^3.0.1" + +"extend-shallow@^2.0.1": + "integrity" "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==" + "resolved" "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "is-extendable" "^0.1.0" + +"extend-shallow@^3.0.0", "extend-shallow@^3.0.2": + "integrity" "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==" + "resolved" "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "assign-symbols" "^1.0.0" + "is-extendable" "^1.0.1" + +"extglob@^2.0.4": + "integrity" "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==" + "resolved" "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz" + "version" "2.0.4" + dependencies: + "array-unique" "^0.3.2" + "define-property" "^1.0.0" + "expand-brackets" "^2.1.4" + "extend-shallow" "^2.0.1" + "fragment-cache" "^0.2.1" + "regex-not" "^1.0.0" + "snapdragon" "^0.8.1" + "to-regex" "^3.0.1" + +"fast-deep-equal@^3.1.1", "fast-deep-equal@^3.1.3": + "integrity" "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "resolved" "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + "version" "3.1.3" + +"fast-glob@^3.2.9": + "integrity" "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==" + "resolved" "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz" + "version" "3.2.12" + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + "glob-parent" "^5.1.2" + "merge2" "^1.3.0" + "micromatch" "^4.0.4" + +"fast-json-stable-stringify@^2.0.0": + "integrity" "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "resolved" "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + "version" "2.1.0" + +"fast-levenshtein@^2.0.6": + "integrity" "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + "resolved" "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + "version" "2.0.6" + +"fastq@^1.6.0": + "integrity" "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==" + "resolved" "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz" + "version" "1.13.0" + dependencies: + "reusify" "^1.0.4" + +"fb-watchman@^2.0.0": + "integrity" "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==" + "resolved" "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "bser" "2.1.1" + +"file-entry-cache@^6.0.1": + "integrity" "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==" + "resolved" "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + "version" "6.0.1" + dependencies: + "flat-cache" "^3.0.4" + +"fill-range@^4.0.0": + "integrity" "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==" + "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "extend-shallow" "^2.0.1" + "is-number" "^3.0.0" + "repeat-string" "^1.6.1" + "to-regex-range" "^2.1.0" + +"fill-range@^7.0.1": + "integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==" + "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + "version" "7.0.1" + dependencies: + "to-regex-range" "^5.0.1" + +"finalhandler@1.1.2": + "integrity" "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==" + "resolved" "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz" + "version" "1.1.2" + dependencies: + "debug" "2.6.9" + "encodeurl" "~1.0.2" + "escape-html" "~1.0.3" + "on-finished" "~2.3.0" + "parseurl" "~1.3.3" + "statuses" "~1.5.0" + "unpipe" "~1.0.0" + +"find-babel-config@^2.0.0": + "integrity" "sha512-dOKT7jvF3hGzlW60Gc3ONox/0rRZ/tz7WCil0bqA1In/3I8f1BctpXahRnEKDySZqci7u+dqq93sZST9fOJpFw==" + "resolved" "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "json5" "^2.1.1" + "path-exists" "^4.0.0" + +"find-cache-dir@^2.0.0": + "integrity" "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==" + "resolved" "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "commondir" "^1.0.1" + "make-dir" "^2.0.0" + "pkg-dir" "^3.0.0" + +"find-up@^3.0.0": + "integrity" "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==" + "resolved" "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "locate-path" "^3.0.0" + +"find-up@^4.1.0": + "integrity" "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==" + "resolved" "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "locate-path" "^5.0.0" + "path-exists" "^4.0.0" + +"find-up@^5.0.0": + "integrity" "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==" + "resolved" "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "locate-path" "^6.0.0" + "path-exists" "^4.0.0" + +"flat-cache@^3.0.4": + "integrity" "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==" + "resolved" "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" + "version" "3.0.4" + dependencies: + "flatted" "^3.1.0" + "rimraf" "^3.0.2" + +"flatted@^3.1.0": + "integrity" "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + "resolved" "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz" + "version" "3.2.7" + +"flow-parser@^0.121.0", "flow-parser@0.*": + "integrity" "sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg==" + "resolved" "https://registry.npmjs.org/flow-parser/-/flow-parser-0.121.0.tgz" + "version" "0.121.0" + +"for-in@^1.0.2": + "integrity" "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==" + "resolved" "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz" + "version" "1.0.2" + +"fragment-cache@^0.2.1": + "integrity" "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==" + "resolved" "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz" + "version" "0.2.1" + dependencies: + "map-cache" "^0.2.2" + +"fresh@0.5.2": + "integrity" "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + "resolved" "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" + "version" "0.5.2" + +"fs-extra@^1.0.0": + "integrity" "sha512-VerQV6vEKuhDWD2HGOybV6v5I73syoc/cXAbKlgTC7M/oFVEtklWlp9QH2Ijw3IaWDOQcMkldSPa7zXy79Z/UQ==" + "resolved" "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "graceful-fs" "^4.1.2" + "jsonfile" "^2.1.0" + "klaw" "^1.0.0" + +"fs-extra@^8.1.0": + "integrity" "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==" + "resolved" "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz" + "version" "8.1.0" + dependencies: + "graceful-fs" "^4.2.0" + "jsonfile" "^4.0.0" + "universalify" "^0.1.0" + +"fs.realpath@^1.0.0": + "integrity" "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + "version" "1.0.0" + +"function-bind@^1.1.1": + "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + "version" "1.1.1" + +"function.prototype.name@^1.1.5": + "integrity" "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==" + "resolved" "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz" + "version" "1.1.5" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.3" + "es-abstract" "^1.19.0" + "functions-have-names" "^1.2.2" + +"functions-have-names@^1.2.2": + "integrity" "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + "resolved" "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + "version" "1.2.3" + +"gensync@^1.0.0-beta.2": + "integrity" "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + "resolved" "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + "version" "1.0.0-beta.2" + +"get-caller-file@^2.0.1", "get-caller-file@^2.0.5": + "integrity" "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + "resolved" "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + "version" "2.0.5" + +"get-intrinsic@^1.0.2", "get-intrinsic@^1.1.0", "get-intrinsic@^1.1.1", "get-intrinsic@^1.1.3": + "integrity" "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==" + "resolved" "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz" + "version" "1.1.3" + dependencies: + "function-bind" "^1.1.1" + "has" "^1.0.3" + "has-symbols" "^1.0.3" + +"get-stream@^4.0.0": + "integrity" "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==" + "resolved" "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "pump" "^3.0.0" + +"get-symbol-description@^1.0.0": + "integrity" "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==" + "resolved" "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "call-bind" "^1.0.2" + "get-intrinsic" "^1.1.1" + +"get-value@^2.0.3", "get-value@^2.0.6": + "integrity" "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==" + "resolved" "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz" + "version" "2.0.6" + +"glob-parent@^5.1.2": + "integrity" "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==" + "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + "version" "5.1.2" + dependencies: + "is-glob" "^4.0.1" + +"glob-parent@^6.0.2": + "integrity" "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==" + "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + "version" "6.0.2" + dependencies: + "is-glob" "^4.0.3" + +"glob@^7.1.3": + "integrity" "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==" + "resolved" "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + "version" "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" + +"glob@^8.0.3": + "integrity" "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==" + "resolved" "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz" + "version" "8.1.0" + dependencies: + "fs.realpath" "^1.0.0" + "inflight" "^1.0.4" + "inherits" "2" + "minimatch" "^5.0.1" + "once" "^1.3.0" + +"globals@^11.1.0": + "integrity" "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "resolved" "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + "version" "11.12.0" + +"globals@^13.15.0": + "integrity" "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==" + "resolved" "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz" + "version" "13.17.0" + dependencies: + "type-fest" "^0.20.2" + +"globby@^11.1.0": + "integrity" "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==" + "resolved" "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + "version" "11.1.0" + dependencies: + "array-union" "^2.1.0" + "dir-glob" "^3.0.1" + "fast-glob" "^3.2.9" + "ignore" "^5.2.0" + "merge2" "^1.4.1" + "slash" "^3.0.0" + +"graceful-fs@^4.1.11", "graceful-fs@^4.1.2", "graceful-fs@^4.1.3", "graceful-fs@^4.1.6", "graceful-fs@^4.1.9", "graceful-fs@^4.2.0", "graceful-fs@^4.2.4", "graceful-fs@^4.2.9": + "integrity" "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" + "version" "4.2.10" + +"grapheme-splitter@^1.0.4": + "integrity" "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + "resolved" "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz" + "version" "1.0.4" + +"has-bigints@^1.0.1", "has-bigints@^1.0.2": + "integrity" "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" + "resolved" "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" + "version" "1.0.2" + +"has-flag@^3.0.0": + "integrity" "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + "version" "3.0.0" + +"has-flag@^4.0.0": + "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + "version" "4.0.0" + +"has-property-descriptors@^1.0.0": + "integrity" "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==" + "resolved" "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "get-intrinsic" "^1.1.1" + +"has-symbols@^1.0.2", "has-symbols@^1.0.3": + "integrity" "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "resolved" "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + "version" "1.0.3" + +"has-tostringtag@^1.0.0": + "integrity" "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==" + "resolved" "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "has-symbols" "^1.0.2" + +"has-value@^0.3.1": + "integrity" "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==" + "resolved" "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz" + "version" "0.3.1" + dependencies: + "get-value" "^2.0.3" + "has-values" "^0.1.4" + "isobject" "^2.0.0" + +"has-value@^1.0.0": + "integrity" "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==" + "resolved" "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "get-value" "^2.0.6" + "has-values" "^1.0.0" + "isobject" "^3.0.0" + +"has-values@^0.1.4": + "integrity" "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==" + "resolved" "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz" + "version" "0.1.4" + +"has-values@^1.0.0": + "integrity" "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==" + "resolved" "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "is-number" "^3.0.0" + "kind-of" "^4.0.0" + +"has@^1.0.3": + "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" + "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + "version" "1.0.3" + dependencies: + "function-bind" "^1.1.1" + +"hash-base@^3.0.0": + "integrity" "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==" + "resolved" "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "inherits" "^2.0.4" + "readable-stream" "^3.6.0" + "safe-buffer" "^5.2.0" + +"hash.js@^1.0.0", "hash.js@^1.0.3": + "integrity" "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==" + "resolved" "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" + "version" "1.1.7" + dependencies: + "inherits" "^2.0.3" + "minimalistic-assert" "^1.0.1" + +"hermes-estree@0.8.0": + "integrity" "sha512-W6JDAOLZ5pMPMjEiQGLCXSSV7pIBEgRR5zGkxgmzGSXHOxqV5dC/M1Zevqpbm9TZDE5tu358qZf8Vkzmsc+u7Q==" + "resolved" "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.8.0.tgz" + "version" "0.8.0" + +"hermes-parser@0.8.0": + "integrity" "sha512-yZKalg1fTYG5eOiToLUaw69rQfZq/fi+/NtEXRU7N87K/XobNRhRWorh80oSge2lWUiZfTgUvRJH+XgZWrhoqA==" + "resolved" "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.8.0.tgz" + "version" "0.8.0" + dependencies: + "hermes-estree" "0.8.0" + +"hermes-profile-transformer@^0.0.6": + "integrity" "sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==" + "resolved" "https://registry.npmjs.org/hermes-profile-transformer/-/hermes-profile-transformer-0.0.6.tgz" + "version" "0.0.6" + dependencies: + "source-map" "^0.7.3" + +"hmac-drbg@^1.0.1": + "integrity" "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==" + "resolved" "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "hash.js" "^1.0.3" + "minimalistic-assert" "^1.0.0" + "minimalistic-crypto-utils" "^1.0.1" + +"hoist-non-react-statics@3.x.x": + "integrity" "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==" + "resolved" "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" + "version" "3.3.2" + dependencies: + "react-is" "^16.7.0" + +"http-errors@2.0.0": + "integrity" "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==" + "resolved" "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "depd" "2.0.0" + "inherits" "2.0.4" + "setprototypeof" "1.2.0" + "statuses" "2.0.1" + "toidentifier" "1.0.1" + +"iconv-lite@^0.6.3": + "integrity" "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==" + "resolved" "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" + "version" "0.6.3" + dependencies: + "safer-buffer" ">= 2.1.2 < 3.0.0" + +"ieee754@^1.1.13", "ieee754@^1.2.1": + "integrity" "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + "resolved" "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" + "version" "1.2.1" + +"ignore@^5.1.1", "ignore@^5.2.0": + "integrity" "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" + "resolved" "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" + "version" "5.2.0" + +"image-size@^0.6.0": + "integrity" "sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA==" + "resolved" "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz" + "version" "0.6.3" + +"import-fresh@^2.0.0": + "integrity" "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==" + "resolved" "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "caller-path" "^2.0.0" + "resolve-from" "^3.0.0" + +"import-fresh@^3.0.0", "import-fresh@^3.2.1": + "integrity" "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==" + "resolved" "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + "version" "3.3.0" + dependencies: + "parent-module" "^1.0.0" + "resolve-from" "^4.0.0" + +"imurmurhash@^0.1.4": + "integrity" "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + "resolved" "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + "version" "0.1.4" + +"inflight@^1.0.4": + "integrity" "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==" + "resolved" "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + "version" "1.0.6" + dependencies: + "once" "^1.3.0" + "wrappy" "1" + +"inherits@^2.0.1", "inherits@^2.0.3", "inherits@^2.0.4", "inherits@~2.0.3", "inherits@~2.0.4", "inherits@2", "inherits@2.0.4": + "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + "version" "2.0.4" + +"internal-slot@^1.0.3": + "integrity" "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==" + "resolved" "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz" + "version" "1.0.3" + dependencies: + "get-intrinsic" "^1.1.0" + "has" "^1.0.3" + "side-channel" "^1.0.4" + +"invariant@^2.2.4": + "integrity" "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==" + "resolved" "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" + "version" "2.2.4" + dependencies: + "loose-envify" "^1.0.0" + +"ip@^1.1.5": + "integrity" "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + "resolved" "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz" + "version" "1.1.8" + +"is-accessor-descriptor@^0.1.6": + "integrity" "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==" + "resolved" "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz" + "version" "0.1.6" + dependencies: + "kind-of" "^3.0.2" + +"is-accessor-descriptor@^1.0.0": + "integrity" "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==" + "resolved" "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "kind-of" "^6.0.0" + +"is-arrayish@^0.2.1": + "integrity" "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + "resolved" "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + "version" "0.2.1" + +"is-bigint@^1.0.1": + "integrity" "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==" + "resolved" "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "has-bigints" "^1.0.1" + +"is-boolean-object@^1.1.0": + "integrity" "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==" + "resolved" "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" + "version" "1.1.2" + dependencies: + "call-bind" "^1.0.2" + "has-tostringtag" "^1.0.0" + +"is-buffer@^1.1.5": + "integrity" "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "resolved" "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + "version" "1.1.6" + +"is-callable@^1.1.4", "is-callable@^1.2.7": + "integrity" "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + "resolved" "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + "version" "1.2.7" + +"is-core-module@^2.11.0", "is-core-module@^2.9.0": + "integrity" "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==" + "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz" + "version" "2.11.0" + dependencies: + "has" "^1.0.3" + +"is-data-descriptor@^0.1.4": + "integrity" "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==" + "resolved" "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz" + "version" "0.1.4" + dependencies: + "kind-of" "^3.0.2" + +"is-data-descriptor@^1.0.0": + "integrity" "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==" + "resolved" "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "kind-of" "^6.0.0" + +"is-date-object@^1.0.1": + "integrity" "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==" + "resolved" "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" + "version" "1.0.5" + dependencies: + "has-tostringtag" "^1.0.0" + +"is-descriptor@^0.1.0": + "integrity" "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==" + "resolved" "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz" + "version" "0.1.6" + dependencies: + "is-accessor-descriptor" "^0.1.6" + "is-data-descriptor" "^0.1.4" + "kind-of" "^5.0.0" + +"is-descriptor@^1.0.0", "is-descriptor@^1.0.2": + "integrity" "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==" + "resolved" "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "is-accessor-descriptor" "^1.0.0" + "is-data-descriptor" "^1.0.0" + "kind-of" "^6.0.2" + +"is-directory@^0.3.1": + "integrity" "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==" + "resolved" "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz" + "version" "0.3.1" + +"is-extendable@^0.1.0", "is-extendable@^0.1.1": + "integrity" "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + "resolved" "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" + "version" "0.1.1" + +"is-extendable@^0.1.1": + "integrity" "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + "resolved" "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" + "version" "0.1.1" + +"is-extendable@^1.0.1": + "integrity" "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==" + "resolved" "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "is-plain-object" "^2.0.4" + +"is-extglob@^2.1.1": + "integrity" "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + "resolved" "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + "version" "2.1.1" + +"is-fullwidth-code-point@^2.0.0": + "integrity" "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" + "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz" + "version" "2.0.0" + +"is-fullwidth-code-point@^3.0.0": + "integrity" "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + "version" "3.0.0" + +"is-glob@^4.0.0", "is-glob@^4.0.1", "is-glob@^4.0.3": + "integrity" "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==" + "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + "version" "4.0.3" + dependencies: + "is-extglob" "^2.1.1" + +"is-interactive@^1.0.0": + "integrity" "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" + "resolved" "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz" + "version" "1.0.0" + +"is-negative-zero@^2.0.2": + "integrity" "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" + "resolved" "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" + "version" "2.0.2" + +"is-number-object@^1.0.4": + "integrity" "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==" + "resolved" "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" + "version" "1.0.7" + dependencies: + "has-tostringtag" "^1.0.0" + +"is-number@^3.0.0": + "integrity" "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==" + "resolved" "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "kind-of" "^3.0.2" + +"is-number@^7.0.0": + "integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + "version" "7.0.0" + +"is-path-inside@^3.0.3": + "integrity" "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" + "resolved" "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" + "version" "3.0.3" + +"is-plain-obj@^2.1.0": + "integrity" "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + "resolved" "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" + "version" "2.1.0" + +"is-plain-object@^2.0.3", "is-plain-object@^2.0.4": + "integrity" "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==" + "resolved" "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" + "version" "2.0.4" + dependencies: + "isobject" "^3.0.1" + +"is-regex@^1.1.4": + "integrity" "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==" + "resolved" "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" + "version" "1.1.4" + dependencies: + "call-bind" "^1.0.2" + "has-tostringtag" "^1.0.0" + +"is-shared-array-buffer@^1.0.2": + "integrity" "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==" + "resolved" "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "call-bind" "^1.0.2" + +"is-stream@^1.1.0": + "integrity" "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==" + "resolved" "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz" + "version" "1.1.0" + +"is-string@^1.0.5", "is-string@^1.0.7": + "integrity" "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==" + "resolved" "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" + "version" "1.0.7" + dependencies: + "has-tostringtag" "^1.0.0" + +"is-symbol@^1.0.2", "is-symbol@^1.0.3": + "integrity" "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==" + "resolved" "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "has-symbols" "^1.0.2" + +"is-unicode-supported@^0.1.0": + "integrity" "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + "resolved" "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" + "version" "0.1.0" + +"is-weakref@^1.0.2": + "integrity" "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==" + "resolved" "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "call-bind" "^1.0.2" + +"is-windows@^1.0.2": + "integrity" "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + "resolved" "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz" + "version" "1.0.2" + +"is-wsl@^1.1.0": + "integrity" "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==" + "resolved" "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz" + "version" "1.1.0" + +"isarray@~1.0.0", "isarray@1.0.0": + "integrity" "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "resolved" "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + "version" "1.0.0" + +"isexe@^2.0.0": + "integrity" "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + "version" "2.0.0" + +"isobject@^2.0.0": + "integrity" "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==" + "resolved" "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "isarray" "1.0.0" + +"isobject@^3.0.0", "isobject@^3.0.1": + "integrity" "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + "resolved" "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + "version" "3.0.1" + +"jest-get-type@^26.3.0": + "integrity" "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==" + "resolved" "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz" + "version" "26.3.0" + +"jest-regex-util@^27.0.6": + "integrity" "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==" + "resolved" "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz" + "version" "27.5.1" + +"jest-serializer@^27.0.6": + "integrity" "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==" + "resolved" "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz" + "version" "27.5.1" + dependencies: + "@types/node" "*" + "graceful-fs" "^4.2.9" + +"jest-util@^27.2.0": + "integrity" "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==" + "resolved" "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz" + "version" "27.5.1" + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + "chalk" "^4.0.0" + "ci-info" "^3.2.0" + "graceful-fs" "^4.2.9" + "picomatch" "^2.2.3" + +"jest-validate@^26.5.2": + "integrity" "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==" + "resolved" "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz" + "version" "26.6.2" + dependencies: + "@jest/types" "^26.6.2" + "camelcase" "^6.0.0" + "chalk" "^4.0.0" + "jest-get-type" "^26.3.0" + "leven" "^3.1.0" + "pretty-format" "^26.6.2" + +"jest-worker@^27.2.0": + "integrity" "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==" + "resolved" "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz" + "version" "27.5.1" + dependencies: + "@types/node" "*" + "merge-stream" "^2.0.0" + "supports-color" "^8.0.0" + +"joi@^17.2.1": + "integrity" "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==" + "resolved" "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz" + "version" "17.7.0" + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" + +"js-sdsl@^4.1.4": + "integrity" "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==" + "resolved" "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz" + "version" "4.1.5" + +"js-tokens@^3.0.0 || ^4.0.0", "js-tokens@^4.0.0": + "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + "version" "4.0.0" + +"js-yaml@^3.13.1": + "integrity" "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==" + "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + "version" "3.14.1" + dependencies: + "argparse" "^1.0.7" + "esprima" "^4.0.0" + +"js-yaml@^4.1.0": + "integrity" "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==" + "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "argparse" "^2.0.1" + +"jsc-android@^250230.2.1": + "integrity" "sha512-KmxeBlRjwoqCnBBKGsihFtvsBHyUFlBxJPK4FzeYcIuBfdjv6jFys44JITAgSTbQD+vIdwMEfyZklsuQX0yI1Q==" + "resolved" "https://registry.npmjs.org/jsc-android/-/jsc-android-250230.2.1.tgz" + "version" "250230.2.1" + +"jscodeshift@^0.13.1": + "integrity" "sha512-lGyiEbGOvmMRKgWk4vf+lUrCWO/8YR8sUR3FKF1Cq5fovjZDlIcw3Hu5ppLHAnEXshVffvaM0eyuY/AbOeYpnQ==" + "resolved" "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.13.1.tgz" + "version" "0.13.1" + dependencies: + "@babel/core" "^7.13.16" + "@babel/parser" "^7.13.16" + "@babel/plugin-proposal-class-properties" "^7.13.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.13.8" + "@babel/plugin-proposal-optional-chaining" "^7.13.12" + "@babel/plugin-transform-modules-commonjs" "^7.13.8" + "@babel/preset-flow" "^7.13.13" + "@babel/preset-typescript" "^7.13.0" + "@babel/register" "^7.13.16" + "babel-core" "^7.0.0-bridge.0" + "chalk" "^4.1.2" + "flow-parser" "0.*" + "graceful-fs" "^4.2.4" + "micromatch" "^3.1.10" + "neo-async" "^2.5.0" + "node-dir" "^0.1.17" + "recast" "^0.20.4" + "temp" "^0.8.4" + "write-file-atomic" "^2.3.0" + +"jsesc@^2.5.1": + "integrity" "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + "version" "2.5.2" + +"jsesc@~0.5.0": + "integrity" "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" + "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" + "version" "0.5.0" + +"json-parse-better-errors@^1.0.1": + "integrity" "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + "resolved" "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz" + "version" "1.0.2" + +"json-schema-traverse@^0.4.1": + "integrity" "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "resolved" "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + "version" "0.4.1" + +"json-stable-stringify-without-jsonify@^1.0.1": + "integrity" "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + "resolved" "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + "version" "1.0.1" + +"json5@^1.0.1": + "integrity" "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==" + "resolved" "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "minimist" "^1.2.0" + +"json5@^2.1.1", "json5@^2.2.2": + "integrity" "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + "resolved" "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + "version" "2.2.3" + +"jsonfile@^2.1.0": + "integrity" "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==" + "resolved" "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz" + "version" "2.4.0" + optionalDependencies: + "graceful-fs" "^4.1.6" + +"jsonfile@^4.0.0": + "integrity" "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==" + "resolved" "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz" + "version" "4.0.0" + optionalDependencies: + "graceful-fs" "^4.1.6" + +"jsx-ast-utils@^2.4.1 || ^3.0.0": + "integrity" "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==" + "resolved" "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz" + "version" "3.3.3" + dependencies: + "array-includes" "^3.1.5" + "object.assign" "^4.1.3" + +"kind-of@^3.0.2", "kind-of@^3.0.3": + "integrity" "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==" + "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" + "version" "3.2.2" + dependencies: + "is-buffer" "^1.1.5" + +"kind-of@^3.2.0": + "integrity" "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==" + "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" + "version" "3.2.2" + dependencies: + "is-buffer" "^1.1.5" + +"kind-of@^4.0.0": + "integrity" "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==" + "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "is-buffer" "^1.1.5" + +"kind-of@^5.0.0": + "integrity" "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz" + "version" "5.1.0" + +"kind-of@^6.0.0", "kind-of@^6.0.2": + "integrity" "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" + "version" "6.0.3" + +"klaw@^1.0.0": + "integrity" "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==" + "resolved" "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz" + "version" "1.3.1" + optionalDependencies: + "graceful-fs" "^4.1.9" + +"kleur@^3.0.3": + "integrity" "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + "resolved" "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" + "version" "3.0.3" + +"leven@^3.1.0": + "integrity" "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + "resolved" "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" + "version" "3.1.0" + +"levn@^0.4.1": + "integrity" "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==" + "resolved" "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + "version" "0.4.1" + dependencies: + "prelude-ls" "^1.2.1" + "type-check" "~0.4.0" + +"locate-path@^3.0.0": + "integrity" "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==" + "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "p-locate" "^3.0.0" + "path-exists" "^3.0.0" + +"locate-path@^5.0.0": + "integrity" "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==" + "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "p-locate" "^4.1.0" + +"locate-path@^6.0.0": + "integrity" "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==" + "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "p-locate" "^5.0.0" + +"lodash.debounce@^4.0.8": + "integrity" "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + "resolved" "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" + "version" "4.0.8" + +"lodash.merge@^4.6.2": + "integrity" "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + "resolved" "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + "version" "4.6.2" + +"lodash.throttle@^4.1.1": + "integrity" "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" + "resolved" "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz" + "version" "4.1.1" + +"lodash@4.17.x": + "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + "version" "4.17.21" + +"log-symbols@^4.1.0": + "integrity" "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==" + "resolved" "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "chalk" "^4.1.0" + "is-unicode-supported" "^0.1.0" + +"logkitty@^0.7.1": + "integrity" "sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==" + "resolved" "https://registry.npmjs.org/logkitty/-/logkitty-0.7.1.tgz" + "version" "0.7.1" + dependencies: + "ansi-fragments" "^0.2.1" + "dayjs" "^1.8.15" + "yargs" "^15.1.0" + +"loose-envify@^1.0.0", "loose-envify@^1.1.0", "loose-envify@^1.4.0": + "integrity" "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==" + "resolved" "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "js-tokens" "^3.0.0 || ^4.0.0" + +"lrc-file-parser@^2.3.0": + "integrity" "sha512-EX+Dnvwqgb8q3mf7WYIR4flOzwrOp9vE2MU+eyRZO0rFUF5BIZgN52SSGXFhfnHd5tUmo7VnLrpCFdURe3O2KQ==" + "resolved" "https://registry.npmjs.org/lrc-file-parser/-/lrc-file-parser-2.3.0.tgz" + "version" "2.3.0" + +"lru-cache@^5.1.1": + "integrity" "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==" + "resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + "version" "5.1.1" + dependencies: + "yallist" "^3.0.2" + +"lru-cache@^6.0.0": + "integrity" "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==" + "resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "yallist" "^4.0.0" + +"make-dir@^2.0.0", "make-dir@^2.1.0": + "integrity" "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==" + "resolved" "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "pify" "^4.0.1" + "semver" "^5.6.0" + +"makeerror@1.0.12": + "integrity" "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==" + "resolved" "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" + "version" "1.0.12" + dependencies: + "tmpl" "1.0.5" + +"map-cache@^0.2.2": + "integrity" "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==" + "resolved" "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz" + "version" "0.2.2" + +"map-visit@^1.0.0": + "integrity" "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==" + "resolved" "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "object-visit" "^1.0.0" + +"md5.js@^1.3.4": + "integrity" "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==" + "resolved" "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz" + "version" "1.3.5" + dependencies: + "hash-base" "^3.0.0" + "inherits" "^2.0.1" + "safe-buffer" "^5.1.2" + +"memoize-one@^5.0.0": + "integrity" "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + "resolved" "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz" + "version" "5.2.1" + +"merge-options@^3.0.4": + "integrity" "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==" + "resolved" "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz" + "version" "3.0.4" + dependencies: + "is-plain-obj" "^2.1.0" + +"merge-stream@^2.0.0": + "integrity" "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "resolved" "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + "version" "2.0.0" + +"merge2@^1.3.0", "merge2@^1.4.1": + "integrity" "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + "resolved" "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + "version" "1.4.1" + +"metro-babel-transformer@0.72.3": + "integrity" "sha512-PTOR2zww0vJbWeeM3qN90WKENxCLzv9xrwWaNtwVlhcV8/diNdNe82sE1xIxLFI6OQuAVwNMv1Y7VsO2I7Ejrw==" + "resolved" "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "@babel/core" "^7.14.0" + "hermes-parser" "0.8.0" + "metro-source-map" "0.72.3" + "nullthrows" "^1.1.1" + +"metro-cache-key@0.72.3": + "integrity" "sha512-kQzmF5s3qMlzqkQcDwDxrOaVxJ2Bh6WRXWdzPnnhsq9LcD3B3cYqQbRBS+3tSuXmathb4gsOdhWslOuIsYS8Rg==" + "resolved" "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.72.3.tgz" + "version" "0.72.3" + +"metro-cache@0.72.3": + "integrity" "sha512-++eyZzwkXvijWRV3CkDbueaXXGlVzH9GA52QWqTgAOgSHYp5jWaDwLQ8qpsMkQzpwSyIF4LLK9aI3eA7Xa132A==" + "resolved" "https://registry.npmjs.org/metro-cache/-/metro-cache-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "metro-core" "0.72.3" + "rimraf" "^2.5.4" + +"metro-config@0.72.3": + "integrity" "sha512-VEsAIVDkrIhgCByq8HKTWMBjJG6RlYwWSu1Gnv3PpHa0IyTjKJtB7wC02rbTjSaemcr82scldf2R+h6ygMEvsw==" + "resolved" "https://registry.npmjs.org/metro-config/-/metro-config-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "cosmiconfig" "^5.0.5" + "jest-validate" "^26.5.2" + "metro" "0.72.3" + "metro-cache" "0.72.3" + "metro-core" "0.72.3" + "metro-runtime" "0.72.3" + +"metro-core@0.72.3": + "integrity" "sha512-KuYWBMmLB4+LxSMcZ1dmWabVExNCjZe3KysgoECAIV+wyIc2r4xANq15GhS94xYvX1+RqZrxU1pa0jQ5OK+/6A==" + "resolved" "https://registry.npmjs.org/metro-core/-/metro-core-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "lodash.throttle" "^4.1.1" + "metro-resolver" "0.72.3" + +"metro-file-map@0.72.3": + "integrity" "sha512-LhuRnuZ2i2uxkpFsz1XCDIQSixxBkBG7oICAFyLyEMDGbcfeY6/NexphfLdJLTghkaoJR5ARFMiIxUg9fIY/pA==" + "resolved" "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "abort-controller" "^3.0.0" + "anymatch" "^3.0.3" + "debug" "^2.2.0" + "fb-watchman" "^2.0.0" + "graceful-fs" "^4.2.4" + "invariant" "^2.2.4" + "jest-regex-util" "^27.0.6" + "jest-serializer" "^27.0.6" + "jest-util" "^27.2.0" + "jest-worker" "^27.2.0" + "micromatch" "^4.0.4" + "walker" "^1.0.7" + optionalDependencies: + "fsevents" "^2.1.2" + +"metro-hermes-compiler@0.72.3": + "integrity" "sha512-QWDQASMiXNW3j8uIQbzIzCdGYv5PpAX/ZiF4/lTWqKRWuhlkP4auhVY4eqdAKj5syPx45ggpjkVE0p8hAPDZYg==" + "resolved" "https://registry.npmjs.org/metro-hermes-compiler/-/metro-hermes-compiler-0.72.3.tgz" + "version" "0.72.3" + +"metro-inspector-proxy@0.72.3": + "integrity" "sha512-UPFkaq2k93RaOi+eqqt7UUmqy2ywCkuxJLasQ55+xavTUS+TQSyeTnTczaYn+YKw+izLTLllGcvqnQcZiWYhGw==" + "resolved" "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "connect" "^3.6.5" + "debug" "^2.2.0" + "ws" "^7.5.1" + "yargs" "^15.3.1" + +"metro-minify-uglify@0.72.3": + "integrity" "sha512-dPXqtMI8TQcj0g7ZrdhC8X3mx3m3rtjtMuHKGIiEXH9CMBvrET8IwrgujQw2rkPcXiSiX8vFDbGMIlfxefDsKA==" + "resolved" "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "uglify-es" "^3.1.9" + +"metro-react-native-babel-preset@0.72.3": + "integrity" "sha512-uJx9y/1NIqoYTp6ZW1osJ7U5ZrXGAJbOQ/Qzl05BdGYvN1S7Qmbzid6xOirgK0EIT0pJKEEh1s8qbassYZe4cw==" + "resolved" "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "@babel/core" "^7.14.0" + "@babel/plugin-proposal-async-generator-functions" "^7.0.0" + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-export-default-from" "^7.0.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" + "@babel/plugin-proposal-optional-chaining" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.0.0" + "@babel/plugin-syntax-export-default-from" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.2.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-syntax-optional-chaining" "^7.0.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-async-to-generator" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-exponentiation-operator" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-react-jsx-self" "^7.0.0" + "@babel/plugin-transform-react-jsx-source" "^7.0.0" + "@babel/plugin-transform-runtime" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-sticky-regex" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.5.0" + "@babel/plugin-transform-unicode-regex" "^7.0.0" + "@babel/template" "^7.0.0" + "react-refresh" "^0.4.0" + +"metro-react-native-babel-transformer@0.72.3": + "integrity" "sha512-Ogst/M6ujYrl/+9mpEWqE3zF7l2mTuftDTy3L8wZYwX1pWUQWQpfU1aJBeWiLxt1XlIq+uriRjKzKoRoIK57EA==" + "resolved" "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "@babel/core" "^7.14.0" + "babel-preset-fbjs" "^3.4.0" + "hermes-parser" "0.8.0" + "metro-babel-transformer" "0.72.3" + "metro-react-native-babel-preset" "0.72.3" + "metro-source-map" "0.72.3" + "nullthrows" "^1.1.1" + +"metro-resolver@0.72.3": + "integrity" "sha512-wu9zSMGdxpKmfECE7FtCdpfC+vrWGTdVr57lDA0piKhZV6VN6acZIvqQ1yZKtS2WfKsngncv5VbB8Y5eHRQP3w==" + "resolved" "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "absolute-path" "^0.0.0" + +"metro-runtime@0.72.3": + "integrity" "sha512-3MhvDKfxMg2u7dmTdpFOfdR71NgNNo4tzAyJumDVQKwnHYHN44f2QFZQqpPBEmqhWlojNeOxsqFsjYgeyMx6VA==" + "resolved" "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "@babel/runtime" "^7.0.0" + "react-refresh" "^0.4.0" + +"metro-source-map@0.72.3": + "integrity" "sha512-eNtpjbjxSheXu/jYCIDrbNEKzMGOvYW6/ePYpRM7gDdEagUOqKOCsi3St8NJIQJzZCsxD2JZ2pYOiomUSkT1yQ==" + "resolved" "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.0.0" + "invariant" "^2.2.4" + "metro-symbolicate" "0.72.3" + "nullthrows" "^1.1.1" + "ob1" "0.72.3" + "source-map" "^0.5.6" + "vlq" "^1.0.0" + +"metro-symbolicate@0.72.3": + "integrity" "sha512-eXG0NX2PJzJ/jTG4q5yyYeN2dr1cUqUaY7worBB0SP5bRWRc3besfb+rXwfh49wTFiL5qR0oOawkU4ZiD4eHXw==" + "resolved" "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "invariant" "^2.2.4" + "metro-source-map" "0.72.3" + "nullthrows" "^1.1.1" + "source-map" "^0.5.6" + "through2" "^2.0.1" + "vlq" "^1.0.0" + +"metro-transform-plugins@0.72.3": + "integrity" "sha512-D+TcUvCKZbRua1+qujE0wV1onZvslW6cVTs7dLCyC2pv20lNHjFr1GtW01jN2fyKR2PcRyMjDCppFd9VwDKnSg==" + "resolved" "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "@babel/core" "^7.14.0" + "@babel/generator" "^7.14.0" + "@babel/template" "^7.0.0" + "@babel/traverse" "^7.14.0" + "nullthrows" "^1.1.1" + +"metro-transform-worker@0.72.3": + "integrity" "sha512-WsuWj9H7i6cHuJuy+BgbWht9DK5FOgJxHLGAyULD5FJdTG9rSMFaHDO5WfC0OwQU5h4w6cPT40iDuEGksM7+YQ==" + "resolved" "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "@babel/core" "^7.14.0" + "@babel/generator" "^7.14.0" + "@babel/parser" "^7.14.0" + "@babel/types" "^7.0.0" + "babel-preset-fbjs" "^3.4.0" + "metro" "0.72.3" + "metro-babel-transformer" "0.72.3" + "metro-cache" "0.72.3" + "metro-cache-key" "0.72.3" + "metro-hermes-compiler" "0.72.3" + "metro-source-map" "0.72.3" + "metro-transform-plugins" "0.72.3" + "nullthrows" "^1.1.1" + +"metro@0.72.3": + "integrity" "sha512-Hb3xTvPqex8kJ1hutQNZhQadUKUwmns/Du9GikmWKBFrkiG3k3xstGAyO5t5rN9JSUEzQT6y9SWzSSOGogUKIg==" + "resolved" "https://registry.npmjs.org/metro/-/metro-0.72.3.tgz" + "version" "0.72.3" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/core" "^7.14.0" + "@babel/generator" "^7.14.0" + "@babel/parser" "^7.14.0" + "@babel/template" "^7.0.0" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.0.0" + "absolute-path" "^0.0.0" + "accepts" "^1.3.7" + "async" "^3.2.2" + "chalk" "^4.0.0" + "ci-info" "^2.0.0" + "connect" "^3.6.5" + "debug" "^2.2.0" + "denodeify" "^1.2.1" + "error-stack-parser" "^2.0.6" + "fs-extra" "^1.0.0" + "graceful-fs" "^4.2.4" + "hermes-parser" "0.8.0" + "image-size" "^0.6.0" + "invariant" "^2.2.4" + "jest-worker" "^27.2.0" + "lodash.throttle" "^4.1.1" + "metro-babel-transformer" "0.72.3" + "metro-cache" "0.72.3" + "metro-cache-key" "0.72.3" + "metro-config" "0.72.3" + "metro-core" "0.72.3" + "metro-file-map" "0.72.3" + "metro-hermes-compiler" "0.72.3" + "metro-inspector-proxy" "0.72.3" + "metro-minify-uglify" "0.72.3" + "metro-react-native-babel-preset" "0.72.3" + "metro-resolver" "0.72.3" + "metro-runtime" "0.72.3" + "metro-source-map" "0.72.3" + "metro-symbolicate" "0.72.3" + "metro-transform-plugins" "0.72.3" + "metro-transform-worker" "0.72.3" + "mime-types" "^2.1.27" + "node-fetch" "^2.2.0" + "nullthrows" "^1.1.1" + "rimraf" "^2.5.4" + "serialize-error" "^2.1.0" + "source-map" "^0.5.6" + "strip-ansi" "^6.0.0" + "temp" "0.8.3" + "throat" "^5.0.0" + "ws" "^7.5.1" + "yargs" "^15.3.1" + +"micromatch@^3.1.10": + "integrity" "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==" + "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz" + "version" "3.1.10" + dependencies: + "arr-diff" "^4.0.0" + "array-unique" "^0.3.2" + "braces" "^2.3.1" + "define-property" "^2.0.2" + "extend-shallow" "^3.0.2" + "extglob" "^2.0.4" + "fragment-cache" "^0.2.1" + "kind-of" "^6.0.2" + "nanomatch" "^1.2.9" + "object.pick" "^1.3.0" + "regex-not" "^1.0.0" + "snapdragon" "^0.8.1" + "to-regex" "^3.0.2" + +"micromatch@^4.0.4": + "integrity" "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==" + "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + "version" "4.0.5" + dependencies: + "braces" "^3.0.2" + "picomatch" "^2.3.1" + +"miller-rabin@^4.0.0": + "integrity" "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==" + "resolved" "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz" + "version" "4.0.1" + dependencies: + "bn.js" "^4.0.0" + "brorand" "^1.0.1" + +"mime-db@>= 1.43.0 < 2", "mime-db@1.52.0": + "integrity" "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + "resolved" "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + "version" "1.52.0" + +"mime-types@^2.1.27", "mime-types@~2.1.34": + "integrity" "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==" + "resolved" "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + "version" "2.1.35" + dependencies: + "mime-db" "1.52.0" + +"mime@^2.4.1": + "integrity" "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" + "resolved" "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz" + "version" "2.6.0" + +"mime@1.6.0": + "integrity" "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + "resolved" "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" + "version" "1.6.0" + +"mimic-fn@^2.1.0": + "integrity" "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + "resolved" "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + "version" "2.1.0" + +"minimalistic-assert@^1.0.0", "minimalistic-assert@^1.0.1": + "integrity" "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "resolved" "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" + "version" "1.0.1" + +"minimalistic-crypto-utils@^1.0.1": + "integrity" "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + "resolved" "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" + "version" "1.0.1" + +"minimatch@^3.0.2", "minimatch@^3.0.5", "minimatch@^3.1.1", "minimatch@^3.1.2": + "integrity" "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==" + "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + "version" "3.1.2" + dependencies: + "brace-expansion" "^1.1.7" + +"minimatch@^5.0.1": + "integrity" "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==" + "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" + "version" "5.1.6" + dependencies: + "brace-expansion" "^2.0.1" + +"minimist@^1.2.0", "minimist@^1.2.6": + "integrity" "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" + "resolved" "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz" + "version" "1.2.7" + +"mixin-deep@^1.2.0": + "integrity" "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==" + "resolved" "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz" + "version" "1.3.2" + dependencies: + "for-in" "^1.0.2" + "is-extendable" "^1.0.1" + +"mkdirp@^0.5.1": + "integrity" "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==" + "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" + "version" "0.5.6" + dependencies: + "minimist" "^1.2.6" + +"ms@^2.1.1", "ms@2.1.2": + "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + "version" "2.1.2" + +"ms@2.0.0": + "integrity" "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + "version" "2.0.0" + +"ms@2.1.3": + "integrity" "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + "version" "2.1.3" + +"nanomatch@^1.2.9": + "integrity" "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==" + "resolved" "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz" + "version" "1.2.13" + dependencies: + "arr-diff" "^4.0.0" + "array-unique" "^0.3.2" + "define-property" "^2.0.2" + "extend-shallow" "^3.0.2" + "fragment-cache" "^0.2.1" + "is-windows" "^1.0.2" + "kind-of" "^6.0.2" + "object.pick" "^1.3.0" + "regex-not" "^1.0.0" + "snapdragon" "^0.8.1" + "to-regex" "^3.0.1" + +"natural-compare-lite@^1.4.0": + "integrity" "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==" + "resolved" "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz" + "version" "1.4.0" + +"natural-compare@^1.4.0": + "integrity" "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + "resolved" "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + "version" "1.4.0" + +"negotiator@0.6.3": + "integrity" "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + "resolved" "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" + "version" "0.6.3" + +"neo-async@^2.5.0": + "integrity" "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + "resolved" "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" + "version" "2.6.2" + +"nice-try@^1.0.4": + "integrity" "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + "resolved" "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" + "version" "1.0.5" + +"nocache@^3.0.1": + "integrity" "sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==" + "resolved" "https://registry.npmjs.org/nocache/-/nocache-3.0.4.tgz" + "version" "3.0.4" + +"node-dir@^0.1.17": + "integrity" "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==" + "resolved" "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz" + "version" "0.1.17" + dependencies: + "minimatch" "^3.0.2" + +"node-fetch@^2.2.0", "node-fetch@^2.6.0": + "integrity" "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==" + "resolved" "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" + "version" "2.6.7" + dependencies: + "whatwg-url" "^5.0.0" + +"node-int64@^0.4.0": + "integrity" "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + "resolved" "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + "version" "0.4.0" + +"node-releases@^2.0.6": + "integrity" "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + "resolved" "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz" + "version" "2.0.6" + +"node-stream-zip@^1.9.1": + "integrity" "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==" + "resolved" "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz" + "version" "1.15.0" + +"normalize-path@^3.0.0": + "integrity" "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "resolved" "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + "version" "3.0.0" + +"npm-run-path@^2.0.0": + "integrity" "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==" + "resolved" "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "path-key" "^2.0.0" + +"nullthrows@^1.1.1": + "integrity" "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" + "resolved" "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz" + "version" "1.1.1" + +"ob1@0.72.3": + "integrity" "sha512-OnVto25Sj7Ghp0vVm2THsngdze3tVq0LOg9LUHsAVXMecpqOP0Y8zaATW8M9gEgs2lNEAcCqV0P/hlmOPhVRvg==" + "resolved" "https://registry.npmjs.org/ob1/-/ob1-0.72.3.tgz" + "version" "0.72.3" + +"object-assign@^4.1.1": + "integrity" "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + "resolved" "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + "version" "4.1.1" + +"object-copy@^0.1.0": + "integrity" "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==" + "resolved" "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz" + "version" "0.1.0" + dependencies: + "copy-descriptor" "^0.1.0" + "define-property" "^0.2.5" + "kind-of" "^3.0.3" + +"object-inspect@^1.12.2", "object-inspect@^1.9.0": + "integrity" "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + "resolved" "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz" + "version" "1.12.2" + +"object-keys@^1.1.1": + "integrity" "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "resolved" "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + "version" "1.1.1" + +"object-visit@^1.0.0": + "integrity" "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==" + "resolved" "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "isobject" "^3.0.0" + +"object.assign@^4.1.3", "object.assign@^4.1.4": + "integrity" "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==" + "resolved" "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz" + "version" "4.1.4" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "has-symbols" "^1.0.3" + "object-keys" "^1.1.1" + +"object.entries@^1.1.6": + "integrity" "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==" + "resolved" "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz" + "version" "1.1.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"object.fromentries@^2.0.6": + "integrity" "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==" + "resolved" "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz" + "version" "2.0.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"object.hasown@^1.1.2": + "integrity" "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==" + "resolved" "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz" + "version" "1.1.2" + dependencies: + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"object.pick@^1.3.0": + "integrity" "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==" + "resolved" "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz" + "version" "1.3.0" + dependencies: + "isobject" "^3.0.1" + +"object.values@^1.1.6": + "integrity" "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==" + "resolved" "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz" + "version" "1.1.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"on-finished@~2.3.0": + "integrity" "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==" + "resolved" "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" + "version" "2.3.0" + dependencies: + "ee-first" "1.1.1" + +"on-finished@2.4.1": + "integrity" "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==" + "resolved" "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" + "version" "2.4.1" + dependencies: + "ee-first" "1.1.1" + +"on-headers@~1.0.2": + "integrity" "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + "resolved" "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz" + "version" "1.0.2" + +"once@^1.3.0", "once@^1.3.1", "once@^1.4.0": + "integrity" "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==" + "resolved" "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "wrappy" "1" + +"onetime@^5.1.0": + "integrity" "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==" + "resolved" "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + "version" "5.1.2" + dependencies: + "mimic-fn" "^2.1.0" + +"open@^6.2.0": + "integrity" "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==" + "resolved" "https://registry.npmjs.org/open/-/open-6.4.0.tgz" + "version" "6.4.0" + dependencies: + "is-wsl" "^1.1.0" + +"optionator@^0.9.1": + "integrity" "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==" + "resolved" "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" + "version" "0.9.1" + dependencies: + "deep-is" "^0.1.3" + "fast-levenshtein" "^2.0.6" + "levn" "^0.4.1" + "prelude-ls" "^1.2.1" + "type-check" "^0.4.0" + "word-wrap" "^1.2.3" + +"ora@^5.4.1": + "integrity" "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==" + "resolved" "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz" + "version" "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" + +"os-tmpdir@^1.0.0": + "integrity" "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + "resolved" "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" + "version" "1.0.2" + +"p-finally@^1.0.0": + "integrity" "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==" + "resolved" "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz" + "version" "1.0.0" + +"p-limit@^2.0.0": + "integrity" "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==" + "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + "version" "2.3.0" + dependencies: + "p-try" "^2.0.0" + +"p-limit@^2.2.0": + "integrity" "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==" + "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + "version" "2.3.0" + dependencies: + "p-try" "^2.0.0" + +"p-limit@^3.0.2": + "integrity" "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==" + "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "yocto-queue" "^0.1.0" + +"p-locate@^3.0.0": + "integrity" "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==" + "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "p-limit" "^2.0.0" + +"p-locate@^4.1.0": + "integrity" "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" + "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "p-limit" "^2.2.0" + +"p-locate@^5.0.0": + "integrity" "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==" + "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "p-limit" "^3.0.2" + +"p-try@^2.0.0": + "integrity" "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "resolved" "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + "version" "2.2.0" + +"pako@^2.1.0": + "integrity" "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + "resolved" "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz" + "version" "2.1.0" + +"parent-module@^1.0.0": + "integrity" "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==" + "resolved" "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "callsites" "^3.0.0" + +"parse-asn1@^5.0.0", "parse-asn1@^5.1.5": + "integrity" "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==" + "resolved" "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz" + "version" "5.1.6" + dependencies: + "asn1.js" "^5.2.0" + "browserify-aes" "^1.0.0" + "evp_bytestokey" "^1.0.0" + "pbkdf2" "^3.0.3" + "safe-buffer" "^5.1.1" + +"parse-json@^4.0.0": + "integrity" "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==" + "resolved" "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "error-ex" "^1.3.1" + "json-parse-better-errors" "^1.0.1" + +"parseurl@~1.3.3": + "integrity" "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + "resolved" "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" + "version" "1.3.3" + +"pascalcase@^0.1.1": + "integrity" "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==" + "resolved" "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz" + "version" "0.1.1" + +"path-exists@^3.0.0": + "integrity" "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" + "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" + "version" "3.0.0" + +"path-exists@^4.0.0": + "integrity" "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + "version" "4.0.0" + +"path-is-absolute@^1.0.0": + "integrity" "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + "resolved" "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + "version" "1.0.1" + +"path-key@^2.0.0": + "integrity" "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" + "resolved" "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" + "version" "2.0.1" + +"path-key@^2.0.1": + "integrity" "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" + "resolved" "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" + "version" "2.0.1" + +"path-key@^3.1.0": + "integrity" "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "resolved" "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + "version" "3.1.1" + +"path-parse@^1.0.7": + "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + "version" "1.0.7" + +"path-type@^4.0.0": + "integrity" "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + "resolved" "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + "version" "4.0.0" + +"pbkdf2@^3.0.3": + "integrity" "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==" + "resolved" "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz" + "version" "3.1.2" + dependencies: + "create-hash" "^1.1.2" + "create-hmac" "^1.1.4" + "ripemd160" "^2.0.1" + "safe-buffer" "^5.0.1" + "sha.js" "^2.4.8" + +"picocolors@^1.0.0": + "integrity" "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "resolved" "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + "version" "1.0.0" + +"picomatch@^2.0.4", "picomatch@^2.2.3", "picomatch@^2.3.1": + "integrity" "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + "version" "2.3.1" + +"pify@^4.0.1": + "integrity" "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + "resolved" "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" + "version" "4.0.1" + +"pirates@^4.0.5": + "integrity" "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==" + "resolved" "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz" + "version" "4.0.5" + +"pkg-dir@^3.0.0": + "integrity" "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==" + "resolved" "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "find-up" "^3.0.0" + +"pkg-up@^3.1.0": + "integrity" "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==" + "resolved" "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "find-up" "^3.0.0" + +"posix-character-classes@^0.1.0": + "integrity" "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==" + "resolved" "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz" + "version" "0.1.1" + +"prelude-ls@^1.2.1": + "integrity" "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + "resolved" "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + "version" "1.2.1" + +"pretty-format@^26.5.2", "pretty-format@^26.6.2": + "integrity" "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==" + "resolved" "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz" + "version" "26.6.2" + dependencies: + "@jest/types" "^26.6.2" + "ansi-regex" "^5.0.0" + "ansi-styles" "^4.0.0" + "react-is" "^17.0.1" + +"process-nextick-args@~2.0.0": + "integrity" "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + "resolved" "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + "version" "2.0.1" + +"promise@^8.3.0": + "integrity" "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==" + "resolved" "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz" + "version" "8.3.0" + dependencies: + "asap" "~2.0.6" + +"prompts@^2.4.0": + "integrity" "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==" + "resolved" "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + "version" "2.4.2" + dependencies: + "kleur" "^3.0.3" + "sisteransi" "^1.0.5" + +"prop-types@^15.7.2", "prop-types@^15.8.1", "prop-types@15.x.x": + "integrity" "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" + "resolved" "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" + "version" "15.8.1" + dependencies: + "loose-envify" "^1.4.0" + "object-assign" "^4.1.1" + "react-is" "^16.13.1" + +"public-encrypt@^4.0.0": + "integrity" "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==" + "resolved" "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz" + "version" "4.0.3" + dependencies: + "bn.js" "^4.1.0" + "browserify-rsa" "^4.0.0" + "create-hash" "^1.1.0" + "parse-asn1" "^5.0.0" + "randombytes" "^2.0.1" + "safe-buffer" "^5.1.2" + +"pump@^3.0.0": + "integrity" "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==" + "resolved" "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "end-of-stream" "^1.1.0" + "once" "^1.3.1" + +"punycode@^2.1.0": + "integrity" "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "resolved" "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" + "version" "2.1.1" + +"queue-microtask@^1.2.2": + "integrity" "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + "resolved" "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + "version" "1.2.3" + +"randombytes@^2.0.0", "randombytes@^2.0.1", "randombytes@^2.0.5": + "integrity" "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==" + "resolved" "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "safe-buffer" "^5.1.0" + +"randomfill@^1.0.3": + "integrity" "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==" + "resolved" "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "randombytes" "^2.0.5" + "safe-buffer" "^5.1.0" + +"range-parser@~1.2.1": + "integrity" "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + "resolved" "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" + "version" "1.2.1" + +"react-devtools-core@4.24.0": + "integrity" "sha512-Rw7FzYOOzcfyUPaAm9P3g0tFdGqGq2LLiAI+wjYcp6CsF3DeeMrRS3HZAho4s273C29G/DJhx0e8BpRE/QZNGg==" + "resolved" "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.24.0.tgz" + "version" "4.24.0" + dependencies: + "shell-quote" "^1.6.1" + "ws" "^7" + +"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", "react-is@^16.13.1", "react-is@^16.7.0": + "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + "version" "16.13.1" + +"react-is@^17.0.1": + "integrity" "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + "resolved" "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" + "version" "17.0.2" + +"react-lifecycles-compat@2.0.0": + "integrity" "sha512-txfpPCQYiazVdcbMRhatqWKcAxJweUu2wDXvts5/7Wyp6+Y9cHojqXHsLPEckzutfHlxZhG8Oiundbmp8Fd6eQ==" + "resolved" "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-2.0.0.tgz" + "version" "2.0.0" + +"react-native-background-timer@^2.4.1": + "integrity" "sha512-TE4Kiy7jUyv+hugxDxitzu38sW1NqjCk4uE5IgU2WevLv7sZacaBc6PZKOShNRPGirLl1NWkaG3LDEkdb9Um5g==" + "resolved" "https://registry.npmjs.org/react-native-background-timer/-/react-native-background-timer-2.4.1.tgz" + "version" "2.4.1" + +"react-native-codegen@^0.70.6": + "integrity" "sha512-kdwIhH2hi+cFnG5Nb8Ji2JwmcCxnaOOo9440ov7XDzSvGfmUStnCzl+MCW8jLjqHcE4icT7N9y+xx4f50vfBTw==" + "resolved" "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.70.6.tgz" + "version" "0.70.6" + dependencies: + "@babel/parser" "^7.14.0" + "flow-parser" "^0.121.0" + "jscodeshift" "^0.13.1" + "nullthrows" "^1.1.1" + +"react-native-exception-handler@^2.10.10": + "integrity" "sha512-otAXGoZDl1689OoUJWN/rXxVbdoZ3xcmyF1uq/CsizdLwwyZqVGd6d+p/vbYvnF996FfEyAEBnHrdFxulTn51w==" + "resolved" "https://registry.npmjs.org/react-native-exception-handler/-/react-native-exception-handler-2.10.10.tgz" + "version" "2.10.10" + +"react-native-fs@^2.20.0": + "integrity" "sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ==" + "resolved" "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz" + "version" "2.20.0" + dependencies: + "base-64" "^0.1.0" + "utf8" "^3.0.0" + +"react-native-gradle-plugin@^0.70.3": + "integrity" "sha512-oOanj84fJEXUg9FoEAQomA8ISG+DVIrTZ3qF7m69VQUJyOGYyDZmPqKcjvRku4KXlEH6hWO9i4ACLzNBh8gC0A==" + "resolved" "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz" + "version" "0.70.3" + +"react-native-navigation@^7.32.1": + "integrity" "sha512-qqpccWh6MqTG0hn/XeggKonSYg+h64kOsYBot/+g2EUC/Usp8TZsKi1B2gzsUrDQy8EmsF9iTBoZMIgjxFG/WQ==" + "resolved" "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-7.32.1.tgz" + "version" "7.32.1" + dependencies: + "hoist-non-react-statics" "3.x.x" + "lodash" "4.17.x" + "prop-types" "15.x.x" + "react-lifecycles-compat" "2.0.0" + "tslib" "1.9.3" + +"react-native-pager-view@^6.1.4": + "integrity" "sha512-fmTwgGwPxGCBusKAq7gHzm+s1Yp0qh5rKPoQszaCuxrb+76KgK4Qe82jJNPUp2xTZOKSw+FbJU2QahF8ncTl+w==" + "resolved" "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.1.4.tgz" + "version" "6.1.4" + +"react-native-quick-base64@^2.0.2", "react-native-quick-base64@^2.0.5": + "integrity" "sha512-waRcIlchdLCSzpWYqRNIN5NyE5PxKyedMQ/sTgA/fcEkBzwp3EOwjhsfVuJuBtc1bHL2Mg34pxDVBxyLU3Mu2Q==" + "resolved" "https://registry.npmjs.org/react-native-quick-base64/-/react-native-quick-base64-2.0.5.tgz" + "version" "2.0.5" + dependencies: + "base64-js" "^1.5.1" + +"react-native-quick-crypto@^0.5.0": + "integrity" "sha512-NYc8r97UaKOfkHj0iyM8OD+S5U+8mTKheb/BYpu7CNJ0qt1VkwFEaWkJtOUWSRbyd24d0AKrC9+97UkroBs9JA==" + "resolved" "https://registry.npmjs.org/react-native-quick-crypto/-/react-native-quick-crypto-0.5.0.tgz" + "version" "0.5.0" + dependencies: + "@craftzdog/react-native-buffer" "^6.0.4" + "@types/node" "^17.0.31" + "crypto-browserify" "^3.12.0" + "events" "^3.3.0" + "react-native-quick-base64" "^2.0.2" + "stream-browserify" "^3.0.0" + "string_decoder" "^1.3.0" + +"react-native-track-player@github:lyswhut/react-native-track-player#38027954a5ac6e3d92961745e0a9633fc647f47a": + "integrity" "sha512-WLUJIbfNPTudwEhr8D70U0kwg3sQsivdFHCGjiq9ko44PmxlINFty+0g1/DmFdWZOAKUrq8y3/e6S+Uj7Uv7Bw==" + "resolved" "git+ssh://git@github.com/lyswhut/react-native-track-player.git#38027954a5ac6e3d92961745e0a9633fc647f47a" + "version" "2.1.2" + +"react-native-vector-icons@^9.2.0": + "integrity" "sha512-wKYLaFuQST/chH3AJRjmOLoLy3JEs1JR6zMNgTaemFpNoXs0ztRnTxcxFD9xhX7cJe1/zoN5BpQYe7kL0m5yyA==" + "resolved" "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-9.2.0.tgz" + "version" "9.2.0" + dependencies: + "prop-types" "^15.7.2" + "yargs" "^16.1.1" + +"react-native@*", "react-native@^0.0.0-0 || 0.60 - 0.71 || 1000.0.0", "react-native@>= 0.62", "react-native@>=0.47.0", "react-native@>=0.57.0", "react-native@>=0.60.0-rc.2", "react-native@0.70.7": + "integrity" "sha512-MvnJJXiEPuOBbf1VPY5WXIUR/n6QB/DAk5XtBz3bzinpy9YBXiiQkhGIrTpVdVt37JeHOzafhfxAMf+Rs8jpvA==" + "resolved" "https://registry.npmjs.org/react-native/-/react-native-0.70.7.tgz" + "version" "0.70.7" + dependencies: + "@jest/create-cache-key-function" "^27.0.1" + "@react-native-community/cli" "9.3.2" + "@react-native-community/cli-platform-android" "9.3.1" + "@react-native-community/cli-platform-ios" "9.3.0" + "@react-native/assets" "1.0.0" + "@react-native/normalize-color" "2.0.0" + "@react-native/polyfills" "2.0.0" + "abort-controller" "^3.0.0" + "anser" "^1.4.9" + "base64-js" "^1.1.2" + "event-target-shim" "^5.0.1" + "invariant" "^2.2.4" + "jsc-android" "^250230.2.1" + "memoize-one" "^5.0.0" + "metro-react-native-babel-transformer" "0.72.3" + "metro-runtime" "0.72.3" + "metro-source-map" "0.72.3" + "mkdirp" "^0.5.1" + "nullthrows" "^1.1.1" + "pretty-format" "^26.5.2" + "promise" "^8.3.0" + "react-devtools-core" "4.24.0" + "react-native-codegen" "^0.70.6" + "react-native-gradle-plugin" "^0.70.3" + "react-refresh" "^0.4.0" + "react-shallow-renderer" "^16.15.0" + "regenerator-runtime" "^0.13.2" + "scheduler" "^0.22.0" + "stacktrace-parser" "^0.1.3" + "use-sync-external-store" "^1.0.0" + "whatwg-fetch" "^3.0.0" + "ws" "^6.1.4" + +"react-refresh@^0.4.0": + "integrity" "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==" + "resolved" "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz" + "version" "0.4.3" + +"react-shallow-renderer@^16.15.0": + "integrity" "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==" + "resolved" "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz" + "version" "16.15.0" + dependencies: + "object-assign" "^4.1.1" + "react-is" "^16.12.0 || ^17.0.0 || ^18.0.0" + +"react@*", "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@>=16.0", "react@>=16.8.6", "react@18.1.0": + "integrity" "sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==" + "resolved" "https://registry.npmjs.org/react/-/react-18.1.0.tgz" + "version" "18.1.0" + dependencies: + "loose-envify" "^1.1.0" + +"readable-stream@^3.4.0", "readable-stream@^3.5.0", "readable-stream@^3.6.0": + "integrity" "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==" + "resolved" "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" + "version" "3.6.0" + dependencies: + "inherits" "^2.0.3" + "string_decoder" "^1.1.1" + "util-deprecate" "^1.0.1" + +"readable-stream@~2.3.6": + "integrity" "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==" + "resolved" "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" + "version" "2.3.7" + dependencies: + "core-util-is" "~1.0.0" + "inherits" "~2.0.3" + "isarray" "~1.0.0" + "process-nextick-args" "~2.0.0" + "safe-buffer" "~5.1.1" + "string_decoder" "~1.1.1" + "util-deprecate" "~1.0.1" + +"readline@^1.3.0": + "integrity" "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==" + "resolved" "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz" + "version" "1.3.0" + +"recast@^0.20.4": + "integrity" "sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==" + "resolved" "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz" + "version" "0.20.5" + dependencies: + "ast-types" "0.14.2" + "esprima" "~4.0.0" + "source-map" "~0.6.1" + "tslib" "^2.0.1" + +"regenerate-unicode-properties@^10.1.0": + "integrity" "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==" + "resolved" "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz" + "version" "10.1.0" + dependencies: + "regenerate" "^1.4.2" + +"regenerate@^1.4.2": + "integrity" "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + "resolved" "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" + "version" "1.4.2" + +"regenerator-runtime@^0.13.11", "regenerator-runtime@^0.13.2": + "integrity" "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" + "version" "0.13.11" + +"regenerator-transform@^0.15.0": + "integrity" "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==" + "resolved" "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz" + "version" "0.15.0" + dependencies: + "@babel/runtime" "^7.8.4" + +"regex-not@^1.0.0", "regex-not@^1.0.2": + "integrity" "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==" + "resolved" "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "extend-shallow" "^3.0.2" + "safe-regex" "^1.1.0" + +"regexp.prototype.flags@^1.4.3": + "integrity" "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==" + "resolved" "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz" + "version" "1.4.3" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.3" + "functions-have-names" "^1.2.2" + +"regexpp@^3.0.0", "regexpp@^3.2.0": + "integrity" "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" + "resolved" "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" + "version" "3.2.0" + +"regexpu-core@^5.1.0": + "integrity" "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==" + "resolved" "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz" + "version" "5.2.1" + dependencies: + "regenerate" "^1.4.2" + "regenerate-unicode-properties" "^10.1.0" + "regjsgen" "^0.7.1" + "regjsparser" "^0.9.1" + "unicode-match-property-ecmascript" "^2.0.0" + "unicode-match-property-value-ecmascript" "^2.0.0" + +"regjsgen@^0.7.1": + "integrity" "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" + "resolved" "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz" + "version" "0.7.1" + +"regjsparser@^0.9.1": + "integrity" "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==" + "resolved" "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz" + "version" "0.9.1" + dependencies: + "jsesc" "~0.5.0" + +"repeat-element@^1.1.2": + "integrity" "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" + "resolved" "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz" + "version" "1.1.4" + +"repeat-string@^1.6.1": + "integrity" "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" + "resolved" "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" + "version" "1.6.1" + +"require-directory@^2.1.1": + "integrity" "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + "resolved" "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + "version" "2.1.1" + +"require-main-filename@^2.0.0": + "integrity" "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + "resolved" "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz" + "version" "2.0.0" + +"reselect@^4.1.7": + "integrity" "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==" + "resolved" "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz" + "version" "4.1.7" + +"resolve-from@^3.0.0": + "integrity" "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==" + "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz" + "version" "3.0.0" + +"resolve-from@^4.0.0": + "integrity" "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + "version" "4.0.0" + +"resolve-url@^0.2.1": + "integrity" "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==" + "resolved" "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz" + "version" "0.2.1" + +"resolve@^1.14.2", "resolve@^1.22.1": + "integrity" "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==" + "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" + "version" "1.22.1" + dependencies: + "is-core-module" "^2.9.0" + "path-parse" "^1.0.7" + "supports-preserve-symlinks-flag" "^1.0.0" + +"resolve@^2.0.0-next.4": + "integrity" "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==" + "resolved" "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz" + "version" "2.0.0-next.4" + dependencies: + "is-core-module" "^2.9.0" + "path-parse" "^1.0.7" + "supports-preserve-symlinks-flag" "^1.0.0" + +"restore-cursor@^3.1.0": + "integrity" "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==" + "resolved" "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "onetime" "^5.1.0" + "signal-exit" "^3.0.2" + +"ret@~0.1.10": + "integrity" "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + "resolved" "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz" + "version" "0.1.15" + +"reusify@^1.0.4": + "integrity" "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + "resolved" "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + "version" "1.0.4" + +"rimraf@^2.5.4": + "integrity" "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==" + "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + "version" "2.7.1" + dependencies: + "glob" "^7.1.3" + +"rimraf@^3.0.2": + "integrity" "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==" + "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "glob" "^7.1.3" + +"rimraf@~2.2.6": + "integrity" "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==" + "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz" + "version" "2.2.8" + +"rimraf@~2.6.2": + "integrity" "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==" + "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz" + "version" "2.6.3" + dependencies: + "glob" "^7.1.3" + +"ripemd160@^2.0.0", "ripemd160@^2.0.1": + "integrity" "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==" + "resolved" "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "hash-base" "^3.0.0" + "inherits" "^2.0.1" + +"run-parallel@^1.1.9": + "integrity" "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==" + "resolved" "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + "version" "1.2.0" + dependencies: + "queue-microtask" "^1.2.2" + +"safe-buffer@^5.0.1", "safe-buffer@^5.1.0", "safe-buffer@^5.1.1", "safe-buffer@^5.1.2", "safe-buffer@~5.1.0", "safe-buffer@~5.1.1", "safe-buffer@5.1.2": + "integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + "version" "5.1.2" + +"safe-buffer@^5.2.0": + "integrity" "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + "version" "5.2.1" + +"safe-buffer@~5.2.0": + "integrity" "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + "version" "5.2.1" + +"safe-regex-test@^1.0.0": + "integrity" "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==" + "resolved" "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "call-bind" "^1.0.2" + "get-intrinsic" "^1.1.3" + "is-regex" "^1.1.4" + +"safe-regex@^1.1.0": + "integrity" "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==" + "resolved" "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz" + "version" "1.1.0" + dependencies: + "ret" "~0.1.10" + +"safer-buffer@^2.1.0", "safer-buffer@>= 2.1.2 < 3.0.0": + "integrity" "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "resolved" "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + "version" "2.1.2" + +"scheduler@^0.22.0": + "integrity" "sha512-6QAm1BgQI88NPYymgGQLCZgvep4FyePDWFpXVK+zNSUgHwlqpJy8VEh8Et0KxTACS4VWwMousBElAZOH9nkkoQ==" + "resolved" "https://registry.npmjs.org/scheduler/-/scheduler-0.22.0.tgz" + "version" "0.22.0" + dependencies: + "loose-envify" "^1.1.0" + +"semver@^5.5.0": + "integrity" "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "resolved" "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" + "version" "5.7.1" + +"semver@^5.6.0": + "integrity" "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "resolved" "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" + "version" "5.7.1" + +"semver@^6.1.1", "semver@^6.1.2", "semver@^6.3.0": + "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + "version" "6.3.0" + +"semver@^7.0.0": + "integrity" "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==" + "resolved" "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz" + "version" "7.3.8" + dependencies: + "lru-cache" "^6.0.0" + +"semver@^7.3.7": + "integrity" "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==" + "resolved" "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz" + "version" "7.3.8" + dependencies: + "lru-cache" "^6.0.0" + +"semver@^7.3.8": + "integrity" "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==" + "resolved" "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz" + "version" "7.3.8" + dependencies: + "lru-cache" "^6.0.0" + +"send@0.18.0": + "integrity" "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==" + "resolved" "https://registry.npmjs.org/send/-/send-0.18.0.tgz" + "version" "0.18.0" + dependencies: + "debug" "2.6.9" + "depd" "2.0.0" + "destroy" "1.2.0" + "encodeurl" "~1.0.2" + "escape-html" "~1.0.3" + "etag" "~1.8.1" + "fresh" "0.5.2" + "http-errors" "2.0.0" + "mime" "1.6.0" + "ms" "2.1.3" + "on-finished" "2.4.1" + "range-parser" "~1.2.1" + "statuses" "2.0.1" + +"serialize-error@^2.1.0": + "integrity" "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==" + "resolved" "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz" + "version" "2.1.0" + +"serve-static@^1.13.1": + "integrity" "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==" + "resolved" "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" + "version" "1.15.0" + dependencies: + "encodeurl" "~1.0.2" + "escape-html" "~1.0.3" + "parseurl" "~1.3.3" + "send" "0.18.0" + +"set-blocking@^2.0.0": + "integrity" "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + "resolved" "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + "version" "2.0.0" + +"set-value@^2.0.0", "set-value@^2.0.1": + "integrity" "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==" + "resolved" "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "extend-shallow" "^2.0.1" + "is-extendable" "^0.1.1" + "is-plain-object" "^2.0.3" + "split-string" "^3.0.1" + +"setprototypeof@1.2.0": + "integrity" "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "resolved" "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" + "version" "1.2.0" + +"sha.js@^2.4.0", "sha.js@^2.4.8": + "integrity" "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==" + "resolved" "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz" + "version" "2.4.11" + dependencies: + "inherits" "^2.0.1" + "safe-buffer" "^5.0.1" + +"shallow-clone@^3.0.0": + "integrity" "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==" + "resolved" "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz" + "version" "3.0.1" + dependencies: + "kind-of" "^6.0.2" + +"shebang-command@^1.2.0": + "integrity" "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==" + "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" + "version" "1.2.0" + dependencies: + "shebang-regex" "^1.0.0" + +"shebang-command@^2.0.0": + "integrity" "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==" + "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "shebang-regex" "^3.0.0" + +"shebang-regex@^1.0.0": + "integrity" "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" + "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" + "version" "1.0.0" + +"shebang-regex@^3.0.0": + "integrity" "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + "version" "3.0.0" + +"shell-quote@^1.6.1", "shell-quote@^1.7.3": + "integrity" "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==" + "resolved" "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz" + "version" "1.7.4" + +"side-channel@^1.0.4": + "integrity" "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==" + "resolved" "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "call-bind" "^1.0.0" + "get-intrinsic" "^1.0.2" + "object-inspect" "^1.9.0" + +"signal-exit@^3.0.0", "signal-exit@^3.0.2": + "integrity" "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "resolved" "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + "version" "3.0.7" + +"sisteransi@^1.0.5": + "integrity" "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + "resolved" "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" + "version" "1.0.5" + +"slash@^3.0.0": + "integrity" "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + "resolved" "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + "version" "3.0.0" + +"slice-ansi@^2.0.0": + "integrity" "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==" + "resolved" "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "ansi-styles" "^3.2.0" + "astral-regex" "^1.0.0" + "is-fullwidth-code-point" "^2.0.0" + +"snapdragon-node@^2.0.1": + "integrity" "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==" + "resolved" "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz" + "version" "2.1.1" + dependencies: + "define-property" "^1.0.0" + "isobject" "^3.0.0" + "snapdragon-util" "^3.0.1" + +"snapdragon-util@^3.0.1": + "integrity" "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==" + "resolved" "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz" + "version" "3.0.1" + dependencies: + "kind-of" "^3.2.0" + +"snapdragon@^0.8.1": + "integrity" "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==" + "resolved" "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz" + "version" "0.8.2" + dependencies: + "base" "^0.11.1" + "debug" "^2.2.0" + "define-property" "^0.2.5" + "extend-shallow" "^2.0.1" + "map-cache" "^0.2.2" + "source-map" "^0.5.6" + "source-map-resolve" "^0.5.0" + "use" "^3.1.0" + +"socket.io-client@^4.6.0": + "integrity" "sha512-2XOp18xnGghUICSd5ziUIS4rB0dhr6S8OvAps8y+HhOjFQlqGcf+FIh6fCIsKKZyWFxJeFPrZRNPGsHDTsz1Ug==" + "resolved" "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.6.0.tgz" + "version" "4.6.0" + dependencies: + "@socket.io/component-emitter" "~3.1.0" + "debug" "~4.3.2" + "engine.io-client" "~6.4.0" + "socket.io-parser" "~4.2.1" + +"socket.io-parser@~4.2.1": + "integrity" "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==" + "resolved" "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz" + "version" "4.2.1" + dependencies: + "@socket.io/component-emitter" "~3.1.0" + "debug" "~4.3.1" + +"source-map-resolve@^0.5.0": + "integrity" "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==" + "resolved" "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz" + "version" "0.5.3" + dependencies: + "atob" "^2.1.2" + "decode-uri-component" "^0.2.0" + "resolve-url" "^0.2.1" + "source-map-url" "^0.4.0" + "urix" "^0.1.0" + +"source-map-support@^0.5.16": + "integrity" "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==" + "resolved" "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + "version" "0.5.21" + dependencies: + "buffer-from" "^1.0.0" + "source-map" "^0.6.0" + +"source-map-url@^0.4.0": + "integrity" "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" + "resolved" "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz" + "version" "0.4.1" + +"source-map@^0.5.6": + "integrity" "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + "version" "0.5.7" + +"source-map@^0.6.0": + "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + "version" "0.6.1" + +"source-map@^0.7.3": + "integrity" "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz" + "version" "0.7.4" + +"source-map@~0.6.1": + "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + "version" "0.6.1" + +"split-string@^3.0.1", "split-string@^3.0.2": + "integrity" "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==" + "resolved" "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "extend-shallow" "^3.0.0" + +"sprintf-js@~1.0.2": + "integrity" "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + "resolved" "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + "version" "1.0.3" + +"stackframe@^1.3.4": + "integrity" "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" + "resolved" "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz" + "version" "1.3.4" + +"stacktrace-parser@^0.1.3": + "integrity" "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==" + "resolved" "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz" + "version" "0.1.10" + dependencies: + "type-fest" "^0.7.1" + +"static-extend@^0.1.1": + "integrity" "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==" + "resolved" "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz" + "version" "0.1.2" + dependencies: + "define-property" "^0.2.5" + "object-copy" "^0.1.0" + +"statuses@~1.5.0": + "integrity" "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + "resolved" "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" + "version" "1.5.0" + +"statuses@2.0.1": + "integrity" "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + "resolved" "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" + "version" "2.0.1" + +"stream-browserify@^3.0.0": + "integrity" "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==" + "resolved" "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "inherits" "~2.0.4" + "readable-stream" "^3.5.0" + +"string_decoder@^1.1.1", "string_decoder@^1.3.0": + "integrity" "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==" + "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + "version" "1.3.0" + dependencies: + "safe-buffer" "~5.2.0" + +"string_decoder@~1.1.1": + "integrity" "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==" + "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + "version" "1.1.1" + dependencies: + "safe-buffer" "~5.1.0" + +"string-width@^4.1.0", "string-width@^4.2.0": + "integrity" "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==" + "resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + "version" "4.2.3" + dependencies: + "emoji-regex" "^8.0.0" + "is-fullwidth-code-point" "^3.0.0" + "strip-ansi" "^6.0.1" + +"string.prototype.matchall@^4.0.8": + "integrity" "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==" + "resolved" "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz" + "version" "4.0.8" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + "get-intrinsic" "^1.1.3" + "has-symbols" "^1.0.3" + "internal-slot" "^1.0.3" + "regexp.prototype.flags" "^1.4.3" + "side-channel" "^1.0.4" + +"string.prototype.trimend@^1.0.5": + "integrity" "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==" + "resolved" "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz" + "version" "1.0.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"string.prototype.trimstart@^1.0.5": + "integrity" "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==" + "resolved" "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz" + "version" "1.0.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"strip-ansi@^5.0.0": + "integrity" "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==" + "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" + "version" "5.2.0" + dependencies: + "ansi-regex" "^4.1.0" + +"strip-ansi@^5.2.0": + "integrity" "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==" + "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" + "version" "5.2.0" + dependencies: + "ansi-regex" "^4.1.0" + +"strip-ansi@^6.0.0", "strip-ansi@^6.0.1": + "integrity" "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" + "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + "version" "6.0.1" + dependencies: + "ansi-regex" "^5.0.1" + +"strip-bom@^3.0.0": + "integrity" "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==" + "resolved" "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + "version" "3.0.0" + +"strip-eof@^1.0.0": + "integrity" "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==" + "resolved" "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz" + "version" "1.0.0" + +"strip-json-comments@^3.1.0", "strip-json-comments@^3.1.1": + "integrity" "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + "resolved" "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + "version" "3.1.1" + +"sudo-prompt@^9.0.0": + "integrity" "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==" + "resolved" "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz" + "version" "9.2.1" + +"supports-color@^5.3.0": + "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + "version" "5.5.0" + dependencies: + "has-flag" "^3.0.0" + +"supports-color@^7.1.0": + "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + "version" "7.2.0" + dependencies: + "has-flag" "^4.0.0" + +"supports-color@^8.0.0": + "integrity" "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + "version" "8.1.1" + dependencies: + "has-flag" "^4.0.0" + +"supports-preserve-symlinks-flag@^1.0.0": + "integrity" "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + "resolved" "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + "version" "1.0.0" + +"temp@^0.8.4": + "integrity" "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==" + "resolved" "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz" + "version" "0.8.4" + dependencies: + "rimraf" "~2.6.2" + +"temp@0.8.3": + "integrity" "sha512-jtnWJs6B1cZlHs9wPG7BrowKxZw/rf6+UpGAkr8AaYmiTyTO7zQlLoST8zx/8TcUPnZmeBoB+H8ARuHZaSijVw==" + "resolved" "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz" + "version" "0.8.3" + dependencies: + "os-tmpdir" "^1.0.0" + "rimraf" "~2.2.6" + +"text-table@^0.2.0": + "integrity" "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + "resolved" "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + "version" "0.2.0" + +"throat@^5.0.0": + "integrity" "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==" + "resolved" "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz" + "version" "5.0.0" + +"through2@^2.0.1": + "integrity" "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==" + "resolved" "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" + "version" "2.0.5" + dependencies: + "readable-stream" "~2.3.6" + "xtend" "~4.0.1" + +"tmpl@1.0.5": + "integrity" "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + "resolved" "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" + "version" "1.0.5" + +"to-fast-properties@^2.0.0": + "integrity" "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + "resolved" "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + "version" "2.0.0" + +"to-object-path@^0.3.0": + "integrity" "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==" + "resolved" "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz" + "version" "0.3.0" + dependencies: + "kind-of" "^3.0.2" + +"to-regex-range@^2.1.0": + "integrity" "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==" + "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz" + "version" "2.1.1" + dependencies: + "is-number" "^3.0.0" + "repeat-string" "^1.6.1" + +"to-regex-range@^5.0.1": + "integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==" + "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + "version" "5.0.1" + dependencies: + "is-number" "^7.0.0" + +"to-regex@^3.0.1", "to-regex@^3.0.2": + "integrity" "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==" + "resolved" "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "define-property" "^2.0.2" + "extend-shallow" "^3.0.2" + "regex-not" "^1.0.2" + "safe-regex" "^1.1.0" + +"toidentifier@1.0.1": + "integrity" "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + "resolved" "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" + "version" "1.0.1" + +"tr46@~0.0.3": + "integrity" "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "resolved" "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" + "version" "0.0.3" + +"tsconfig-paths@^3.14.1": + "integrity" "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==" + "resolved" "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz" + "version" "3.14.1" + dependencies: + "@types/json5" "^0.0.29" + "json5" "^1.0.1" + "minimist" "^1.2.6" + "strip-bom" "^3.0.0" + +"tslib@^1.8.1": + "integrity" "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + "version" "1.14.1" + +"tslib@^2.0.1": + "integrity" "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz" + "version" "2.4.1" + +"tslib@1.9.3": + "integrity" "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz" + "version" "1.9.3" + +"tsutils@^3.21.0": + "integrity" "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==" + "resolved" "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" + "version" "3.21.0" + dependencies: + "tslib" "^1.8.1" + +"type-check@^0.4.0", "type-check@~0.4.0": + "integrity" "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==" + "resolved" "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + "version" "0.4.0" + dependencies: + "prelude-ls" "^1.2.1" + +"type-fest@^0.20.2": + "integrity" "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + "version" "0.20.2" + +"type-fest@^0.7.1": + "integrity" "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==" + "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz" + "version" "0.7.1" + +"typescript@*", "typescript@^4.9.5", "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta": + "integrity" "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" + "resolved" "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz" + "version" "4.9.5" + +"uglify-es@^3.1.9": + "integrity" "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==" + "resolved" "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz" + "version" "3.3.9" + dependencies: + "commander" "~2.13.0" + "source-map" "~0.6.1" + +"unbox-primitive@^1.0.2": + "integrity" "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==" + "resolved" "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "call-bind" "^1.0.2" + "has-bigints" "^1.0.2" + "has-symbols" "^1.0.3" + "which-boxed-primitive" "^1.0.2" + +"unicode-canonical-property-names-ecmascript@^2.0.0": + "integrity" "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" + "resolved" "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz" + "version" "2.0.0" + +"unicode-match-property-ecmascript@^2.0.0": + "integrity" "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==" + "resolved" "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "unicode-canonical-property-names-ecmascript" "^2.0.0" + "unicode-property-aliases-ecmascript" "^2.0.0" + +"unicode-match-property-value-ecmascript@^2.0.0": + "integrity" "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" + "resolved" "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz" + "version" "2.0.0" + +"unicode-property-aliases-ecmascript@^2.0.0": + "integrity" "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" + "resolved" "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz" + "version" "2.1.0" + +"union-value@^1.0.0": + "integrity" "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==" + "resolved" "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "arr-union" "^3.1.0" + "get-value" "^2.0.6" + "is-extendable" "^0.1.1" + "set-value" "^2.0.1" + +"universalify@^0.1.0": + "integrity" "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + "resolved" "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" + "version" "0.1.2" + +"unpipe@~1.0.0": + "integrity" "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + "resolved" "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" + "version" "1.0.0" + +"unset-value@^1.0.0": + "integrity" "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==" + "resolved" "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "has-value" "^0.3.1" + "isobject" "^3.0.0" + +"update-browserslist-db@^1.0.9": + "integrity" "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==" + "resolved" "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz" + "version" "1.0.10" + dependencies: + "escalade" "^3.1.1" + "picocolors" "^1.0.0" + +"uri-js@^4.2.2": + "integrity" "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==" + "resolved" "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + "version" "4.4.1" + dependencies: + "punycode" "^2.1.0" + +"urix@^0.1.0": + "integrity" "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==" + "resolved" "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz" + "version" "0.1.0" + +"use-sync-external-store@^1.0.0": + "integrity" "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==" + "resolved" "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz" + "version" "1.2.0" + +"use@^3.1.0": + "integrity" "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + "resolved" "https://registry.npmjs.org/use/-/use-3.1.1.tgz" + "version" "3.1.1" + +"utf8@^3.0.0": + "integrity" "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" + "resolved" "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz" + "version" "3.0.0" + +"util-deprecate@^1.0.1", "util-deprecate@~1.0.1": + "integrity" "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + "version" "1.0.2" + +"utils-merge@1.0.1": + "integrity" "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + "resolved" "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" + "version" "1.0.1" + +"vary@~1.1.2": + "integrity" "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + "resolved" "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + "version" "1.1.2" + +"vlq@^1.0.0": + "integrity" "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==" + "resolved" "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz" + "version" "1.0.1" + +"walker@^1.0.7": + "integrity" "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==" + "resolved" "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" + "version" "1.0.8" + dependencies: + "makeerror" "1.0.12" + +"wcwidth@^1.0.1": + "integrity" "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==" + "resolved" "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "defaults" "^1.0.3" + +"webidl-conversions@^3.0.0": + "integrity" "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "resolved" "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" + "version" "3.0.1" + +"whatwg-fetch@^3.0.0": + "integrity" "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + "resolved" "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz" + "version" "3.6.2" + +"whatwg-url@^5.0.0": + "integrity" "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==" + "resolved" "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "tr46" "~0.0.3" + "webidl-conversions" "^3.0.0" + +"which-boxed-primitive@^1.0.2": + "integrity" "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==" + "resolved" "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "is-bigint" "^1.0.1" + "is-boolean-object" "^1.1.0" + "is-number-object" "^1.0.4" + "is-string" "^1.0.5" + "is-symbol" "^1.0.3" + +"which-module@^2.0.0": + "integrity" "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" + "resolved" "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" + "version" "2.0.0" + +"which@^1.2.9": + "integrity" "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==" + "resolved" "https://registry.npmjs.org/which/-/which-1.3.1.tgz" + "version" "1.3.1" + dependencies: + "isexe" "^2.0.0" + +"which@^2.0.1": + "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" + "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "isexe" "^2.0.0" + +"word-wrap@^1.2.3": + "integrity" "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + "resolved" "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" + "version" "1.2.3" + +"wrap-ansi@^6.2.0": + "integrity" "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==" + "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" + "version" "6.2.0" + dependencies: + "ansi-styles" "^4.0.0" + "string-width" "^4.1.0" + "strip-ansi" "^6.0.0" + +"wrap-ansi@^7.0.0": + "integrity" "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==" + "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + "version" "7.0.0" + dependencies: + "ansi-styles" "^4.0.0" + "string-width" "^4.1.0" + "strip-ansi" "^6.0.0" + +"wrappy@1": + "integrity" "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "version" "1.0.2" + +"write-file-atomic@^2.3.0": + "integrity" "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==" + "resolved" "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz" + "version" "2.4.3" + dependencies: + "graceful-fs" "^4.1.11" + "imurmurhash" "^0.1.4" + "signal-exit" "^3.0.2" + +"ws@^6.1.4": + "integrity" "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==" + "resolved" "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz" + "version" "6.2.2" + dependencies: + "async-limiter" "~1.0.0" + +"ws@^7.5.1": + "integrity" "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==" + "resolved" "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" + "version" "7.5.9" + +"ws@^7": + "integrity" "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==" + "resolved" "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" + "version" "7.5.9" + +"ws@~8.11.0": + "integrity" "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==" + "resolved" "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz" + "version" "8.11.0" + +"xmlhttprequest-ssl@~2.0.0": + "integrity" "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" + "resolved" "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz" + "version" "2.0.0" + +"xtend@~4.0.1": + "integrity" "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + "resolved" "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" + "version" "4.0.2" + +"y18n@^4.0.0": + "integrity" "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + "resolved" "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz" + "version" "4.0.3" + +"y18n@^5.0.5": + "integrity" "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + "resolved" "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + "version" "5.0.8" + +"yallist@^3.0.2": + "integrity" "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "resolved" "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + "version" "3.1.1" + +"yallist@^4.0.0": + "integrity" "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "resolved" "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + "version" "4.0.0" + +"yargs-parser@^18.1.2": + "integrity" "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==" + "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" + "version" "18.1.3" + dependencies: + "camelcase" "^5.0.0" + "decamelize" "^1.2.0" + +"yargs-parser@^20.2.2": + "integrity" "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" + "version" "20.2.9" + +"yargs@^15.1.0", "yargs@^15.3.1": + "integrity" "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==" + "resolved" "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz" + "version" "15.4.1" + dependencies: + "cliui" "^6.0.0" + "decamelize" "^1.2.0" + "find-up" "^4.1.0" + "get-caller-file" "^2.0.1" + "require-directory" "^2.1.1" + "require-main-filename" "^2.0.0" + "set-blocking" "^2.0.0" + "string-width" "^4.2.0" + "which-module" "^2.0.0" + "y18n" "^4.0.0" + "yargs-parser" "^18.1.2" + +"yargs@^16.1.1": + "integrity" "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==" + "resolved" "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" + "version" "16.2.0" + dependencies: + "cliui" "^7.0.2" + "escalade" "^3.1.1" + "get-caller-file" "^2.0.5" + "require-directory" "^2.1.1" + "string-width" "^4.2.0" + "y18n" "^5.0.5" + "yargs-parser" "^20.2.2" + +"yocto-queue@^0.1.0": + "integrity" "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + "resolved" "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + "version" "0.1.0"