mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #1096 from ConfusedPolarBear/quickconnect
Add quick connect (login without typing password)
This commit is contained in:
commit
1dad3e7eeb
15 changed files with 319 additions and 3 deletions
58
src/controllers/dashboard/quickconnect.js
Normal file
58
src/controllers/dashboard/quickconnect.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
import loading from 'loading';
|
||||
import toast from 'toast';
|
||||
import globalize from 'globalize';
|
||||
|
||||
const unavailable = 'Unavailable';
|
||||
const available = 'Available';
|
||||
const active = 'Active';
|
||||
let page;
|
||||
|
||||
export default function(view) {
|
||||
view.addEventListener('viewshow', function () {
|
||||
page = this;
|
||||
loading.show();
|
||||
page.querySelector('#btnQuickConnectSubmit').onclick = onSubmit;
|
||||
updatePage();
|
||||
});
|
||||
}
|
||||
|
||||
function loadPage(status) {
|
||||
let check = status === available || status === active;
|
||||
|
||||
page.querySelector('#quickConnectStatus').textContent = status.toLocaleLowerCase();
|
||||
page.querySelector('#chkQuickConnectAvailable').checked = check;
|
||||
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
loading.show();
|
||||
|
||||
let newStatus = page.querySelector('#chkQuickConnectAvailable').checked ? available : unavailable;
|
||||
|
||||
let url = ApiClient.getUrl('/QuickConnect/Available?Status=' + newStatus);
|
||||
|
||||
ApiClient.ajax({
|
||||
type: 'POST',
|
||||
url: url
|
||||
}, true).then(() => {
|
||||
toast(globalize.translate('SettingsSaved'));
|
||||
setTimeout(updatePage, 500);
|
||||
|
||||
return true;
|
||||
}).catch((e) => {
|
||||
console.error('Unable to set quick connect status. error:', e);
|
||||
});
|
||||
|
||||
loading.hide();
|
||||
return false;
|
||||
}
|
||||
|
||||
function updatePage() {
|
||||
ApiClient.getQuickConnect('Status').then((response) => {
|
||||
loadPage(response);
|
||||
return true;
|
||||
}).catch((e) => {
|
||||
console.error('Unable to get quick connect status. error:', e);
|
||||
});
|
||||
}
|
|
@ -42,6 +42,10 @@
|
|||
<button is="emby-button" type="button" class="raised cancel block btnManual">
|
||||
<span>${ButtonManualLogin}</span>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="raised cancel block btnQuick">
|
||||
<span>${ButtonUseQuickConnect}</span>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="raised cancel block btnForgotPassword">
|
||||
<span>${ButtonForgotPassword}</span>
|
||||
|
|
|
@ -19,8 +19,7 @@ import 'emby-checkbox';
|
|||
var user = result.User;
|
||||
loading.hide();
|
||||
|
||||
Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient);
|
||||
Dashboard.navigate('home.html');
|
||||
onLoginSuccessful(user.Id, result.AccessToken, apiClient);
|
||||
}, function (response) {
|
||||
page.querySelector('#txtManualName').value = '';
|
||||
page.querySelector('#txtManualPassword').value = '';
|
||||
|
@ -41,6 +40,60 @@ import 'emby-checkbox';
|
|||
});
|
||||
}
|
||||
|
||||
function authenticateQuickConnect(apiClient) {
|
||||
let url = apiClient.getUrl('/QuickConnect/Initiate');
|
||||
apiClient.getJSON(url).then(function (json) {
|
||||
if (!json.Secret || !json.Code) {
|
||||
console.error('Malformed quick connect response', json);
|
||||
return false;
|
||||
}
|
||||
|
||||
Dashboard.alert({
|
||||
message: globalize.translate('QuickConnectAuthorizeCode', json.Code),
|
||||
title: globalize.translate('QuickConnect')
|
||||
});
|
||||
|
||||
let connectUrl = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret);
|
||||
|
||||
let interval = setInterval(function() {
|
||||
apiClient.getJSON(connectUrl).then(async function(data) {
|
||||
if (!data.Authenticated) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearInterval(interval);
|
||||
|
||||
let result = await apiClient.quickConnect(data.Authentication);
|
||||
onLoginSuccessful(result.User.Id, result.AccessToken, apiClient);
|
||||
}, function (e) {
|
||||
clearInterval(interval);
|
||||
|
||||
Dashboard.alert({
|
||||
message: globalize.translate('QuickConnectDeactivated'),
|
||||
title: globalize.translate('HeaderError')
|
||||
});
|
||||
|
||||
console.error('Unable to login with quick connect', e);
|
||||
});
|
||||
}, 5000, connectUrl);
|
||||
|
||||
return true;
|
||||
}, function(e) {
|
||||
Dashboard.alert({
|
||||
message: globalize.translate('QuickConnectNotActive'),
|
||||
title: globalize.translate('HeaderError')
|
||||
});
|
||||
|
||||
console.error('Quick connect error: ', e);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function onLoginSuccessful(id, accessToken, apiClient) {
|
||||
Dashboard.onServerChanged(id, accessToken, apiClient);
|
||||
Dashboard.navigate('home.html');
|
||||
}
|
||||
|
||||
function showManualForm(context, showCancel, focusPassword) {
|
||||
context.querySelector('.chkRememberLogin').checked = appSettings.enableAutoLogin();
|
||||
context.querySelector('.manualLoginForm').classList.remove('hide');
|
||||
|
@ -187,6 +240,11 @@ import 'emby-checkbox';
|
|||
Dashboard.navigate('forgotpassword.html');
|
||||
});
|
||||
view.querySelector('.btnCancel').addEventListener('click', showVisualForm);
|
||||
view.querySelector('.btnQuick').addEventListener('click', function () {
|
||||
const apiClient = getApiClient();
|
||||
authenticateQuickConnect(apiClient);
|
||||
return false;
|
||||
});
|
||||
view.querySelector('.btnManual').addEventListener('click', function () {
|
||||
view.querySelector('#txtManualName').value = '';
|
||||
showManualForm(view, true);
|
||||
|
@ -194,6 +252,7 @@ import 'emby-checkbox';
|
|||
view.querySelector('.btnSelectServer').addEventListener('click', function () {
|
||||
Dashboard.selectServer();
|
||||
});
|
||||
|
||||
view.addEventListener('viewshow', function (e) {
|
||||
loading.show();
|
||||
libraryMenu.setTransparentMenu(true);
|
||||
|
|
|
@ -48,6 +48,16 @@
|
|||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="lnkQuickConnectPreferences listItem-border">
|
||||
<div class="listItem">
|
||||
<em class="material-icons listItemIcon listItemIcon-transparent">tap_and_play</em>
|
||||
<div class="listItemBody">
|
||||
<div class="listItemBodyText">${QuickConnect}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="clientSettings listItem-border">
|
||||
<div class="listItem">
|
||||
<span class="material-icons listItemIcon listItemIcon-transparent devices_other"></span>
|
||||
|
|
|
@ -26,6 +26,7 @@ export default function (view, params) {
|
|||
page.querySelector('.lnkHomePreferences').setAttribute('href', 'mypreferenceshome.html?userId=' + userId);
|
||||
page.querySelector('.lnkPlaybackPreferences').setAttribute('href', 'mypreferencesplayback.html?userId=' + userId);
|
||||
page.querySelector('.lnkSubtitlePreferences').setAttribute('href', 'mypreferencessubtitles.html?userId=' + userId);
|
||||
page.querySelector('.lnkQuickConnectPreferences').setAttribute('href', 'mypreferencesquickconnect.html');
|
||||
|
||||
if (window.NativeShell && window.NativeShell.AppHost.supports('clientsettings')) {
|
||||
page.querySelector('.clientSettings').classList.remove('hide');
|
||||
|
|
17
src/controllers/user/quickConnect/index.html
Normal file
17
src/controllers/user/quickConnect/index.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
<div id="quickConnectPreferencesPage" data-role="page" class="page libraryPage userPreferencesPage noSecondaryNavPage" data-title="${QuickConnect}" data-backbutton="true" style="margin: 0 auto; max-width: 54em">
|
||||
<button is="emby-button" id="btnQuickConnectActivate" type="button" class="raised button-submit block">
|
||||
<span>${ButtonActivate}</span>
|
||||
</button>
|
||||
|
||||
<form class="quickConnectSettingsContainer">
|
||||
<div style="margin-bottom: 1em">
|
||||
${QuickConnectDescription}
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="number" min="0" max="999999" required id="txtQuickConnectCode" label="${LabelQuickConnectCode}" autocomplete="off" />
|
||||
</div>
|
||||
<button id="btnQuickConnectAuthorize" is="emby-button" type="submit" class="raised button-submit block">
|
||||
<span>${Authorize}</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
61
src/controllers/user/quickConnect/index.js
Normal file
61
src/controllers/user/quickConnect/index.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
import QuickConnectSettings from 'quickConnectSettings';
|
||||
import globalize from 'globalize';
|
||||
import toast from 'toast';
|
||||
|
||||
export default function (view) {
|
||||
let quickConnectSettingsInstance = null;
|
||||
|
||||
view.addEventListener('viewshow', function () {
|
||||
let codeElement = view.querySelector('#txtQuickConnectCode');
|
||||
|
||||
quickConnectSettingsInstance = new QuickConnectSettings();
|
||||
|
||||
view.querySelector('#btnQuickConnectActivate').addEventListener('click', () => {
|
||||
quickConnectSettingsInstance.activate(quickConnectSettingsInstance).then(() => {
|
||||
renderPage();
|
||||
});
|
||||
});
|
||||
|
||||
view.querySelector('#btnQuickConnectAuthorize').addEventListener('click', () => {
|
||||
if (!codeElement.validity.valid) {
|
||||
toast(globalize.translate('QuickConnectInvalidCode'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let code = codeElement.value;
|
||||
quickConnectSettingsInstance.authorize(code);
|
||||
});
|
||||
|
||||
view.querySelector('.quickConnectSettingsContainer').addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
renderPage();
|
||||
});
|
||||
|
||||
function renderPage(forceActive = false) {
|
||||
ApiClient.getQuickConnect('Status').then((status) => {
|
||||
let btn = view.querySelector('#btnQuickConnectActivate');
|
||||
let container = view.querySelector('.quickConnectSettingsContainer');
|
||||
|
||||
// The activation button should only be visible when quick connect is unavailable (with the text replaced with an error) or when it is available (so it can be activated)
|
||||
// The authorization container is only usable when quick connect is active, so it should be hidden otherwise
|
||||
container.style.display = 'none';
|
||||
|
||||
if (status === 'Unavailable') {
|
||||
btn.textContent = globalize.translate('QuickConnectNotAvailable');
|
||||
btn.disabled = true;
|
||||
btn.classList.remove('button-submit');
|
||||
btn.classList.add('button');
|
||||
} else if (status === 'Active' || forceActive) {
|
||||
container.style.display = '';
|
||||
btn.style.display = 'none';
|
||||
}
|
||||
|
||||
return true;
|
||||
}).catch((e) => {
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue