fix(lint) make sure eslint also runs on TypeScript files (#11777)

Co-authored-by: robertpin <robert.pin9@gmail.com>
Co-authored-by: Gabriel Borlea <gabriel.borlea@8x8.com>
This commit is contained in:
Saúl Ibarra Corretgé 2022-07-11 14:30:37 +02:00 committed by GitHub
parent 61a6ce2a2e
commit b0deb9ec0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 1063 additions and 200 deletions

647
package-lock.json generated
View File

@ -148,6 +148,8 @@
"@types/react-native": "0.67.6", "@types/react-native": "0.67.6",
"@types/react-redux": "7.1.24", "@types/react-redux": "7.1.24",
"@types/uuid": "8.3.4", "@types/uuid": "8.3.4",
"@typescript-eslint/eslint-plugin": "5.30.5",
"@typescript-eslint/parser": "5.30.4",
"babel-loader": "8.2.3", "babel-loader": "8.2.3",
"babel-plugin-optional-require": "0.3.1", "babel-plugin-optional-require": "0.3.1",
"circular-dependency-plugin": "5.2.0", "circular-dependency-plugin": "5.2.0",
@ -5644,6 +5646,392 @@
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
}, },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz",
"integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.30.5",
"@typescript-eslint/type-utils": "5.30.5",
"@typescript-eslint/utils": "5.30.5",
"debug": "^4.3.4",
"functional-red-black-tree": "^1.0.1",
"ignore": "^5.2.0",
"regexpp": "^3.2.0",
"semver": "^7.3.7",
"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": {
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz",
"integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.30.5",
"@typescript-eslint/visitor-keys": "5.30.5"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz",
"integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz",
"integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.30.5",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/eslint-plugin/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/@typescript-eslint/eslint-plugin/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,
"engines": {
"node": ">= 4"
}
},
"node_modules/@typescript-eslint/eslint-plugin/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,
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@typescript-eslint/parser": {
"version": "5.30.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.4.tgz",
"integrity": "sha512-/ge1HtU63wVoED4VnlU2o+FPFmi017bPYpeSrCmd8Ycsti4VSxXrmcpXXm7JpI4GT0Aa7qviabv1PEp6L5bboQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.30.4",
"@typescript-eslint/types": "5.30.4",
"@typescript-eslint/typescript-estree": "5.30.4",
"debug": "^4.3.4"
},
"engines": {
"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/@typescript-eslint/scope-manager": {
"version": "5.30.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.4.tgz",
"integrity": "sha512-DNzlQwGSiGefz71JwaHrpcaAX3zYkEcy8uVuan3YMKOa6qeW/y+7SaD8KIsIAruASwq6P+U4BjWBWtM2O+mwBQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.30.4",
"@typescript-eslint/visitor-keys": "5.30.4"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz",
"integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==",
"dev": true,
"dependencies": {
"@typescript-eslint/utils": "5.30.5",
"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": {
"eslint": "*"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.30.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.4.tgz",
"integrity": "sha512-NTEvqc+Vvu8Q6JeAKryHk2eqLKqsr2St3xhIjhOjQv5wQUBhaTuix4WOSacqj0ONWfKVU12Eug3LEAB95GBkMA==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.30.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.4.tgz",
"integrity": "sha512-V4VnEs6/J9/nNizaA12IeU4SAeEYaiKr7XndLNfV5+3zZSB4hIu6EhHJixTKhvIqA+EEHgBl6re8pivBMLLO1w==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.30.4",
"@typescript-eslint/visitor-keys": "5.30.4",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.3.7",
"tsutils": "^3.21.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/@typescript-eslint/typescript-estree/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,
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@typescript-eslint/utils": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz",
"integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.9",
"@typescript-eslint/scope-manager": "5.30.5",
"@typescript-eslint/types": "5.30.5",
"@typescript-eslint/typescript-estree": "5.30.5",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0"
},
"engines": {
"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"
}
},
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz",
"integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.30.5",
"@typescript-eslint/visitor-keys": "5.30.5"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz",
"integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz",
"integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.30.5",
"@typescript-eslint/visitor-keys": "5.30.5",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.3.7",
"tsutils": "^3.21.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/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz",
"integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.30.5",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/utils/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/@typescript-eslint/utils/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,
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.30.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.4.tgz",
"integrity": "sha512-ulKGse3mruSc8x6l8ORSc6+1ORyJzKmZeIaRTu/WpaF/jx3vHvEn5XZUKF9XaVg2710mFmTAUlLcLYLPp/Zf/Q==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.30.4",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/visitor-keys/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/@vladmandic/human": { "node_modules/@vladmandic/human": {
"version": "2.6.5", "version": "2.6.5",
"resolved": "https://registry.npmjs.org/@vladmandic/human/-/human-2.6.5.tgz", "resolved": "https://registry.npmjs.org/@vladmandic/human/-/human-2.6.5.tgz",
@ -18684,6 +19072,27 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
}, },
"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": { "node_modules/type-check": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@ -24339,6 +24748,227 @@
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
}, },
"@typescript-eslint/eslint-plugin": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz",
"integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.30.5",
"@typescript-eslint/type-utils": "5.30.5",
"@typescript-eslint/utils": "5.30.5",
"debug": "^4.3.4",
"functional-red-black-tree": "^1.0.1",
"ignore": "^5.2.0",
"regexpp": "^3.2.0",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
},
"dependencies": {
"@typescript-eslint/scope-manager": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz",
"integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.30.5",
"@typescript-eslint/visitor-keys": "5.30.5"
}
},
"@typescript-eslint/types": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz",
"integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==",
"dev": true
},
"@typescript-eslint/visitor-keys": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz",
"integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.30.5",
"eslint-visitor-keys": "^3.3.0"
}
},
"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
},
"ignore": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
"dev": true
},
"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,
"requires": {
"lru-cache": "^6.0.0"
}
}
}
},
"@typescript-eslint/parser": {
"version": "5.30.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.4.tgz",
"integrity": "sha512-/ge1HtU63wVoED4VnlU2o+FPFmi017bPYpeSrCmd8Ycsti4VSxXrmcpXXm7JpI4GT0Aa7qviabv1PEp6L5bboQ==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.30.4",
"@typescript-eslint/types": "5.30.4",
"@typescript-eslint/typescript-estree": "5.30.4",
"debug": "^4.3.4"
}
},
"@typescript-eslint/scope-manager": {
"version": "5.30.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.4.tgz",
"integrity": "sha512-DNzlQwGSiGefz71JwaHrpcaAX3zYkEcy8uVuan3YMKOa6qeW/y+7SaD8KIsIAruASwq6P+U4BjWBWtM2O+mwBQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.30.4",
"@typescript-eslint/visitor-keys": "5.30.4"
}
},
"@typescript-eslint/type-utils": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz",
"integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==",
"dev": true,
"requires": {
"@typescript-eslint/utils": "5.30.5",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/types": {
"version": "5.30.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.4.tgz",
"integrity": "sha512-NTEvqc+Vvu8Q6JeAKryHk2eqLKqsr2St3xhIjhOjQv5wQUBhaTuix4WOSacqj0ONWfKVU12Eug3LEAB95GBkMA==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "5.30.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.4.tgz",
"integrity": "sha512-V4VnEs6/J9/nNizaA12IeU4SAeEYaiKr7XndLNfV5+3zZSB4hIu6EhHJixTKhvIqA+EEHgBl6re8pivBMLLO1w==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.30.4",
"@typescript-eslint/visitor-keys": "5.30.4",
"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.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
}
}
},
"@typescript-eslint/utils": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz",
"integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.9",
"@typescript-eslint/scope-manager": "5.30.5",
"@typescript-eslint/types": "5.30.5",
"@typescript-eslint/typescript-estree": "5.30.5",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0"
},
"dependencies": {
"@typescript-eslint/scope-manager": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz",
"integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.30.5",
"@typescript-eslint/visitor-keys": "5.30.5"
}
},
"@typescript-eslint/types": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz",
"integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz",
"integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.30.5",
"@typescript-eslint/visitor-keys": "5.30.5",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz",
"integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.30.5",
"eslint-visitor-keys": "^3.3.0"
}
},
"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
},
"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,
"requires": {
"lru-cache": "^6.0.0"
}
}
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.30.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.4.tgz",
"integrity": "sha512-ulKGse3mruSc8x6l8ORSc6+1ORyJzKmZeIaRTu/WpaF/jx3vHvEn5XZUKF9XaVg2710mFmTAUlLcLYLPp/Zf/Q==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.30.4",
"eslint-visitor-keys": "^3.3.0"
},
"dependencies": {
"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
}
}
},
"@vladmandic/human": { "@vladmandic/human": {
"version": "2.6.5", "version": "2.6.5",
"resolved": "https://registry.npmjs.org/@vladmandic/human/-/human-2.6.5.tgz", "resolved": "https://registry.npmjs.org/@vladmandic/human/-/human-2.6.5.tgz",
@ -34413,6 +35043,23 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
}, },
"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": { "type-check": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",

View File

@ -153,6 +153,8 @@
"@types/react-native": "0.67.6", "@types/react-native": "0.67.6",
"@types/react-redux": "7.1.24", "@types/react-redux": "7.1.24",
"@types/uuid": "8.3.4", "@types/uuid": "8.3.4",
"@typescript-eslint/eslint-plugin": "5.30.5",
"@typescript-eslint/parser": "5.30.4",
"babel-loader": "8.2.3", "babel-loader": "8.2.3",
"babel-plugin-optional-require": "0.3.1", "babel-plugin-optional-require": "0.3.1",
"circular-dependency-plugin": "5.2.0", "circular-dependency-plugin": "5.2.0",
@ -188,9 +190,9 @@
}, },
"license": "Apache-2.0", "license": "Apache-2.0",
"scripts": { "scripts": {
"lint": "eslint --max-warnings 0 .", "lint": "eslint --ext .js,.ts,.tsx --max-warnings 0 .",
"lang-sort": "./resources/lang-sort.sh", "lang-sort": "./resources/lang-sort.sh",
"lint-fix": "eslint --max-warnings 0 --fix .", "lint-fix": "eslint --ext .js,.ts,.tsx --max-warnings 0 --fix .",
"postinstall": "patch-package --error-on-fail && jetify", "postinstall": "patch-package --error-on-fail && jetify",
"validate": "npm ls", "validate": "npm ls",
"start": "make dev" "start": "make dev"

View File

@ -6,6 +6,27 @@ module.exports = {
'@jitsi/eslint-config/react', '@jitsi/eslint-config/react',
'.eslintrc-react-native.js' '.eslintrc-react-native.js'
], ],
'overrides': [
{
'files': [ '*.ts', '*.tsx' ],
parser: '@typescript-eslint/parser',
rules: {
'no-undef': 'off',
'no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'no-prototype-builtins': 'off'
},
'plugins': [ '@typescript-eslint' ],
'extends': [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended'
]
}
],
'rules': { 'rules': {
'flowtype/no-types-missing-file-annotation': 0, 'flowtype/no-types-missing-file-annotation': 0,

View File

@ -44,7 +44,7 @@ export * from './actions.any';
* scheme, or a mere room name. * scheme, or a mere room name.
* @returns {Function} * @returns {Function}
*/ */
export function appNavigate(uri: ?string) { export function appNavigate(uri?: string) {
logger.info(`appNavigate to ${uri}`); logger.info(`appNavigate to ${uri}`);
return async (dispatch: Dispatch<any>, getState: Function) => { return async (dispatch: Dispatch<any>, getState: Function) => {

View File

@ -1,10 +1,10 @@
import { IAnalyticsState } from "../analytics/reducer" import { IAnalyticsState } from '../analytics/reducer';
import { IAuthenticationState } from "../authentication/reducer" import { IAuthenticationState } from '../authentication/reducer';
import { IAVModerationState } from "../av-moderation/reducer" import { IAVModerationState } from '../av-moderation/reducer';
import { IAppState } from "../base/app/reducer" import { IAppState } from '../base/app/reducer';
import { IAudioOnlyState } from "../base/audio-only/reducer" import { IAudioOnlyState } from '../base/audio-only/reducer';
import { IConferenceState } from "../base/conference/reducer" import { IConferenceState } from '../base/conference/reducer';
import { IConfig } from "../base/config/configType" import { IConfig } from '../base/config/configType';
export interface IStore { export interface IStore {
getState: Function, getState: Function,

View File

@ -1,6 +1,8 @@
/* eslint-disable import/order */
import ReducerRegistry from '../base/redux/ReducerRegistry';
// @ts-ignore // @ts-ignore
import { assign } from '../base/redux/functions'; import { assign } from '../base/redux/functions';
import ReducerRegistry from '../base/redux/ReducerRegistry';
import { import {
CANCEL_LOGIN, CANCEL_LOGIN,

View File

@ -1,4 +1,4 @@
import { MEDIA_TYPE, type MediaType } from '../base/media/constants'; import { MEDIA_TYPE } from '../base/media/constants';
/** /**
* Mapping between a media type and the witelist reducer key. * Mapping between a media type and the witelist reducer key.

View File

@ -3,6 +3,7 @@ import type { MediaType } from '../base/media/constants';
import { import {
PARTICIPANT_LEFT, PARTICIPANT_LEFT,
PARTICIPANT_UPDATED PARTICIPANT_UPDATED
// @ts-ignore // @ts-ignore
} from '../base/participants'; } from '../base/participants';
import ReducerRegistry from '../base/redux/ReducerRegistry'; import ReducerRegistry from '../base/redux/ReducerRegistry';
@ -52,7 +53,7 @@ function _updatePendingParticipant(mediaType: MediaType, participant: any, state
let arrayItemChanged = false; let arrayItemChanged = false;
const storeKey = MEDIA_TYPE_TO_PENDING_STORE_KEY[mediaType]; const storeKey = MEDIA_TYPE_TO_PENDING_STORE_KEY[mediaType];
const arr = state[storeKey]; const arr = state[storeKey];
const newArr = arr.map((pending: { id: string} ) => { const newArr = arr.map((pending: { id: string}) => {
if (pending.id === participant.id) { if (pending.id === participant.id) {
arrayItemChanged = true; arrayItemChanged = true;

View File

@ -1,9 +1,13 @@
/* eslint-disable import/order */
// @ts-ignore // @ts-ignore
import { LOCKED_LOCALLY, LOCKED_REMOTELY } from '../../room-lock'; import { LOCKED_LOCALLY, LOCKED_REMOTELY } from '../../room-lock';
// @ts-ignore // @ts-ignore
import { CONNECTION_WILL_CONNECT, SET_LOCATION_URL } from '../connection'; import { CONNECTION_WILL_CONNECT, SET_LOCATION_URL } from '../connection';
// @ts-ignore // @ts-ignore
import { JitsiConferenceErrors } from '../lib-jitsi-meet'; import { JitsiConferenceErrors } from '../lib-jitsi-meet';
// @ts-ignore // @ts-ignore
import { assign, set } from '../redux'; import { assign, set } from '../redux';
import ReducerRegistry from '../redux/ReducerRegistry'; import ReducerRegistry from '../redux/ReducerRegistry';
@ -28,6 +32,7 @@ import {
SET_START_MUTED_POLICY, SET_START_MUTED_POLICY,
SET_START_REACTIONS_MUTED SET_START_REACTIONS_MUTED
} from './actionTypes'; } from './actionTypes';
// @ts-ignore // @ts-ignore
import { isRoomValid } from './functions'; import { isRoomValid } from './functions';
@ -376,7 +381,8 @@ function _p2pStatusChanged(state: any, action: any) {
* @returns {Object} The new state of the feature base/conference after the * @returns {Object} The new state of the feature base/conference after the
* reduction of the specified action. * reduction of the specified action.
*/ */
function _setPassword(state: any, { conference, method, password }: {conference: any, method: Object, password: string}) { function _setPassword(state: any, { conference, method, password }
: {conference: any, method: Object, password: string}) {
switch (method) { switch (method) {
case conference.join: case conference.join:
return assign(state, { return assign(state, {

View File

@ -187,7 +187,7 @@ export interface IConfig {
notifyAllParticipants?: boolean; notifyAllParticipants?: boolean;
}; };
transcribingEnabled?: boolean; transcribingEnabled?: boolean;
transcribeWithAppLanguage?: boolean; transcribeWithAppLanguage?: boolean;
preferredTranscribeLanguage?: string; preferredTranscribeLanguage?: string;
autoCaptionOnRecord?: boolean; autoCaptionOnRecord?: boolean;
transcription?: { transcription?: {
@ -464,4 +464,4 @@ export interface IConfig {
tileTime?: number; tileTime?: number;
}; };
locationURL?: string; locationURL?: string;
} }

View File

@ -1,6 +1,8 @@
/* eslint-disable import/order */
import _ from 'lodash'; import _ from 'lodash';
import { CONFERENCE_INFO } from '../../conference/components/constants'; import { CONFERENCE_INFO } from '../../conference/components/constants';
// @ts-ignore // @ts-ignore
import { equals } from '../redux'; import { equals } from '../redux';
import ReducerRegistry from '../redux/ReducerRegistry'; import ReducerRegistry from '../redux/ReducerRegistry';
@ -13,10 +15,11 @@ import {
OVERWRITE_CONFIG OVERWRITE_CONFIG
} from './actionTypes'; } from './actionTypes';
import { IConfig } from './configType'; import { IConfig } from './configType';
// @ts-ignore // @ts-ignore
import { _cleanupConfig } from './functions'; import { _cleanupConfig } from './functions';
declare var interfaceConfig: any; declare let interfaceConfig: any;
/** /**
* The initial state of the feature base/config when executing in a * The initial state of the feature base/config when executing in a
@ -307,15 +310,18 @@ function _translateLegacyConfig(oldValue: IConfig) {
filteredConferenceInfo.forEach(key => { filteredConferenceInfo.forEach(key => {
newValue.conferenceInfo = oldValue.conferenceInfo ?? {}; newValue.conferenceInfo = oldValue.conferenceInfo ?? {};
// hideRecordingLabel does not mean not render it at all, but autoHide it // hideRecordingLabel does not mean not render it at all, but autoHide it
if (key === 'hideRecordingLabel') { if (key === 'hideRecordingLabel') {
newValue.conferenceInfo.alwaysVisible newValue.conferenceInfo.alwaysVisible
= (newValue.conferenceInfo?.alwaysVisible ?? []).filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c)); = (newValue.conferenceInfo?.alwaysVisible ?? [])
.filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
newValue.conferenceInfo.autoHide newValue.conferenceInfo.autoHide
= _.union(newValue.conferenceInfo.autoHide, CONFERENCE_HEADER_MAPPING[key]); = _.union(newValue.conferenceInfo.autoHide, CONFERENCE_HEADER_MAPPING[key]);
} else { } else {
newValue.conferenceInfo.alwaysVisible newValue.conferenceInfo.alwaysVisible
= (newValue.conferenceInfo.alwaysVisible ?? []).filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c)); = (newValue.conferenceInfo.alwaysVisible ?? [])
.filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
newValue.conferenceInfo.autoHide newValue.conferenceInfo.autoHide
= (newValue.conferenceInfo.autoHide ?? []).filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c)); = (newValue.conferenceInfo.autoHide ?? []).filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
} }

View File

@ -15,6 +15,6 @@ const BottomSheetContainer: () => JSX.Element = () => {
{ React.createElement(sheet, sheetProps) } { React.createElement(sheet, sheetProps) }
</Fragment> </Fragment>
); );
} };
export default BottomSheetContainer; export default BottomSheetContainer;

View File

@ -1,16 +1,23 @@
/* eslint-disable import/order */
import './middleware.any.js'; import './middleware.any.js';
// @ts-ignore
import { MiddlewareRegistry } from '../redux';
import { IStore } from '../../app/types'; import { IStore } from '../../app/types';
import { SET_VIDEO_MUTED } from './actionTypes';
import LocalRecordingManager from '../../recording/components/Recording/LocalRecordingManager.web';
// @ts-ignore
import { openDialog } from '../dialog';
// @ts-ignore // @ts-ignore
import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../../notifications'; import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../../notifications';
import LocalRecordingManager from '../../recording/components/Recording/LocalRecordingManager.web';
// @ts-ignore // @ts-ignore
import StopRecordingDialog from '../../recording/components/Recording/web/StopRecordingDialog'; import StopRecordingDialog from '../../recording/components/Recording/web/StopRecordingDialog';
// @ts-ignore
import { openDialog } from '../dialog';
// @ts-ignore
import { MiddlewareRegistry } from '../redux';
import { SET_VIDEO_MUTED } from './actionTypes';
/** /**
* Implements the entry point of the middleware of the feature base/media. * Implements the entry point of the middleware of the feature base/media.
* *
@ -19,22 +26,24 @@ import StopRecordingDialog from '../../recording/components/Recording/web/StopRe
*/ */
MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: any) => { MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: any) => {
const { dispatch } = store; const { dispatch } = store;
switch(action.type) {
case SET_VIDEO_MUTED: {
if (LocalRecordingManager.isRecordingLocally() && LocalRecordingManager.selfRecording.on) {
if (action.muted && LocalRecordingManager.selfRecording.withVideo) {
dispatch(openDialog(StopRecordingDialog, { localRecordingVideoStop: true }));
return; switch (action.type) {
} else if (!action.muted && !LocalRecordingManager.selfRecording.withVideo) { case SET_VIDEO_MUTED: {
dispatch(showNotification({ if (LocalRecordingManager.isRecordingLocally() && LocalRecordingManager.selfRecording.on) {
titleKey: 'recording.localRecordingNoVideo', if (action.muted && LocalRecordingManager.selfRecording.withVideo) {
descriptionKey: 'recording.localRecordingVideoWarning', dispatch(openDialog(StopRecordingDialog, { localRecordingVideoStop: true }));
uid: 'recording.localRecordingNoVideo'
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); return;
} } else if (!action.muted && !LocalRecordingManager.selfRecording.withVideo) {
dispatch(showNotification({
titleKey: 'recording.localRecordingNoVideo',
descriptionKey: 'recording.localRecordingVideoWarning',
uid: 'recording.localRecordingNoVideo'
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
} }
} }
} }
}
return next(action); return next(action);
}); });

View File

@ -7,10 +7,11 @@ import {
} from 'react-native-paper'; } from 'react-native-paper';
import BaseTheme from '../../../ui/components/BaseTheme.native'; import BaseTheme from '../../../ui/components/BaseTheme.native';
import styles from './styles';
import { BUTTON_MODES, BUTTON_TYPES } from '../../constants'; import { BUTTON_MODES, BUTTON_TYPES } from '../../constants';
import { ButtonProps } from '../../types'; import { ButtonProps } from '../../types';
import styles from './styles';
const Button: React.FC<ButtonProps> = ({ const Button: React.FC<ButtonProps> = ({
accessibilityLabel, accessibilityLabel,
@ -35,16 +36,16 @@ const Button: React.FC<ButtonProps> = ({
if (type === PRIMARY) { if (type === PRIMARY) {
buttonLabelStyles = styles.buttonLabelPrimary; buttonLabelStyles = styles.buttonLabelPrimary;
color = BaseTheme.palette.action01; color = BaseTheme.palette.action01;
mode = CONTAINED mode = CONTAINED;
} else if (type === SECONDARY) { } else if (type === SECONDARY) {
buttonLabelStyles = styles.buttonLabelSecondary; buttonLabelStyles = styles.buttonLabelSecondary;
color = BaseTheme.palette.action02; color = BaseTheme.palette.action02;
mode = CONTAINED mode = CONTAINED;
} else if (type === DESTRUCTIVE) { } else if (type === DESTRUCTIVE) {
color = BaseTheme.palette.actionDanger; color = BaseTheme.palette.actionDanger;
buttonLabelStyles = styles.buttonLabelDestructive; buttonLabelStyles = styles.buttonLabelDestructive;
mode = CONTAINED mode = CONTAINED;
} else { } else {
color = buttonColor; color = buttonColor;
buttonLabelStyles = styles.buttonLabel; buttonLabelStyles = styles.buttonLabel;
} }
@ -56,7 +57,7 @@ const Button: React.FC<ButtonProps> = ({
buttonStyles = styles.button; buttonStyles = styles.button;
} }
if ( type === TERTIARY) { if (type === TERTIARY) {
return ( return (
<TouchableRipple <TouchableRipple
accessibilityLabel = { accessibilityLabel } accessibilityLabel = { accessibilityLabel }
@ -69,9 +70,9 @@ const Button: React.FC<ButtonProps> = ({
] }> ] }>
<Text <Text
style = { [ style = { [
buttonLabelStyles, buttonLabelStyles,
labelStyle labelStyle
] }>{ t(label) }</Text> ] }>{ t(label) }</Text>
</TouchableRipple> </TouchableRipple>
); );
} }

View File

@ -3,10 +3,11 @@ import { TouchableRipple } from 'react-native-paper';
import { Icon } from '../../../icons'; import { Icon } from '../../../icons';
import BaseTheme from '../../../ui/components/BaseTheme.native'; import BaseTheme from '../../../ui/components/BaseTheme.native';
import styles from './styles';
import { BUTTON_TYPES } from '../../constants'; import { BUTTON_TYPES } from '../../constants';
import { IconButtonProps } from '../../types'; import { IconButtonProps } from '../../types';
import styles from './styles';
const IconButton: React.FC<IconButtonProps> = ({ const IconButton: React.FC<IconButtonProps> = ({
accessibilityLabel, accessibilityLabel,
@ -33,7 +34,7 @@ const IconButton: React.FC<IconButtonProps> = ({
color = BaseTheme.palette.icon02; color = BaseTheme.palette.icon02;
iconButtonContainerStyles = styles.iconButtonContainerSecondary; iconButtonContainerStyles = styles.iconButtonContainerSecondary;
rippleColor = BaseTheme.palette.action02; rippleColor = BaseTheme.palette.action02;
} else if ( type === TERTIARY) { } else if (type === TERTIARY) {
color = BaseTheme.palette.icon01; color = BaseTheme.palette.icon01;
iconButtonContainerStyles = styles.iconButtonContainer; iconButtonContainerStyles = styles.iconButtonContainer;
rippleColor = BaseTheme.palette.action03; rippleColor = BaseTheme.palette.action03;

View File

@ -5,14 +5,14 @@ import type { Reducer } from 'redux';
* The type of the dictionary/map which associates a reducer (function) with the * The type of the dictionary/map which associates a reducer (function) with the
* name of he Redux state property managed by the reducer. * name of he Redux state property managed by the reducer.
*/ */
declare type NameReducerMap<S, A> = { [name: string]: Reducer<S, Action<any>> }; type NameReducerMap<S> = { [name: string]: Reducer<S, Action<any>> };
/** /**
* A registry for Redux reducers, allowing features to register themselves * A registry for Redux reducers, allowing features to register themselves
* without needing to create additional inter-feature dependencies. * without needing to create additional inter-feature dependencies.
*/ */
class ReducerRegistry { class ReducerRegistry {
_elements: NameReducerMap<any, any>; _elements: NameReducerMap<any>;
/** /**
* Creates a ReducerRegistry instance. * Creates a ReducerRegistry instance.
@ -35,7 +35,7 @@ class ReducerRegistry {
* included (such as reducers from third-party modules). * included (such as reducers from third-party modules).
* @returns {Function} * @returns {Function}
*/ */
combineReducers(additional: NameReducerMap<any, any> = {}) { combineReducers(additional: NameReducerMap<any> = {}) {
// $FlowExpectedError // $FlowExpectedError
return combineReducers({ return combineReducers({
...this._elements, ...this._elements,

View File

@ -1,7 +1,7 @@
/** /**
* Checks whether we are loaded in iframe. * Checks whether we are loaded in iframe.
* *
* @returns Whether the current page is loaded in an iframe. * @returns {boolean} Whether the current page is loaded in an iframe.
*/ */
export function inIframe(): boolean { export function inIframe(): boolean {
if (navigator.product === 'ReactNative') { if (navigator.product === 'ReactNative') {

View File

@ -5,9 +5,9 @@ import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
/** /**
* React component for Audio icon. * React component for Audio icon.
* *
* @returns {JSX.Element} - the Audio icon. * @returns {JSX.Element} - The Audio icon.
* *
*/ */
const AudioIcon = () : JSX.Element => (<Icon const AudioIcon = () : JSX.Element => (<Icon
color = { BaseTheme.palette.text06 } color = { BaseTheme.palette.text06 }

View File

@ -5,8 +5,8 @@ import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
/** /**
* Implements an end meeting icon. * Implements an end meeting icon.
* *
* @returns {JSX.Element} - the end meeting icon. * @returns {JSX.Element} - The end meeting icon.
*/ */
const EndMeetingIcon = () : JSX.Element => (<Icon const EndMeetingIcon = () : JSX.Element => (<Icon
color = { BaseTheme.palette.icon01 } color = { BaseTheme.palette.icon01 }

View File

@ -1,14 +1,13 @@
import React, { useCallback } from 'react'; import React, { useCallback, useState } from 'react';
import { useState } from 'react';
import { View, TouchableOpacity } from 'react-native'; import { View, TouchableOpacity } from 'react-native';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { import {
createShortcutEvent, createShortcutEvent,
sendAnalytics, sendAnalytics,
ACTION_SHORTCUT_PRESSED as PRESSED, ACTION_SHORTCUT_PRESSED as PRESSED,
ACTION_SHORTCUT_RELEASED as RELEASED ACTION_SHORTCUT_RELEASED as RELEASED
} from '../../../../analytics'; } from '../../../../analytics';
import { getFeatureFlag, AUDIO_MUTE_BUTTON_ENABLED } from '../../../../base/flags'; import { getFeatureFlag, AUDIO_MUTE_BUTTON_ENABLED } from '../../../../base/flags';
import { Icon, IconMicrophone, IconMicrophoneEmptySlash } from '../../../../base/icons'; import { Icon, IconMicrophone, IconMicrophoneEmptySlash } from '../../../../base/icons';
import { MEDIA_TYPE } from '../../../../base/media'; import { MEDIA_TYPE } from '../../../../base/media';
@ -41,7 +40,7 @@ const MicrophoneButton = () : JSX.Element => {
}, [ audioMuted, disabled ]); }, [ audioMuted, disabled ]);
const onLongPress = useCallback(() => { const onLongPress = useCallback(() => {
if ( !disabled && !audioMuted) { if (!disabled && !audioMuted) {
sendAnalytics(createShortcutEvent( sendAnalytics(createShortcutEvent(
'push.to.talk', 'push.to.talk',
PRESSED, PRESSED,
@ -49,7 +48,7 @@ const MicrophoneButton = () : JSX.Element => {
LONG_PRESS)); LONG_PRESS));
setLongPress(true); setLongPress(true);
} }
}, [audioMuted, disabled, setLongPress]); }, [ audioMuted, disabled, setLongPress ]);
const onPressOut = useCallback(() => { const onPressOut = useCallback(() => {
if (longPress) { if (longPress) {
@ -62,13 +61,13 @@ const MicrophoneButton = () : JSX.Element => {
)); ));
dispatch(muteLocal(true, MEDIA_TYPE.AUDIO)); dispatch(muteLocal(true, MEDIA_TYPE.AUDIO));
} }
}, [longPress, setLongPress]); }, [ longPress, setLongPress ]);
return ( return (
<TouchableOpacity <TouchableOpacity
onLongPress = { onLongPress }
onPressIn = { onPressIn } onPressIn = { onPressIn }
onLongPress={ onLongPress } onPressOut = { onPressOut } >
onPressOut={ onPressOut } >
<View <View
style = { [ style = { [
styles.microphoneStyles.container, styles.microphoneStyles.container,

View File

@ -1,16 +1,16 @@
import React from 'react'; import React from 'react';
import { StyleProp, Text, View, ViewStyle } from 'react-native';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { Text, View } from 'react-native';
import { getConferenceName } from '../../../../base/conference/functions'; import { getConferenceName } from '../../../../base/conference/functions';
import { ConnectionIndicator } from '../../../../connection-indicator';
import { getFeatureFlag, MEETING_NAME_ENABLED } from '../../../../base/flags'; import { getFeatureFlag, MEETING_NAME_ENABLED } from '../../../../base/flags';
import { JitsiRecordingConstants } from '../../../../base/lib-jitsi-meet'; import { JitsiRecordingConstants } from '../../../../base/lib-jitsi-meet';
import { connect } from '../../../../base/redux';; import { getLocalParticipant } from '../../../../base/participants';
import { RecordingLabel } from '../../../../recording'; import { connect } from '../../../../base/redux';
import ConnectionIndicator from '../../../../connection-indicator/components/native/ConnectionIndicator';
import RecordingLabel from '../../../../recording/components/native/RecordingLabel';
import { VideoQualityLabel } from '../../../../video-quality'; import { VideoQualityLabel } from '../../../../video-quality';
import { getLocalParticipant } from '../../../../base/participants';
import styles from './styles'; import styles from './styles';
@ -36,30 +36,30 @@ type Props = {
* @returns {JSX.Element} * @returns {JSX.Element}
*/ */
const TitleBar = (props: Props) : JSX.Element => { const TitleBar = (props: Props) : JSX.Element => {
const localParticipant = useSelector(getLocalParticipant); const localParticipant = useSelector(getLocalParticipant);
const localParticipantId = localParticipant?.id; const localParticipantId = localParticipant?.id;
return (<> return (<>
<View <View
pointerEvents = 'box-none' pointerEvents = 'box-none'
style = { styles.titleBarWrapper }> style = { styles.titleBarWrapper as StyleProp<ViewStyle> }>
<View <View
pointerEvents = 'box-none' pointerEvents = 'box-none'
style = { styles.roomNameWrapper }> style = { styles.roomNameWrapper as StyleProp<ViewStyle> }>
<View style = { styles.qualityLabelContainer }> <View style = { styles.qualityLabelContainer as StyleProp<ViewStyle> }>
<VideoQualityLabel /> <VideoQualityLabel />
</View> </View>
<ConnectionIndicator <ConnectionIndicator
participantId = { localParticipantId } iconStyle = { styles.connectionIndicatorIcon }
iconStyle = { styles.connectionIndicatorIcon } /> participantId = { localParticipantId } />
<View style = { styles.headerLabels }> <View style = { styles.headerLabels as StyleProp<ViewStyle> }>
<RecordingLabel mode = { JitsiRecordingConstants.mode.FILE } /> <RecordingLabel mode = { JitsiRecordingConstants.mode.FILE } />
<RecordingLabel mode = { JitsiRecordingConstants.mode.STREAM } /> <RecordingLabel mode = { JitsiRecordingConstants.mode.STREAM } />
</View> </View>
{ {
props._meetingNameEnabled props._meetingNameEnabled
&& <View style = { styles.roomNameView }> && <View style = { styles.roomNameView as StyleProp<ViewStyle> }>
<Text <Text
numberOfLines = { 1 } numberOfLines = { 1 }
style = { styles.roomName }> style = { styles.roomName }>
@ -70,7 +70,7 @@ const TitleBar = (props: Props) : JSX.Element => {
</View> </View>
</View> </View>
</>); </>);
} };
/** /**
* Maps part of the Redux store to the props of this component. * Maps part of the Redux store to the props of this component.

View File

@ -1,13 +1,17 @@
/* eslint-disable import/order */
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
// @ts-ignore // @ts-ignore
import { IconMenuDown } from '../../../base/icons'; import { IconMenuDown } from '../../../base/icons';
// @ts-ignore // @ts-ignore
import { Label } from '../../../base/label'; import { Label } from '../../../base/label';
// @ts-ignore // @ts-ignore
import { Tooltip } from '../../../base/tooltip'; import { Tooltip } from '../../../base/tooltip';
// @ts-ignore // @ts-ignore
import { setTopPanelVisible } from '../../../filmstrip/actions.web'; import { setTopPanelVisible } from '../../../filmstrip/actions.web';
@ -20,11 +24,11 @@ const ToggleTopPanelLabel = () => {
}, []); }, []);
return topPanelHidden && (<Tooltip return topPanelHidden && (<Tooltip
content={t('toggleTopPanelLabel') } content = { t('toggleTopPanelLabel') }
position = { 'bottom' }> position = { 'bottom' }>
<Label <Label
icon={IconMenuDown} icon = { IconMenuDown }
onClick = { onClick }/> onClick = { onClick } />
</Tooltip>); </Tooltip>);
}; };

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { Image } from 'react-native'; import { Image, ImageStyle, StyleProp, ViewStyle } from 'react-native';
import { SvgUri } from 'react-native-svg'; import { SvgUri } from 'react-native-svg';
// @ts-ignore // @ts-ignore
@ -40,7 +40,7 @@ const BrandingImageBackground: React.FC<Props> = ({ uri }:Props) => {
// Align the <min-y> of the element's viewBox // Align the <min-y> of the element's viewBox
// with the smallest Y value of the viewport. // with the smallest Y value of the viewport.
preserveAspectRatio = 'xMinYMin' preserveAspectRatio = 'xMinYMin'
style = { styles.brandingImageBackgroundSvg } style = { styles.brandingImageBackgroundSvg as StyleProp<ViewStyle> }
uri = { imgSrc } uri = { imgSrc }
viewBox = '0 0 400 650' viewBox = '0 0 400 650'
width = '100%' /> width = '100%' />
@ -50,7 +50,7 @@ const BrandingImageBackground: React.FC<Props> = ({ uri }:Props) => {
= ( = (
<Image <Image
source = {{ uri: imgSrc }} source = {{ uri: imgSrc }}
style = { styles.brandingImageBackground } /> style = { styles.brandingImageBackground as StyleProp<ImageStyle> } />
); );
} }

View File

@ -4,12 +4,12 @@ export default {
* {@code BrandingImageBackground} Style. * {@code BrandingImageBackground} Style.
*/ */
brandingImageBackgroundSvg: { brandingImageBackgroundSvg: {
position: 'absolute' as 'absolute' position: 'absolute'
}, },
brandingImageBackground: { brandingImageBackground: {
height: '100%', height: '100%',
position: 'absolute' as 'absolute', position: 'absolute',
width: '100%' width: '100%'
} }
}; };

View File

@ -36,7 +36,7 @@ export interface FaceLandmarksHelper {
} }
/** /**
* Helper class for human library * Helper class for human library.
*/ */
export class HumanHelper implements FaceLandmarksHelper { export class HumanHelper implements FaceLandmarksHelper {
protected human: Human | undefined; protected human: Human | undefined;
@ -44,6 +44,7 @@ export class HumanHelper implements FaceLandmarksHelper {
protected baseUrl: string; protected baseUrl: string;
private detectionInProgress = false; private detectionInProgress = false;
private lastValidFaceBox: FaceBox | undefined; private lastValidFaceBox: FaceBox | undefined;
/** /**
* Configuration for human. * Configuration for human.
*/ */
@ -66,7 +67,7 @@ export class HumanHelper implements FaceLandmarksHelper {
}, },
mesh: { enabled: false }, mesh: { enabled: false },
iris: { enabled: false }, iris: { enabled: false },
emotion: { emotion: {
enabled: false, enabled: false,
modelPath: 'emotion.json' modelPath: 'emotion.json'
}, },
@ -78,12 +79,23 @@ export class HumanHelper implements FaceLandmarksHelper {
segmentation: { enabled: false } segmentation: { enabled: false }
}; };
/**
* Constructor function for the helper which initialize the helper.
*
* @param {InitInput} input - The input for the helper.
* @returns {void}
*/
constructor({ baseUrl, detectionTypes }: InitInput) { constructor({ baseUrl, detectionTypes }: InitInput) {
this.faceDetectionTypes = detectionTypes; this.faceDetectionTypes = detectionTypes;
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
this.init(); this.init();
} }
/**
* Initializes the human helper with the available tfjs backend for the given detection types.
*
* @returns {Promise<void>}
*/
async init(): Promise<void> { async init(): Promise<void> {
if (!this.human) { if (!this.human) {
@ -95,7 +107,7 @@ export class HumanHelper implements FaceLandmarksHelper {
} }
if (this.faceDetectionTypes.length > 0 && this.config.face) { if (this.faceDetectionTypes.length > 0 && this.config.face) {
this.config.face.enabled = true this.config.face.enabled = true;
} }
if (this.faceDetectionTypes.includes(DETECTION_TYPES.FACE_BOX) && this.config.face?.detector) { if (this.faceDetectionTypes.includes(DETECTION_TYPES.FACE_BOX) && this.config.face?.detector) {
@ -107,16 +119,24 @@ export class HumanHelper implements FaceLandmarksHelper {
} }
const initialHuman = new Human(this.config); const initialHuman = new Human(this.config);
try { try {
await initialHuman.load(); await initialHuman.load();
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
this.human = initialHuman; this.human = initialHuman;
} }
} }
/**
* Gets the face box from the detections, if there is no valid detections it will return undefined..
*
* @param {Array<FaceResult>} detections - The array with the detections.
* @param {number} threshold - Face box position change threshold.
* @returns {FaceBox | undefined}
*/
getFaceBox(detections: Array<FaceResult>, threshold: number): FaceBox | undefined { getFaceBox(detections: Array<FaceResult>, threshold: number): FaceBox | undefined {
if (this.getFaceCount(detections) !== 1) { if (this.getFaceCount(detections) !== 1) {
return; return;
@ -127,18 +147,24 @@ export class HumanHelper implements FaceLandmarksHelper {
left: Math.round(detections[0].boxRaw[0] * 100), left: Math.round(detections[0].boxRaw[0] * 100),
right: Math.round((detections[0].boxRaw[0] + detections[0].boxRaw[2]) * 100) right: Math.round((detections[0].boxRaw[0] + detections[0].boxRaw[2]) * 100)
}; };
faceBox.width = Math.round(faceBox.right - faceBox.left); faceBox.width = Math.round(faceBox.right - faceBox.left);
if (this.lastValidFaceBox && threshold && Math.abs(this.lastValidFaceBox.left - faceBox.left) < threshold) { if (this.lastValidFaceBox && threshold && Math.abs(this.lastValidFaceBox.left - faceBox.left) < threshold) {
return; return;
} }
this.lastValidFaceBox = faceBox; this.lastValidFaceBox = faceBox;
return faceBox; return faceBox;
} }
/**
* Gets the face expression from the detections, if there is no valid detections it will return undefined.
*
* @param {Array<FaceResult>} detections - The array with the detections.
* @returns {string | undefined}
*/
getFaceExpression(detections: Array<FaceResult>): string | undefined { getFaceExpression(detections: Array<FaceResult>): string | undefined {
if (this.getFaceCount(detections) !== 1) { if (this.getFaceCount(detections) !== 1) {
return; return;
@ -149,6 +175,12 @@ export class HumanHelper implements FaceLandmarksHelper {
} }
} }
/**
* Gets the face count from the detections, which is the number of detections.
*
* @param {Array<FaceResult>} detections - The array with the detections.
* @returns {number}
*/
getFaceCount(detections: Array<FaceResult> | undefined): number { getFaceCount(detections: Array<FaceResult> | undefined): number {
if (detections) { if (detections) {
return detections.length; return detections.length;
@ -157,44 +189,56 @@ export class HumanHelper implements FaceLandmarksHelper {
return 0; return 0;
} }
/**
* Gets the detections from the image captured from the track.
*
* @param {ImageBitmap | ImageData} image - The image captured from the track,
* if OffscreenCanvas available it will be ImageBitmap, otherwise it will be ImageData.
* @returns {Promise<Array<FaceResult>>}
*/
async getDetections(image: ImageBitmap | ImageData): Promise<Array<FaceResult>> { async getDetections(image: ImageBitmap | ImageData): Promise<Array<FaceResult>> {
if (!this.human || !this.faceDetectionTypes.length) { if (!this.human || !this.faceDetectionTypes.length) {
return []; return [];
} }
this.human.tf.engine().startScope(); this.human.tf.engine().startScope();
const imageTensor = this.human.tf.browser.fromPixels(image); const imageTensor = this.human.tf.browser.fromPixels(image);
const { face: detections } = await this.human.detect(imageTensor, this.config); const { face: detections } = await this.human.detect(imageTensor, this.config);
this.human.tf.engine().endScope(); this.human.tf.engine().endScope();
return detections.filter(detection => detection.score > FACE_DETECTION_SCORE_THRESHOLD);
}
return detections.filter(detection => detection.score > FACE_DETECTION_SCORE_THRESHOLD);
}
/**
* Gathers together all the data from the detections, it's the function that will be called in the worker.
*
* @param {DetectInput} input - The input for the detections.
* @returns {Promise<DetectOutput>}
*/
public async detect({ image, threshold } : DetectInput): Promise<DetectOutput> { public async detect({ image, threshold } : DetectInput): Promise<DetectOutput> {
let detections;
let faceExpression; let faceExpression;
let faceBox; let faceBox;
this.detectionInProgress = true; this.detectionInProgress = true;
detections = await this.getDetections(image); const detections = await this.getDetections(image);
if (this.faceDetectionTypes.includes(DETECTION_TYPES.FACE_EXPRESSIONS)) { if (this.faceDetectionTypes.includes(DETECTION_TYPES.FACE_EXPRESSIONS)) {
faceExpression = this.getFaceExpression(detections); faceExpression = this.getFaceExpression(detections);
} }
if (this.faceDetectionTypes.includes(DETECTION_TYPES.FACE_BOX)) { if (this.faceDetectionTypes.includes(DETECTION_TYPES.FACE_BOX)) {
//if more than one face is detected the face centering will be disabled. // if more than one face is detected the face centering will be disabled.
if (this.getFaceCount(detections) > 1 ) { if (this.getFaceCount(detections) > 1) {
this.faceDetectionTypes.splice(this.faceDetectionTypes.indexOf(DETECTION_TYPES.FACE_BOX), 1); this.faceDetectionTypes.splice(this.faceDetectionTypes.indexOf(DETECTION_TYPES.FACE_BOX), 1);
//face-box for re-centering // face-box for re-centering
faceBox = { faceBox = {
left: 0, left: 0,
right: 100, right: 100,
width: 100, width: 100
}; };
} else { } else {
faceBox = this.getFaceBox(detections, threshold); faceBox = this.getFaceBox(detections, threshold);
@ -204,14 +248,19 @@ export class HumanHelper implements FaceLandmarksHelper {
this.detectionInProgress = false; this.detectionInProgress = false;
return { return {
faceExpression, faceExpression,
faceBox, faceBox,
faceCount: this.getFaceCount(detections) faceCount: this.getFaceCount(detections)
} };
} }
/**
* Returns the detection state.
*
* @returns {boolean}
*/
public getDetectionInProgress(): boolean { public getDetectionInProgress(): boolean {
return this.detectionInProgress; return this.detectionInProgress;
} }
} }

View File

@ -59,4 +59,4 @@ export const DETECTION_TYPES = {
/** /**
* Threshold for detection score of face. * Threshold for detection score of face.
*/ */
export const FACE_DETECTION_SCORE_THRESHOLD = 0.6; export const FACE_DETECTION_SCORE_THRESHOLD = 0.6;

View File

@ -1,5 +1,5 @@
import { FaceLandmarksHelper, HumanHelper } from './FaceLandmarksHelper';
import { DETECT_FACE, INIT_WORKER } from './constants'; import { DETECT_FACE, INIT_WORKER } from './constants';
import { FaceLandmarksHelper, HumanHelper }from './FaceLandmarksHelper';
let helper: FaceLandmarksHelper; let helper: FaceLandmarksHelper;

View File

@ -13,14 +13,14 @@ import styles from './styles';
const GifsMenuFooter = (): JSX.Element => { const GifsMenuFooter = (): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
return( return (
<View style={ styles.credit }> <View style = { styles.credit }>
<Text <Text
style={ styles.creditText }>{ t('poweredby') }</Text> style = { styles.creditText }>{ t('poweredby') }</Text>
<Image <Image
source = { require('../../../../../images/GIPHY_logo.png') } /> source = { require('../../../../../images/GIPHY_logo.png') } />
</View> </View>
) );
}; };
export default GifsMenuFooter; export default GifsMenuFooter;

View File

@ -5,7 +5,6 @@ import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { Chat, ChatAndPolls } from '../../../../../chat'; import { Chat, ChatAndPolls } from '../../../../../chat';
import Conference from '../../../../../conference/components/native/Conference'; import Conference from '../../../../../conference/components/native/Conference';
import CarMode from '../../../../../conference/components/native/carmode/CarMode'; import CarMode from '../../../../../conference/components/native/carmode/CarMode';
import { getDisablePolls } from '../../../../../conference/functions'; import { getDisablePolls } from '../../../../../conference/functions';

View File

@ -16,7 +16,7 @@ export const rootNavigationRef = React.createRef();
* @param {Object} params - Params to pass to the destination route. * @param {Object} params - Params to pass to the destination route.
* @returns {Function} * @returns {Function}
*/ */
export function navigateRoot(name: string, params: Object) { export function navigateRoot(name: string, params?: Object) {
return rootNavigationRef.current?.navigate(name, params); return rootNavigationRef.current?.navigate(name, params);
} }

View File

@ -1,3 +1,4 @@
/* eslint-disable import/order */
import { makeStyles } from '@material-ui/core'; import { makeStyles } from '@material-ui/core';
import React, { useCallback, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -5,16 +6,22 @@ import { useSelector } from 'react-redux';
// @ts-ignore // @ts-ignore
import { Avatar } from '../../../../../base/avatar'; import { Avatar } from '../../../../../base/avatar';
// @ts-ignore // @ts-ignore
import { ContextMenu, ContextMenuItemGroup } from '../../../../../base/components'; import { ContextMenu, ContextMenuItemGroup } from '../../../../../base/components';
// @ts-ignore // @ts-ignore
import { isLocalParticipantModerator } from '../../../../../base/participants'; import { isLocalParticipantModerator } from '../../../../../base/participants';
// @ts-ignore // @ts-ignore
import { getBreakoutRooms } from '../../../../../breakout-rooms/functions'; import { getBreakoutRooms } from '../../../../../breakout-rooms/functions';
// @ts-ignore // @ts-ignore
import { showOverflowDrawer } from '../../../../../toolbox/functions.web'; import { showOverflowDrawer } from '../../../../../toolbox/functions.web';
// @ts-ignore // @ts-ignore
import SendToRoomButton from '../../../../../video-menu/components/web/SendToRoomButton'; import SendToRoomButton from '../../../../../video-menu/components/web/SendToRoomButton';
// @ts-ignore // @ts-ignore
import { AVATAR_SIZE } from '../../../../constants'; import { AVATAR_SIZE } from '../../../../constants';
@ -74,7 +81,7 @@ export const RoomParticipantContextMenu = ({
const styles = useStyles(); const styles = useStyles();
const { t } = useTranslation(); const { t } = useTranslation();
const isLocalModerator = useSelector(isLocalParticipantModerator); const isLocalModerator = useSelector(isLocalParticipantModerator);
const lowerMenu = useCallback(() => onSelect(true), [onSelect]); const lowerMenu = useCallback(() => onSelect(true), [ onSelect ]);
const rooms: Object = useSelector(getBreakoutRooms); const rooms: Object = useSelector(getBreakoutRooms);
const overflowDrawer = useSelector(showOverflowDrawer); const overflowDrawer = useSelector(showOverflowDrawer);
@ -88,7 +95,8 @@ export const RoomParticipantContextMenu = ({
} }
return null; return null;
}).filter(Boolean), [ entity, rooms ]); })
.filter(Boolean), [ entity, rooms ]);
return isLocalModerator && ( return isLocalModerator && (
<ContextMenu <ContextMenu

View File

@ -1,6 +1,6 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { View } from 'react-native'; import { View } from 'react-native';
import { useDispatch, useSelector} from "react-redux"; import { useDispatch, useSelector } from 'react-redux';
import { openDialog, openSheet } from '../../../base/dialog'; import { openDialog, openSheet } from '../../../base/dialog';
import { IconHorizontalPoints } from '../../../base/icons'; import { IconHorizontalPoints } from '../../../base/icons';
@ -28,7 +28,7 @@ const ParticipantsPaneFooter = (): JSX.Element => {
const showMoreActions = useSelector(isMoreActionsVisible); const showMoreActions = useSelector(isMoreActionsVisible);
const showMuteAll = useSelector(isMuteAllVisible); const showMuteAll = useSelector(isMuteAllVisible);
return( return (
<View style = { styles.participantsPaneFooter }> <View style = { styles.participantsPaneFooter }>
{ {
showMuteAll && ( showMuteAll && (
@ -49,7 +49,7 @@ const ParticipantsPaneFooter = (): JSX.Element => {
) )
} }
</View> </View>
) );
}; };
export default ParticipantsPaneFooter; export default ParticipantsPaneFooter;

View File

@ -1,16 +1,18 @@
/* eslint-disable import/order */
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Text, View } from 'react-native'; import { Text, View } from 'react-native';
// @ts-ignore // @ts-ignore
import { Avatar } from '../../../base/avatar'; import { Avatar } from '../../../base/avatar';
// @ts-ignore // @ts-ignore
import { BottomSheet, hideSheet } from '../../../base/dialog'; import { BottomSheet, hideSheet } from '../../../base/dialog';
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux';
import { getBreakoutRooms } from '../../../breakout-rooms/functions'; import { getBreakoutRooms } from '../../../breakout-rooms/functions';
import SendToBreakoutRoom from '../../../video-menu/components/native/SendToBreakoutRoom'; import SendToBreakoutRoom from '../../../video-menu/components/native/SendToBreakoutRoom';
import styles from '../../../video-menu/components/native/styles'; import styles from '../../../video-menu/components/native/styles';
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
/** /**
* Size of the rendered avatar in the menu. * Size of the rendered avatar in the menu.

View File

@ -1,11 +1,12 @@
// @ts-ignore /* eslint-disable import/order */
import { IStore } from '../app/types';
// @ts-ignore // @ts-ignore
import { MiddlewareRegistry } from '../base/redux'; import { MiddlewareRegistry } from '../base/redux';
import { PARTICIPANTS_PANE_CLOSE, PARTICIPANTS_PANE_OPEN } from './actionTypes'; import { PARTICIPANTS_PANE_CLOSE, PARTICIPANTS_PANE_OPEN } from './actionTypes';
declare var APP: any; declare let APP: any;
/** /**
* Middleware which intercepts participants pane actions. * Middleware which intercepts participants pane actions.
@ -13,18 +14,19 @@ declare var APP: any;
* @param {IStore} store - The redux store. * @param {IStore} store - The redux store.
* @returns {Function} * @returns {Function}
*/ */
MiddlewareRegistry.register((store: IStore) => (next:Function) => (action:any) => { MiddlewareRegistry.register(() => (next:Function) => (action:any) => {
switch(action.type) { switch (action.type) {
case PARTICIPANTS_PANE_OPEN: case PARTICIPANTS_PANE_OPEN:
if (typeof APP !== 'undefined') { if (typeof APP !== 'undefined') {
APP.API.notifyParticipantsPaneToggled(true); APP.API.notifyParticipantsPaneToggled(true);
} }
break; break;
case PARTICIPANTS_PANE_CLOSE: case PARTICIPANTS_PANE_CLOSE:
if (typeof APP !== 'undefined') { if (typeof APP !== 'undefined') {
APP.API.notifyParticipantsPaneToggled(false); APP.API.notifyParticipantsPaneToggled(false);
} }
break; break;
} }
return next(action); return next(action);
}); });

View File

@ -4,7 +4,10 @@ import {
BackHandler, BackHandler,
View, View,
TextInput, TextInput,
Platform Platform,
StyleProp,
TextStyle,
ViewStyle
} from 'react-native'; } from 'react-native';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
@ -29,6 +32,7 @@ import AudioMuteButton from '../../toolbox/components/AudioMuteButton';
import VideoMuteButton from '../../toolbox/components/VideoMuteButton'; import VideoMuteButton from '../../toolbox/components/VideoMuteButton';
import { isDisplayNameRequired } from '../functions'; import { isDisplayNameRequired } from '../functions';
import { PrejoinProps } from '../types'; import { PrejoinProps } from '../types';
import styles from './styles'; import styles from './styles';
@ -92,7 +96,7 @@ const Prejoin: React.FC<PrejoinProps> = ({ navigation }: PrejoinProps) => {
return () => BackHandler.removeEventListener('hardwareBackPress', goBack); return () => BackHandler.removeEventListener('hardwareBackPress', goBack);
}, [ ]); }, []);
useLayoutEffect(() => { useLayoutEffect(() => {
navigation.setOptions({ navigation.setOptions({
@ -127,12 +131,12 @@ const Prejoin: React.FC<PrejoinProps> = ({ navigation }: PrejoinProps) => {
<LargeVideo /> <LargeVideo />
</View> </View>
<View style = { contentContainerStyles }> <View style = { contentContainerStyles }>
<View style = { styles.formWrapper }> <View style = { styles.formWrapper as StyleProp<ViewStyle> }>
<TextInput <TextInput
onChangeText = { onChangeDisplayName } onChangeText = { onChangeDisplayName }
placeholder = { t('dialog.enterDisplayName') } placeholder = { t('dialog.enterDisplayName') }
placeholderTextColor = { BaseTheme.palette.text03 } placeholderTextColor = { BaseTheme.palette.text03 }
style = { styles.field } style = { styles.field as StyleProp<TextStyle> }
value = { displayName } /> value = { displayName } />
<Button <Button
accessibilityLabel = 'prejoin.joinMeeting' accessibilityLabel = 'prejoin.joinMeeting'

View File

@ -1,3 +1,3 @@
interface PrejoinProps { export interface PrejoinProps {
navigation: Object; navigation: any;
} }

View File

@ -13,6 +13,7 @@ import { ReactionsAction } from './reducer';
* Sets the reaction queue. * Sets the reaction queue.
* *
* @param {Array} queue - The new queue. * @param {Array} queue - The new queue.
* @returns {ReactionsAction}
*/ */
export function setReactionQueue(queue: Array<ReactionEmojiProps>): ReactionsAction { export function setReactionQueue(queue: Array<ReactionEmojiProps>): ReactionsAction {
return { return {
@ -26,6 +27,7 @@ export function setReactionQueue(queue: Array<ReactionEmojiProps>): ReactionsAct
* Removes a reaction from the queue. * Removes a reaction from the queue.
* *
* @param {string} uid - Id of the reaction to be removed. * @param {string} uid - Id of the reaction to be removed.
* @returns {Function}
*/ */
export function removeReaction(uid: string): Function { export function removeReaction(uid: string): Function {
return (dispatch: Function, getState: Function) => { return (dispatch: Function, getState: Function) => {
@ -38,6 +40,8 @@ export function removeReaction(uid: string): Function {
/** /**
* Sends the reactions buffer to everyone in the conference. * Sends the reactions buffer to everyone in the conference.
*
* @returns {ReactionsAction}
*/ */
export function sendReactions(): ReactionsAction { export function sendReactions(): ReactionsAction {
return { return {
@ -49,6 +53,7 @@ export function sendReactions(): ReactionsAction {
* Adds a reaction to the local buffer. * Adds a reaction to the local buffer.
* *
* @param {string} reaction - The reaction to be added. * @param {string} reaction - The reaction to be added.
* @returns {ReactionsAction}
*/ */
export function addReactionToBuffer(reaction: string): ReactionsAction { export function addReactionToBuffer(reaction: string): ReactionsAction {
return { return {
@ -59,6 +64,8 @@ export function addReactionToBuffer(reaction: string): ReactionsAction {
/** /**
* Clears the reaction buffer. * Clears the reaction buffer.
*
* @returns {ReactionsAction}
*/ */
export function flushReactionBuffer(): ReactionsAction { export function flushReactionBuffer(): ReactionsAction {
return { return {
@ -70,6 +77,7 @@ export function flushReactionBuffer(): ReactionsAction {
* Adds a reaction message to the chat. * Adds a reaction message to the chat.
* *
* @param {string} message - The reaction message. * @param {string} message - The reaction message.
* @returns {ReactionsAction}
*/ */
export function addReactionsToChat(message: string): ReactionsAction { export function addReactionsToChat(message: string): ReactionsAction {
return { return {
@ -82,6 +90,7 @@ export function addReactionsToChat(message: string): ReactionsAction {
* Adds reactions to the animation queue. * Adds reactions to the animation queue.
* *
* @param {Array} reactions - The reactions to be animated. * @param {Array} reactions - The reactions to be animated.
* @returns {ReactionsAction}
*/ */
export function pushReactions(reactions: Array<string>): ReactionsAction { export function pushReactions(reactions: Array<string>): ReactionsAction {
return { return {

View File

@ -6,6 +6,8 @@ import { ReactionsAction } from './reducer';
/** /**
* Toggles the visibility of the reactions menu. * Toggles the visibility of the reactions menu.
*
* @returns {void}
*/ */
export function toggleReactionsMenuVisibility(): ReactionsAction { export function toggleReactionsMenuVisibility(): ReactionsAction {
return { return {
@ -15,6 +17,8 @@ export function toggleReactionsMenuVisibility(): ReactionsAction {
/** /**
* Displays the disable sounds notification. * Displays the disable sounds notification.
*
* @returns {void}
*/ */
export function displayReactionSoundsNotification(): ReactionsAction { export function displayReactionSoundsNotification(): ReactionsAction {
return { return {

View File

@ -1,10 +1,13 @@
/* eslint-disable import/order */
import React, { Component } from 'react'; import React, { Component } from 'react';
// @ts-ignore
import { IStore } from '../../../app/types';
// @ts-ignore // @ts-ignore
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux';
import { removeReaction } from '../../actions.any'; import { removeReaction } from '../../actions.any';
import { REACTIONS } from '../../constants'; import { REACTIONS } from '../../constants';
import { IStore } from '../../../app/types';
type Props = { type Props = {
@ -86,8 +89,10 @@ class ReactionEmoji extends Component<Props, State> {
} }
} }
const mapDispatchToProps = (dispatch: IStore['dispatch']) => ({ const mapDispatchToProps = (dispatch: IStore['dispatch']) => {
reactionRemove: (uid: string) => dispatch(removeReaction(uid)) return {
}); reactionRemove: (uid: string) => dispatch(removeReaction(uid))
};
};
export default connect(null, mapDispatchToProps)(ReactionEmoji); export default connect(undefined, mapDispatchToProps)(ReactionEmoji);

View File

@ -1,3 +1,4 @@
/* eslint-disable import/order */
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { Component } from 'react'; import React, { Component } from 'react';
@ -7,21 +8,29 @@ import {
createReactionMenuEvent, createReactionMenuEvent,
createToolbarEvent, createToolbarEvent,
sendAnalytics sendAnalytics
// @ts-ignore // @ts-ignore
} from '../../../analytics'; } from '../../../analytics';
import { IStore } from '../../../app/types'; import { IStore } from '../../../app/types';
// @ts-ignore // @ts-ignore
import { isMobileBrowser } from '../../../base/environment/utils'; import { isMobileBrowser } from '../../../base/environment/utils';
// @ts-ignore // @ts-ignore
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n';
// @ts-ignore // @ts-ignore
import { getLocalParticipant, hasRaisedHand, raiseHand } from '../../../base/participants'; import { getLocalParticipant, hasRaisedHand, raiseHand } from '../../../base/participants';
// @ts-ignore // @ts-ignore
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux';
// @ts-ignore // @ts-ignore
import { GifsMenu, GifsMenuButton } from '../../../gifs/components'; import { GifsMenu, GifsMenuButton } from '../../../gifs/components';
// @ts-ignore // @ts-ignore
import { isGifEnabled, isGifsMenuOpen } from '../../../gifs/functions'; import { isGifEnabled, isGifsMenuOpen } from '../../../gifs/functions';
// @ts-ignore // @ts-ignore
import { dockToolbox } from '../../../toolbox/actions.web'; import { dockToolbox } from '../../../toolbox/actions.web';
import { addReactionToBuffer } from '../../actions.any'; import { addReactionToBuffer } from '../../actions.any';
@ -88,8 +97,6 @@ type Props = {
t: Function t: Function
}; };
declare var APP: Object;
const styles = (theme: any) => { const styles = (theme: any) => {
return { return {
overflow: { overflow: {
@ -201,6 +208,7 @@ class ReactionsMenu extends Component<Props> {
accessibilityLabel = { t(`toolbar.accessibilityLabel.${key}`) } accessibilityLabel = { t(`toolbar.accessibilityLabel.${key}`) }
icon = { REACTIONS[key].emoji } icon = { REACTIONS[key].emoji }
key = { key } key = { key }
// eslint-disable-next-line react/jsx-no-bind
onClick = { doSendReaction } onClick = { doSendReaction }
toggled = { false } toggled = { false }
tooltip = { `${t(`toolbar.${key}`)} (${modifierKey} + ${REACTIONS[key].shortcutChar})` } />); tooltip = { `${t(`toolbar.${key}`)} (${modifierKey} + ${REACTIONS[key].shortcutChar})` } />);
@ -274,6 +282,7 @@ function mapDispatchToProps(dispatch: IStore['dispatch']) {
...bindActionCreators( ...bindActionCreators(
{ {
_dockToolbox: dockToolbox _dockToolbox: dockToolbox
// @ts-ignore // @ts-ignore
}, dispatch) }, dispatch)
}; };
@ -282,5 +291,6 @@ function mapDispatchToProps(dispatch: IStore['dispatch']) {
export default translate(connect( export default translate(connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
// @ts-ignore // @ts-ignore
)(withStyles(styles)(ReactionsMenu))); )(withStyles(styles)(ReactionsMenu)));

View File

@ -1,17 +1,21 @@
// @flow /* eslint-disable import/order */
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
// @ts-ignore // @ts-ignore
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
// @ts-ignore // @ts-ignore
import { isMobileBrowser } from '../../../base/environment/utils'; import { isMobileBrowser } from '../../../base/environment/utils';
// @ts-ignore // @ts-ignore
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n';
// @ts-ignore // @ts-ignore
import { IconArrowUp } from '../../../base/icons'; import { IconArrowUp } from '../../../base/icons';
// @ts-ignore // @ts-ignore
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux';
// @ts-ignore // @ts-ignore
import ToolboxButtonWithIconPopup from '../../../base/toolbox/components/web/ToolboxButtonWithIconPopup'; import ToolboxButtonWithIconPopup from '../../../base/toolbox/components/web/ToolboxButtonWithIconPopup';
import { toggleReactionsMenuVisibility } from '../../actions.web'; import { toggleReactionsMenuVisibility } from '../../actions.web';
@ -73,9 +77,6 @@ type Props = {
t: Function t: Function
}; };
declare var APP: Object;
/** /**
* Button used for the reactions menu. * Button used for the reactions menu.
* *

View File

@ -1,9 +1,12 @@
/* eslint-disable import/order */
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
// @ts-ignore // @ts-ignore
import { getFeatureFlag, REACTIONS_ENABLED } from '../base/flags'; import { getFeatureFlag, REACTIONS_ENABLED } from '../base/flags';
// @ts-ignore // @ts-ignore
import { getLocalParticipant } from '../base/participants'; import { getLocalParticipant } from '../base/participants';
// @ts-ignore // @ts-ignore
import { extractFqnFromPath } from '../dynamic-branding/functions.any'; import { extractFqnFromPath } from '../dynamic-branding/functions.any';
@ -14,6 +17,7 @@ import logger from './logger';
* Returns the queue of reactions. * Returns the queue of reactions.
* *
* @param {Object} state - The state of the application. * @param {Object} state - The state of the application.
* @returns {Array}
*/ */
export function getReactionsQueue(state: any): Array<ReactionEmojiProps> { export function getReactionsQueue(state: any): Array<ReactionEmojiProps> {
return state['features/reactions'].queue; return state['features/reactions'].queue;
@ -23,6 +27,7 @@ export function getReactionsQueue(state: any): Array<ReactionEmojiProps> {
* Returns chat message from reactions buffer. * Returns chat message from reactions buffer.
* *
* @param {Array} buffer - The reactions buffer. * @param {Array} buffer - The reactions buffer.
* @returns {string}
*/ */
export function getReactionMessageFromBuffer(buffer: Array<string>): string { export function getReactionMessageFromBuffer(buffer: Array<string>): string {
return buffer.map<string>(reaction => REACTIONS[reaction].message).reduce((acc, val) => `${acc}${val}`); return buffer.map<string>(reaction => REACTIONS[reaction].message).reduce((acc, val) => `${acc}${val}`);
@ -32,6 +37,7 @@ export function getReactionMessageFromBuffer(buffer: Array<string>): string {
* Returns reactions array with uid. * Returns reactions array with uid.
* *
* @param {Array} buffer - The reactions buffer. * @param {Array} buffer - The reactions buffer.
* @returns {Array}
*/ */
export function getReactionsWithId(buffer: Array<string>): Array<ReactionEmojiProps> { export function getReactionsWithId(buffer: Array<string>): Array<ReactionEmojiProps> {
return buffer.map<ReactionEmojiProps>(reaction => { return buffer.map<ReactionEmojiProps>(reaction => {
@ -47,6 +53,7 @@ export function getReactionsWithId(buffer: Array<string>): Array<ReactionEmojiPr
* *
* @param {Object} state - The redux state object. * @param {Object} state - The redux state object.
* @param {Array} reactions - Reactions array to be sent. * @param {Array} reactions - Reactions array to be sent.
* @returns {void}
*/ */
export async function sendReactionsWebhook(state: any, reactions: Array<string>) { export async function sendReactionsWebhook(state: any, reactions: Array<string>) {
const { webhookProxyUrl: url } = state['features/base/config']; const { webhookProxyUrl: url } = state['features/base/config'];
@ -93,6 +100,7 @@ export async function sendReactionsWebhook(state: any, reactions: Array<string>)
* Returns unique reactions from the reactions buffer. * Returns unique reactions from the reactions buffer.
* *
* @param {Array} reactions - The reactions buffer. * @param {Array} reactions - The reactions buffer.
* @returns {Array}
*/ */
function getUniqueReactions(reactions: Array<string>): Array<string> { function getUniqueReactions(reactions: Array<string>): Array<string> {
return [ ...new Set(reactions) ]; return [ ...new Set(reactions) ];
@ -103,6 +111,7 @@ function getUniqueReactions(reactions: Array<string>): Array<string> {
* *
* @param {Array} reactions - Array of reactions. * @param {Array} reactions - Array of reactions.
* @param {string} reaction - Reaction to get frequency for. * @param {string} reaction - Reaction to get frequency for.
* @returns {number}
*/ */
function getReactionFrequency(reactions: Array<string>, reaction: string): number { function getReactionFrequency(reactions: Array<string>, reaction: string): number {
return reactions.filter(r => r === reaction).length; return reactions.filter(r => r === reaction).length;
@ -112,6 +121,7 @@ function getReactionFrequency(reactions: Array<string>, reaction: string): numbe
* Returns the threshold number for a given frequency. * Returns the threshold number for a given frequency.
* *
* @param {number} frequency - Frequency of reaction. * @param {number} frequency - Frequency of reaction.
* @returns {number}
*/ */
function getSoundThresholdByFrequency(frequency: number): number { function getSoundThresholdByFrequency(frequency: number): number {
for (const i of SOUNDS_THRESHOLDS) { for (const i of SOUNDS_THRESHOLDS) {
@ -127,6 +137,7 @@ function getSoundThresholdByFrequency(frequency: number): number {
* Returns unique reactions with threshold. * Returns unique reactions with threshold.
* *
* @param {Array} reactions - The reactions buffer. * @param {Array} reactions - The reactions buffer.
* @returns {Array}
*/ */
export function getReactionsSoundsThresholds(reactions: Array<string>): Array<ReactionThreshold> { export function getReactionsSoundsThresholds(reactions: Array<string>): Array<ReactionThreshold> {
const unique = getUniqueReactions(reactions); const unique = getUniqueReactions(reactions);
@ -143,6 +154,7 @@ export function getReactionsSoundsThresholds(reactions: Array<string>): Array<Re
* Whether or not the reactions are enabled. * Whether or not the reactions are enabled.
* *
* @param {Object} state - The Redux state object. * @param {Object} state - The Redux state object.
* @returns {boolean}
*/ */
export function isReactionsEnabled(state: any): boolean { export function isReactionsEnabled(state: any): boolean {
const { disableReactions } = state['features/base/config']; const { disableReactions } = state['features/base/config'];

View File

@ -2,6 +2,7 @@
* Returns the visibility state of the reactions menu. * Returns the visibility state of the reactions menu.
* *
* @param {Object} state - The state of the application. * @param {Object} state - The state of the application.
* @returns {boolean}
*/ */
export function getReactionsMenuVisibility(state: any): boolean { export function getReactionsMenuVisibility(state: any): boolean {
return state['features/reactions'].visible; return state['features/reactions'].visible;

View File

@ -1,30 +1,41 @@
/* eslint-disable import/order */
// @ts-ignore // @ts-ignore
import { batch } from 'react-redux'; import { batch } from 'react-redux';
// @ts-ignore // @ts-ignore
import { createReactionSoundsDisabledEvent, sendAnalytics } from '../analytics'; import { createReactionSoundsDisabledEvent, sendAnalytics } from '../analytics';
// @ts-ignore // @ts-ignore
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app'; import { IStore } from '../app/types';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
import { import {
CONFERENCE_JOIN_IN_PROGRESS, CONFERENCE_JOIN_IN_PROGRESS,
SET_START_REACTIONS_MUTED, SET_START_REACTIONS_MUTED,
setStartReactionsMuted setStartReactionsMuted
// @ts-ignore // @ts-ignore
} from '../base/conference'; } from '../base/conference';
import { import {
getParticipantById, getParticipantById,
getParticipantCount, getParticipantCount,
isLocalParticipantModerator isLocalParticipantModerator
// @ts-ignore // @ts-ignore
} from '../base/participants'; } from '../base/participants';
// @ts-ignore // @ts-ignore
import { MiddlewareRegistry } from '../base/redux'; import { MiddlewareRegistry } from '../base/redux';
import { SETTINGS_UPDATED } from '../base/settings/actionTypes'; import { SETTINGS_UPDATED } from '../base/settings/actionTypes';
// @ts-ignore // @ts-ignore
import { updateSettings } from '../base/settings/actions'; import { updateSettings } from '../base/settings/actions';
// @ts-ignore // @ts-ignore
import { playSound, registerSound, unregisterSound } from '../base/sounds'; import { playSound, registerSound, unregisterSound } from '../base/sounds';
// @ts-ignore // @ts-ignore
import { getDisabledSounds } from '../base/sounds/functions.any'; import { getDisabledSounds } from '../base/sounds/functions.any';
// @ts-ignore // @ts-ignore
import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications'; import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications';
@ -60,7 +71,6 @@ import {
} from './functions.any'; } from './functions.any';
import logger from './logger'; import logger from './logger';
import { RAISE_HAND_SOUND_FILE } from './sounds'; import { RAISE_HAND_SOUND_FILE } from './sounds';
import { IStore } from '../app/types';
/** /**
* Middleware which intercepts Reactions actions to handle changes to the * Middleware which intercepts Reactions actions to handle changes to the
@ -241,6 +251,7 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action:any)
* @param {Object} store - The redux store. Used to calculate and dispatch * @param {Object} store - The redux store. Used to calculate and dispatch
* updates. * updates.
* @private * @private
* @returns {void}
*/ */
function _onMuteReactionsCommand(attributes: MuteCommandAttributes = {}, id: string, store: IStore) { function _onMuteReactionsCommand(attributes: MuteCommandAttributes = {}, id: string, store: IStore) {
const state = store.getState(); const state = store.getState();
@ -267,6 +278,7 @@ function _onMuteReactionsCommand(attributes: MuteCommandAttributes = {}, id: str
} }
const oldState = Boolean(state['features/base/conference'].startReactionsMuted); const oldState = Boolean(state['features/base/conference'].startReactionsMuted);
// @ts-ignore // @ts-ignore
const newState = attributes.startReactionsMuted === 'true'; const newState = attributes.startReactionsMuted === 'true';

View File

@ -10,20 +10,24 @@ import {
} from './actionTypes'; } from './actionTypes';
import { ReactionEmojiProps } from './constants'; import { ReactionEmojiProps } from './constants';
interface State { interface IReactionsState {
/** /**
* The indicator that determines whether the reactions menu is visible. * The indicator that determines whether the reactions menu is visible.
*/ */
visible: boolean, visible: boolean,
/** /**
* An array that contains the reactions buffer to be sent. * An array that contains the reactions buffer to be sent.
*/ */
buffer: Array<string>, buffer: Array<string>,
/** /**
* A number, non-zero value which identifies the timer created by a call * A number, non-zero value which identifies the timer created by a call
* to setTimeout(). * to setTimeout().
*/ */
timeoutID: number|null, timeoutID: number|null,
/** /**
* The array of reactions to animate. * The array of reactions to animate.
*/ */
@ -35,19 +39,23 @@ interface State {
notificationDisplayed: boolean notificationDisplayed: boolean
} }
export interface ReactionsAction extends Partial<State> { export interface ReactionsAction extends Partial<IReactionsState> {
/** /**
* The message to be added to the chat. * The message to be added to the chat.
*/ */
message?: string, message?: string,
/** /**
* The reaction to be added to buffer. * The reaction to be added to buffer.
*/ */
reaction?: string, reaction?: string,
/** /**
* The reactions to be added to the animation queue. * The reactions to be added to the animation queue.
*/ */
reactions?: Array<string>, reactions?: Array<string>,
/** /**
* The action type. * The action type.
*/ */
@ -58,8 +66,9 @@ export interface ReactionsAction extends Partial<State> {
* Returns initial state for reactions' part of Redux store. * Returns initial state for reactions' part of Redux store.
* *
* @private * @private
* @returns {IReactionsState}
*/ */
function _getInitialState(): State { function _getInitialState(): IReactionsState {
return { return {
visible: false, visible: false,
buffer: [], buffer: [],
@ -71,7 +80,7 @@ function _getInitialState(): State {
ReducerRegistry.register( ReducerRegistry.register(
'features/reactions', 'features/reactions',
(state: State = _getInitialState(), action: ReactionsAction) => { (state: IReactionsState = _getInitialState(), action: ReactionsAction) => {
switch (action.type) { switch (action.type) {
case TOGGLE_REACTIONS_VISIBLE: case TOGGLE_REACTIONS_VISIBLE:

View File

@ -1,36 +1,40 @@
interface IReduxStore { import { IStore } from '../../../app/types';
dispatch: Function;
getState: Function;
}
interface ILocalRecordingManager { interface ILocalRecordingManager {
addAudioTrackToLocalRecording: (track: MediaStreamTrack) => void; addAudioTrackToLocalRecording: (track: MediaStreamTrack) => void;
stopLocalRecording: () => void; stopLocalRecording: () => void;
startLocalRecording: (store: IReduxStore) => void; startLocalRecording: (store: IStore) => void;
isRecordingLocally: () => boolean; isRecordingLocally: () => boolean;
} }
const LocalRecordingManager: ILocalRecordingManager = { const LocalRecordingManager: ILocalRecordingManager = {
/** /**
* Adds audio track to the recording stream. * Adds audio track to the recording stream.
*
* @param {MediaStreamTrack} track - Track to be added,.
* @returns {void}
*/ */
addAudioTrackToLocalRecording(track) { addAudioTrackToLocalRecording() { },
},
/** /**
* Stops local recording. * Stops local recording.
*
* @returns {void}
* */ * */
stopLocalRecording() { stopLocalRecording() { },
},
/** /**
* Starts a local recording. * Starts a local recording.
*
* @param {IStore} store - The Redux store.
* @returns {void}
*/ */
async startLocalRecording(store) { async startLocalRecording() { },
},
/** /**
* Whether or not we're currently recording locally. * Whether or not we're currently recording locally.
*
* @returns {boolean}
*/ */
isRecordingLocally() { isRecordingLocally() {
return false; return false;

View File

@ -1,22 +1,24 @@
/* eslint-disable import/order */
import { v4 as uuidV4 } from 'uuid'; import { v4 as uuidV4 } from 'uuid';
import fixWebmDuration from 'webm-duration-fix'; import fixWebmDuration from 'webm-duration-fix';
import { IStore } from '../../../app/types';
// @ts-ignore // @ts-ignore
import { getRoomName } from '../../../base/conference'; import { getRoomName } from '../../../base/conference';
// @ts-ignore // @ts-ignore
import { MEDIA_TYPE } from '../../../base/media'; import { MEDIA_TYPE } from '../../../base/media';
// @ts-ignore // @ts-ignore
import { getTrackState, getLocalTrack } from '../../../base/tracks'; import { getTrackState, getLocalTrack } from '../../../base/tracks';
import { inIframe } from '../../../base/util/iframeUtils'; import { inIframe } from '../../../base/util/iframeUtils';
// @ts-ignore // @ts-ignore
import { stopLocalVideoRecording } from '../../actions.any'; import { stopLocalVideoRecording } from '../../actions.any';
declare var APP: any; declare let APP: any;
interface IReduxStore {
dispatch: Function;
getState: Function;
}
interface SelfRecording { interface SelfRecording {
on: boolean; on: boolean;
@ -37,7 +39,7 @@ interface ILocalRecordingManager {
getFilename: () => string; getFilename: () => string;
saveRecording: (recordingData: Blob[], filename: string) => void; saveRecording: (recordingData: Blob[], filename: string) => void;
stopLocalRecording: () => void; stopLocalRecording: () => void;
startLocalRecording: (store: IReduxStore, onlySelf: boolean) => void; startLocalRecording: (store: IStore, onlySelf: boolean) => void;
isRecordingLocally: () => boolean; isRecordingLocally: () => boolean;
totalSize: number; totalSize: number;
selfRecording: SelfRecording; selfRecording: SelfRecording;
@ -48,15 +50,16 @@ const getMimeType = (): string => {
'video/mp4;codecs=h264', 'video/mp4;codecs=h264',
'video/webm;codecs=h264', 'video/webm;codecs=h264',
'video/webm;codecs=vp9', 'video/webm;codecs=vp9',
'video/webm;codecs=vp8', 'video/webm;codecs=vp8'
]; ];
for(let type of possibleTypes) {
if(MediaRecorder.isTypeSupported(type)) { for (const type of possibleTypes) {
if (MediaRecorder.isTypeSupported(type)) {
return type; return type;
} }
} }
throw new Error("No MIME Type supported by MediaRecorder"); throw new Error('No MIME Type supported by MediaRecorder');
} };
const VIDEO_BIT_RATE = 2500000; // 2.5Mbps in bits const VIDEO_BIT_RATE = 2500000; // 2.5Mbps in bits
@ -86,6 +89,8 @@ const LocalRecordingManager: ILocalRecordingManager = {
/** /**
* Initializes audio context used for mixing audio tracks. * Initializes audio context used for mixing audio tracks.
*
* @returns {void}
*/ */
initializeAudioMixer() { initializeAudioMixer() {
this.audioContext = new AudioContext(); this.audioContext = new AudioContext();
@ -94,6 +99,9 @@ const LocalRecordingManager: ILocalRecordingManager = {
/** /**
* Mixes multiple audio tracks to the destination media stream. * Mixes multiple audio tracks to the destination media stream.
*
* @param {MediaStream} stream - The stream to mix.
* @returns {void}
* */ * */
mixAudioStream(stream) { mixAudioStream(stream) {
if (stream.getAudioTracks().length > 0 && this.audioDestination) { if (stream.getAudioTracks().length > 0 && this.audioDestination) {
@ -103,9 +111,12 @@ const LocalRecordingManager: ILocalRecordingManager = {
/** /**
* Adds audio track to the recording stream. * Adds audio track to the recording stream.
*
* @param {MediaStreamTrack} track - The track to be added.
* @returns {void}
*/ */
addAudioTrackToLocalRecording(track) { addAudioTrackToLocalRecording(track) {
if(this.selfRecording.on) { if (this.selfRecording.on) {
return; return;
} }
if (track) { if (track) {
@ -117,6 +128,8 @@ const LocalRecordingManager: ILocalRecordingManager = {
/** /**
* Returns a filename based ono the Jitsi room name in the URL and timestamp. * Returns a filename based ono the Jitsi room name in the URL and timestamp.
*
* @returns {string}
* */ * */
getFilename() { getFilename() {
const now = new Date(); const now = new Date();
@ -127,15 +140,21 @@ const LocalRecordingManager: ILocalRecordingManager = {
/** /**
* Saves local recording to file. * Saves local recording to file.
*
* @param {Array} recordingData - The recording data.
* @param {string} filename - The name of the file.
* @returns {void}
* */ * */
async saveRecording(recordingData, filename) { async saveRecording(recordingData, filename) {
// @ts-ignore // @ts-ignore
const blob = await fixWebmDuration(new Blob(recordingData, { type: this.mediaType })); const blob = await fixWebmDuration(new Blob(recordingData, { type: this.mediaType }));
// @ts-ignore // @ts-ignore
const url = window.URL.createObjectURL(blob); const url = window.URL.createObjectURL(blob);
const a = document.createElement('a'); const a = document.createElement('a');
const extension = this.mediaType.slice(this.mediaType.indexOf('/') + 1, this.mediaType.indexOf(';')) const extension = this.mediaType.slice(this.mediaType.indexOf('/') + 1, this.mediaType.indexOf(';'));
a.style.display = 'none'; a.style.display = 'none';
a.href = url; a.href = url;
a.download = `${filename}.${extension}`; a.download = `${filename}.${extension}`;
@ -144,6 +163,8 @@ const LocalRecordingManager: ILocalRecordingManager = {
/** /**
* Stops local recording. * Stops local recording.
*
* @returns {void}
* */ * */
stopLocalRecording() { stopLocalRecording() {
if (this.recorder) { if (this.recorder) {
@ -157,9 +178,14 @@ const LocalRecordingManager: ILocalRecordingManager = {
/** /**
* Starts a local recording. * Starts a local recording.
*
* @param {IStore} store - The redux store.
* @param {boolean} onlySelf - Whether to record only self streams.
* @returns {void}
*/ */
async startLocalRecording(store, onlySelf) { async startLocalRecording(store, onlySelf) {
const { dispatch, getState } = store; const { dispatch, getState } = store;
// @ts-ignore // @ts-ignore
const supportsCaptureHandle = Boolean(navigator.mediaDevices.setCaptureHandleConfig) && !inIframe(); const supportsCaptureHandle = Boolean(navigator.mediaDevices.setCaptureHandleConfig) && !inIframe();
const tabId = uuidV4(); const tabId = uuidV4();
@ -170,25 +196,27 @@ const LocalRecordingManager: ILocalRecordingManager = {
let gdmStream: MediaStream = new MediaStream(); let gdmStream: MediaStream = new MediaStream();
const tracks = getTrackState(getState()); const tracks = getTrackState(getState());
if(onlySelf) { if (onlySelf) {
let audioTrack: MediaStreamTrack | undefined = getLocalTrack(tracks, MEDIA_TYPE.AUDIO)?.jitsiTrack?.track; let audioTrack: MediaStreamTrack | undefined = getLocalTrack(tracks, MEDIA_TYPE.AUDIO)?.jitsiTrack?.track;
let videoTrack: MediaStreamTrack | undefined = getLocalTrack(tracks, MEDIA_TYPE.VIDEO)?.jitsiTrack?.track; let videoTrack: MediaStreamTrack | undefined = getLocalTrack(tracks, MEDIA_TYPE.VIDEO)?.jitsiTrack?.track;
if(!audioTrack) {
if (!audioTrack) {
APP.conference.muteAudio(false); APP.conference.muteAudio(false);
setTimeout(() => APP.conference.muteAudio(true), 100); setTimeout(() => APP.conference.muteAudio(true), 100);
await new Promise((resolve) => { await new Promise(resolve => {
setTimeout(resolve, 100); setTimeout(resolve, 100);
}); });
} }
if(videoTrack && videoTrack.readyState !== 'live') { if (videoTrack && videoTrack.readyState !== 'live') {
videoTrack = undefined; videoTrack = undefined;
} }
audioTrack = getLocalTrack(getTrackState(getState()), MEDIA_TYPE.AUDIO)?.jitsiTrack?.track; audioTrack = getLocalTrack(getTrackState(getState()), MEDIA_TYPE.AUDIO)?.jitsiTrack?.track;
if(!audioTrack && !videoTrack) { if (!audioTrack && !videoTrack) {
throw new Error('NoLocalStreams') throw new Error('NoLocalStreams');
} }
this.selfRecording.withVideo = Boolean(videoTrack); this.selfRecording.withVideo = Boolean(videoTrack);
const localTracks = []; const localTracks = [];
audioTrack && localTracks.push(audioTrack); audioTrack && localTracks.push(audioTrack);
videoTrack && localTracks.push(videoTrack); videoTrack && localTracks.push(videoTrack);
this.stream = new MediaStream(localTracks); this.stream = new MediaStream(localTracks);
@ -204,7 +232,8 @@ const LocalRecordingManager: ILocalRecordingManager = {
// @ts-ignore // @ts-ignore
gdmStream = await navigator.mediaDevices.getDisplayMedia({ gdmStream = await navigator.mediaDevices.getDisplayMedia({
// @ts-ignore // @ts-ignore
video: { displaySurface: 'browser', frameRate: 30 }, video: { displaySurface: 'browser',
frameRate: 30 },
audio: { audio: {
autoGainControl: false, autoGainControl: false,
channelCount: 2, channelCount: 2,
@ -212,6 +241,7 @@ const LocalRecordingManager: ILocalRecordingManager = {
noiseSuppression: false noiseSuppression: false
} }
}); });
// @ts-ignore // @ts-ignore
const isBrowser = gdmStream.getVideoTracks()[0].getSettings().displaySurface === 'browser'; const isBrowser = gdmStream.getVideoTracks()[0].getSettings().displaySurface === 'browser';
@ -232,7 +262,7 @@ const LocalRecordingManager: ILocalRecordingManager = {
} }
}); });
this.stream = new MediaStream([ this.stream = new MediaStream([
...(this.audioDestination?.stream.getAudioTracks() || []), ...this.audioDestination?.stream.getAudioTracks() || [],
gdmStream.getVideoTracks()[0] gdmStream.getVideoTracks()[0]
]); ]);
} }
@ -251,7 +281,7 @@ const LocalRecordingManager: ILocalRecordingManager = {
} }
}); });
if(!onlySelf) { if (!onlySelf) {
this.recorder.addEventListener('stop', () => { this.recorder.addEventListener('stop', () => {
this.stream?.getTracks().forEach((track: MediaStreamTrack) => track.stop()); this.stream?.getTracks().forEach((track: MediaStreamTrack) => track.stop());
gdmStream?.getTracks().forEach((track: MediaStreamTrack) => track.stop()); gdmStream?.getTracks().forEach((track: MediaStreamTrack) => track.stop());
@ -271,6 +301,8 @@ const LocalRecordingManager: ILocalRecordingManager = {
/** /**
* Whether or not we're currently recording locally. * Whether or not we're currently recording locally.
*
* @returns {boolean}
*/ */
isRecordingLocally() { isRecordingLocally() {
return Boolean(this.recorder); return Boolean(this.recorder);

View File

@ -34,7 +34,7 @@ class OpenCarmodeButton extends AbstractButton<AbstractButtonProps, any, any> {
* @private * @private
* @returns {Object} * @returns {Object}
*/ */
function _mapStateToProps(state: Object, ownProps: AbstractButtonProps): Object { function _mapStateToProps(state: Object, ownProps: AbstractButtonProps): Object {
const enabled = getFeatureFlag(state, CAR_MODE_ENABLED, true); const enabled = getFeatureFlag(state, CAR_MODE_ENABLED, true);
const { visible = enabled } = ownProps; const { visible = enabled } = ownProps;

View File

@ -22,8 +22,9 @@ const ScreenSharingButton = props => (
* Maps (parts of) the redux state to the associated props for the * Maps (parts of) the redux state to the associated props for the
* {@code ScreenSharingButton} component. * {@code ScreenSharingButton} component.
* *
* @param state - The Redux state. * @param {Object} state - The Redux state.
* @private * @private
* @returns {Object}
*/ */
function _mapStateToProps(state: object): object { function _mapStateToProps(state: object): object {
return { return {