Initial import of f7cloud-mobile native Android app.
Kotlin/Compose client for F7cloud (mail, files, talk, calendar, contacts, tasks, support). Current version: 0.5.113 (build 121).
This commit is contained in:
@@ -0,0 +1,320 @@
|
||||
/**
|
||||
* F7cloud APK: skip "Check devices" and join incoming calls with camera/mic off.
|
||||
* Requires sessionStorage f7_apk_direct_join=1 (set from Android on push accept).
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var LOG = 'F7TalkJoin';
|
||||
var LEFT_PREFIX = 'f7_apk_left_';
|
||||
var STYLE_ID = 'f7-talk-hide-media-style';
|
||||
|
||||
function log(msg) {
|
||||
try { console.debug('[' + LOG + '] ' + msg); } catch (e) { /* ignore */ }
|
||||
}
|
||||
|
||||
function roomToken() {
|
||||
var m = window.location.pathname.match(/\/call\/([A-Za-z0-9]+)/);
|
||||
return m ? m[1] : null;
|
||||
}
|
||||
|
||||
function leftKey() {
|
||||
var t = roomToken();
|
||||
return t ? (LEFT_PREFIX + t) : null;
|
||||
}
|
||||
|
||||
function markLeft() {
|
||||
try {
|
||||
var k = leftKey();
|
||||
if (k) {
|
||||
sessionStorage.setItem(k, String(Date.now()));
|
||||
}
|
||||
sessionStorage.removeItem('f7_apk_direct_join');
|
||||
document.documentElement.removeAttribute('data-f7-direct-join');
|
||||
log('marked left');
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
|
||||
function leftRecently() {
|
||||
try {
|
||||
var k = leftKey();
|
||||
if (!k) {
|
||||
return false;
|
||||
}
|
||||
var ts = parseInt(sessionStorage.getItem(k) || '0', 10);
|
||||
return ts > 0 && (Date.now() - ts) < (10 * 60 * 1000);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isDirectJoin() {
|
||||
if (leftRecently()) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sessionStorage.getItem('f7_apk_direct_join') === '1';
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function stripDirectCallHash() {
|
||||
try {
|
||||
if (window.location.hash === '#direct-call') {
|
||||
history.replaceState(history.state, '', window.location.pathname + window.location.search);
|
||||
log('stripped #direct-call hash');
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
|
||||
function prepareStorage() {
|
||||
stripDirectCallHash();
|
||||
try {
|
||||
localStorage.setItem('showMediaSettings', 'false');
|
||||
document.documentElement.setAttribute('data-f7-direct-join', '1');
|
||||
} catch (e) { /* ignore */ }
|
||||
var token = roomToken();
|
||||
if (token) {
|
||||
try {
|
||||
localStorage.setItem('videoDisabled_' + token, 'true');
|
||||
localStorage.removeItem('audioDisabled_' + token);
|
||||
} catch (e2) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
function hideMediaDialogs() {
|
||||
var roots = document.querySelectorAll('.media-settings');
|
||||
for (var i = 0; i < roots.length; i++) {
|
||||
var el = roots[i];
|
||||
var modal = el.closest('.modal-wrapper')
|
||||
|| el.closest('.modal-container')
|
||||
|| el.closest('[role="dialog"]')
|
||||
|| el;
|
||||
modal.style.setProperty('display', 'none', 'important');
|
||||
modal.style.setProperty('visibility', 'hidden', 'important');
|
||||
modal.style.setProperty('opacity', '0', 'important');
|
||||
modal.style.setProperty('pointer-events', 'none', 'important');
|
||||
}
|
||||
}
|
||||
|
||||
function injectHideStyle() {
|
||||
if (document.getElementById(STYLE_ID)) {
|
||||
return;
|
||||
}
|
||||
var style = document.createElement('style');
|
||||
style.id = STYLE_ID;
|
||||
style.textContent = ''
|
||||
+ 'html[data-f7-direct-join="1"] .modal-wrapper,'
|
||||
+ 'html[data-f7-direct-join="1"] .modal-container,'
|
||||
+ 'html[data-f7-direct-join="1"] .media-settings,'
|
||||
+ 'html[data-f7-direct-join="1"] .modal-wrapper .media-settings'
|
||||
+ '{display:none!important;visibility:hidden!important;opacity:0!important;pointer-events:none!important;}';
|
||||
(document.head || document.documentElement).appendChild(style);
|
||||
hideMediaDialogs();
|
||||
}
|
||||
|
||||
function eventBus() {
|
||||
if (window._nc_event_bus) {
|
||||
return window._nc_event_bus;
|
||||
}
|
||||
if (window.OC && window.OC._eventBus) {
|
||||
return window.OC._eventBus;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function emitEvent(name, arg) {
|
||||
var bus = eventBus();
|
||||
if (!bus || typeof bus.emit !== 'function') {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
bus.emit(name, arg === undefined ? '' : arg);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function labelMatchesMediaToggle(label) {
|
||||
return label.indexOf('camera') !== -1 || label.indexOf('video') !== -1
|
||||
|| label.indexOf('камер') !== -1 || label.indexOf('видео') !== -1
|
||||
|| label.indexOf('mute video') !== -1 || label.indexOf('turn off') !== -1;
|
||||
}
|
||||
|
||||
function disableCameraInMediaSettings() {
|
||||
var root = document.querySelector('.media-settings');
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
var toggles = root.querySelector('.media-settings__toggles');
|
||||
var scope = toggles || root;
|
||||
var buttons = scope.querySelectorAll('button');
|
||||
for (var i = 0; i < buttons.length; i++) {
|
||||
var b = buttons[i];
|
||||
var label = ((b.getAttribute('aria-label') || '') + ' ' + (b.getAttribute('title') || '')).toLowerCase();
|
||||
if (!labelMatchesMediaToggle(label)) {
|
||||
continue;
|
||||
}
|
||||
var pressed = b.getAttribute('aria-pressed');
|
||||
if (pressed === 'true' || pressed === null) {
|
||||
b.click();
|
||||
log('toggled camera off: ' + label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clickJoinButtons() {
|
||||
var root = document.querySelector('.media-settings');
|
||||
if (root) {
|
||||
var inDialog = root.querySelectorAll('button.action-button, button.primary, button[class*="join"]');
|
||||
for (var d = 0; d < inDialog.length; d++) {
|
||||
var db = inDialog[d];
|
||||
if (db.disabled || db.offsetParent === null) {
|
||||
continue;
|
||||
}
|
||||
var dt = ((db.getAttribute('aria-label') || '') + ' ' + (db.textContent || '')).toLowerCase();
|
||||
if (dt.indexOf('join') !== -1 || dt.indexOf('присоедин') !== -1
|
||||
|| dt.indexOf('answer') !== -1 || dt.indexOf('начать') !== -1
|
||||
|| dt.indexOf('apply') !== -1 || dt.indexOf('примен') !== -1
|
||||
|| dt.indexOf('save') !== -1 || dt.indexOf('сохран') !== -1
|
||||
|| dt.indexOf('готово') !== -1) {
|
||||
db.click();
|
||||
log('clicked in-dialog: ' + dt);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var btn = document.querySelector('button.join-call');
|
||||
if (btn && !btn.disabled && btn.offsetParent !== null) {
|
||||
btn.click();
|
||||
log('clicked button.join-call');
|
||||
return true;
|
||||
}
|
||||
|
||||
var buttons = document.querySelectorAll('button.action-button, button.primary');
|
||||
for (var i = 0; i < buttons.length; i++) {
|
||||
var b = buttons[i];
|
||||
if (b.disabled || b.offsetParent === null) {
|
||||
continue;
|
||||
}
|
||||
var t = ((b.getAttribute('aria-label') || '') + ' ' + (b.textContent || '')).toLowerCase();
|
||||
if (t.indexOf('join') !== -1 || t.indexOf('присоедин') !== -1
|
||||
|| t.indexOf('answer') !== -1 || t.indexOf('ответ') !== -1
|
||||
|| t.indexOf('принять') !== -1 || t.indexOf('начать') !== -1) {
|
||||
b.click();
|
||||
log('clicked: ' + t);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function forceJoin() {
|
||||
if (!isDirectJoin()) {
|
||||
return false;
|
||||
}
|
||||
prepareStorage();
|
||||
injectHideStyle();
|
||||
disableCameraInMediaSettings();
|
||||
emitEvent('talk:media-settings:hide');
|
||||
if (clickJoinButtons()) {
|
||||
try { sessionStorage.removeItem('f7_apk_direct_join'); } catch (e) { /* ignore */ }
|
||||
setTimeout(function () {
|
||||
document.documentElement.removeAttribute('data-f7-direct-join');
|
||||
}, 5000);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function installLeaveHook() {
|
||||
if (window.__f7TalkLeaveHook) {
|
||||
return;
|
||||
}
|
||||
window.__f7TalkLeaveHook = true;
|
||||
document.addEventListener('click', function (ev) {
|
||||
var el = ev.target;
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < 5 && el; i++) {
|
||||
if (el.tagName && el.tagName.toLowerCase() === 'button') {
|
||||
break;
|
||||
}
|
||||
el = el.parentElement;
|
||||
}
|
||||
if (!el || !el.tagName || el.tagName.toLowerCase() !== 'button') {
|
||||
return;
|
||||
}
|
||||
var txt = ((el.getAttribute('aria-label') || '') + ' ' + (el.textContent || '')).toLowerCase();
|
||||
if (txt.indexOf('leave') !== -1 || txt.indexOf('hang up') !== -1 || txt.indexOf('end') !== -1
|
||||
|| txt.indexOf('выйти') !== -1 || txt.indexOf('покин') !== -1 || txt.indexOf('заверш') !== -1) {
|
||||
markLeft();
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
function installBusHook() {
|
||||
if (window.__f7TalkBusHook) {
|
||||
return;
|
||||
}
|
||||
var bus = eventBus();
|
||||
if (!bus || typeof bus.on !== 'function') {
|
||||
return;
|
||||
}
|
||||
window.__f7TalkBusHook = true;
|
||||
bus.on('talk:media-settings:show', function () {
|
||||
if (!isDirectJoin()) {
|
||||
return;
|
||||
}
|
||||
log('block media-settings');
|
||||
prepareStorage();
|
||||
injectHideStyle();
|
||||
setTimeout(function () {
|
||||
disableCameraInMediaSettings();
|
||||
emitEvent('talk:media-settings:hide');
|
||||
forceJoin();
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
|
||||
var tries = 0;
|
||||
function tick() {
|
||||
if (!isDirectJoin()) {
|
||||
return;
|
||||
}
|
||||
installLeaveHook();
|
||||
installBusHook();
|
||||
injectHideStyle();
|
||||
tries++;
|
||||
if (forceJoin() || tries >= 100) {
|
||||
return;
|
||||
}
|
||||
setTimeout(tick, 200);
|
||||
}
|
||||
|
||||
function start() {
|
||||
prepareStorage();
|
||||
if (!isDirectJoin()) {
|
||||
return;
|
||||
}
|
||||
if (!roomToken()) {
|
||||
return;
|
||||
}
|
||||
tries = 0;
|
||||
installLeaveHook();
|
||||
installBusHook();
|
||||
tick();
|
||||
}
|
||||
|
||||
window.addEventListener('hashchange', start);
|
||||
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||
start();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', start);
|
||||
window.addEventListener('load', start);
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user