1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

fix sync status display

This commit is contained in:
Luke Pulverenti 2015-10-02 02:14:04 -04:00
parent a07e6b59a3
commit 94a5cf7549
26 changed files with 415 additions and 276 deletions

View file

@ -880,7 +880,7 @@
var tests = []; var tests = [];
if (server.LastConnectionMode != null) { if (server.LastConnectionMode != null) {
tests.push(server.LastConnectionMode); //tests.push(server.LastConnectionMode);
} }
if (tests.indexOf(MediaBrowser.ConnectionMode.Manual) == -1) { tests.push(MediaBrowser.ConnectionMode.Manual); } if (tests.indexOf(MediaBrowser.ConnectionMode.Manual) == -1) { tests.push(MediaBrowser.ConnectionMode.Manual); }
if (tests.indexOf(MediaBrowser.ConnectionMode.Local) == -1) { tests.push(MediaBrowser.ConnectionMode.Local); } if (tests.indexOf(MediaBrowser.ConnectionMode.Local) == -1) { tests.push(MediaBrowser.ConnectionMode.Local); }

View file

@ -27,14 +27,14 @@
"web-component-tester": "*", "web-component-tester": "*",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
}, },
"homepage": "https://github.com/polymerelements/iron-behaviors", "homepage": "https://github.com/PolymerElements/iron-behaviors",
"_release": "1.0.8", "_release": "1.0.8",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.8", "tag": "v1.0.8",
"commit": "663ad706b43989f4961d945b8116cf4db346532f" "commit": "663ad706b43989f4961d945b8116cf4db346532f"
}, },
"_source": "git://github.com/polymerelements/iron-behaviors.git", "_source": "git://github.com/PolymerElements/iron-behaviors.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "polymerelements/iron-behaviors" "_originalSource": "PolymerElements/iron-behaviors"
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-overlay-behavior", "name": "iron-overlay-behavior",
"version": "1.0.8", "version": "1.0.9",
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",
"description": "Provides a behavior for making an element an overlay", "description": "Provides a behavior for making an element an overlay",
"private": true, "private": true,
@ -35,11 +35,11 @@
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
}, },
"homepage": "https://github.com/polymerelements/iron-overlay-behavior", "homepage": "https://github.com/polymerelements/iron-overlay-behavior",
"_release": "1.0.8", "_release": "1.0.9",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.8", "tag": "v1.0.9",
"commit": "cf25fe1ff2f585fa84190537bf62b94eb1579aad" "commit": "87f7763d323fffa07357a08777ad831b7c2c2fb8"
}, },
"_source": "git://github.com/polymerelements/iron-overlay-behavior.git", "_source": "git://github.com/polymerelements/iron-overlay-behavior.git",
"_target": "^1.0.0", "_target": "^1.0.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-overlay-behavior", "name": "iron-overlay-behavior",
"version": "1.0.8", "version": "1.0.9",
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",
"description": "Provides a behavior for making an element an overlay", "description": "Provides a behavior for making an element an overlay",
"private": true, "private": true,

View file

@ -28,7 +28,8 @@ intent. Closing generally implies that the user acknowledged the content on the
it will cancel whenever the user taps outside it or presses the escape key. This behavior is it will cancel whenever the user taps outside it or presses the escape key. This behavior is
configurable with the `no-cancel-on-esc-key` and the `no-cancel-on-outside-click` properties. configurable with the `no-cancel-on-esc-key` and the `no-cancel-on-outside-click` properties.
`close()` should be called explicitly by the implementer when the user interacts with a control `close()` should be called explicitly by the implementer when the user interacts with a control
in the overlay element. in the overlay element. When the dialog is canceled, the overlay fires an 'iron-overlay-canceled'
event. Call `preventDefault` on this event to prevent the overlay from closing.
### Positioning ### Positioning
@ -199,6 +200,11 @@ context. You should place this element as a child of `<body>` whenever possible.
* Cancels the overlay. * Cancels the overlay.
*/ */
cancel: function() { cancel: function() {
var cancelEvent = this.fire('iron-overlay-canceled', undefined, {cancelable: true});
if (cancelEvent.defaultPrevented) {
return;
}
this.opened = false; this.opened = false;
this._setCanceled(true); this._setCanceled(true);
}, },

View file

@ -180,6 +180,15 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}); });
test('cancel an overlay by clicking outside', function(done) { test('cancel an overlay by clicking outside', function(done) {
runAfterOpen(overlay, function() {
overlay.addEventListener('iron-overlay-canceled', function(event) {
done();
});
Polymer.Base.fire.call(document, 'click');
});
});
test('close an overlay by clicking outside', function(done) {
runAfterOpen(overlay, function() { runAfterOpen(overlay, function() {
overlay.addEventListener('iron-overlay-closed', function(event) { overlay.addEventListener('iron-overlay-closed', function(event) {
assert.isTrue(event.detail.canceled, 'overlay is canceled'); assert.isTrue(event.detail.canceled, 'overlay is canceled');
@ -189,7 +198,35 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}); });
}); });
test('cancel event can be prevented', function(done) {
runAfterOpen(overlay, function() {
overlay.addEventListener('iron-overlay-canceled', function(event) {
event.preventDefault();
});
var closedListener = function(event) {
throw new Error('iron-overlay-closed should not fire');
};
overlay.addEventListener('iron-overlay-closed', closedListener);
Polymer.Base.fire.call(document, 'click');
setTimeout(function() {
overlay.removeEventListener('iron-overlay-closed', closedListener);
done();
}, 10);
});
});
test('cancel an overlay with esc key', function(done) { test('cancel an overlay with esc key', function(done) {
runAfterOpen(overlay, function() {
overlay.addEventListener('iron-overlay-canceled', function(event) {
done();
});
fireEvent('keydown', {
keyCode: 27
}, document);
});
});
test('close an overlay with esc key', function(done) {
runAfterOpen(overlay, function() { runAfterOpen(overlay, function() {
overlay.addEventListener('iron-overlay-closed', function(event) { overlay.addEventListener('iron-overlay-closed', function(event) {
assert.isTrue(event.detail.canceled, 'overlay is canceled'); assert.isTrue(event.detail.canceled, 'overlay is canceled');

View file

@ -269,22 +269,7 @@
currentItemId = itemId; currentItemId = itemId;
currentItemType = itemType; currentItemType = itemType;
var dlg = document.createElement('paper-dialog'); var dlg = PaperDialogHelper.createDialog();
dlg.setAttribute('with-backdrop', 'with-backdrop');
dlg.setAttribute('role', 'alertdialog');
// without this safari will scroll the background instead of the dialog contents
// but not needed here since this is already on top of an existing dialog
// dlg.setAttribute('modal', 'modal');
// seeing max call stack size exceeded in the debugger with this
dlg.setAttribute('noAutoFocus', 'noAutoFocus');
dlg.entryAnimation = 'scale-up-animation';
dlg.exitAnimation = 'fade-out-animation';
dlg.classList.add('fullscreen-editor-paper-dialog');
dlg.classList.add('ui-body-b');
dlg.classList.add('smoothScrollY');
var html = ''; var html = '';
html += '<h2 class="dialogHeader">'; html += '<h2 class="dialogHeader">';

View file

@ -230,19 +230,7 @@
ApiClient.getItem(Dashboard.getCurrentUserId(), itemId).done(function (item) { ApiClient.getItem(Dashboard.getCurrentUserId(), itemId).done(function (item) {
var dlg = document.createElement('paper-dialog'); var dlg = PaperDialogHelper.createDialog();
dlg.setAttribute('with-backdrop', 'with-backdrop');
dlg.setAttribute('role', 'alertdialog');
// without this safari will scroll the background instead of the dialog contents
dlg.setAttribute('modal', 'modal');
// seeing max call stack size exceeded in the debugger with this
dlg.setAttribute('noAutoFocus', 'noAutoFocus');
dlg.entryAnimation = 'scale-up-animation';
dlg.exitAnimation = 'fade-out-animation';
dlg.classList.add('fullscreen-editor-paper-dialog');
dlg.classList.add('ui-body-b');
dlg.classList.add('smoothScrollY');
var html = ''; var html = '';
html += '<h2 class="dialogHeader">'; html += '<h2 class="dialogHeader">';

View file

@ -132,22 +132,7 @@
currentItemId = itemId; currentItemId = itemId;
var dlg = document.createElement('paper-dialog'); var dlg = PaperDialogHelper.createDialog();
dlg.setAttribute('with-backdrop', 'with-backdrop');
dlg.setAttribute('role', 'alertdialog');
// without this safari will scroll the background instead of the dialog contents
// but not needed here since this is already on top of an existing dialog
// dlg.setAttribute('modal', 'modal');
// seeing max call stack size exceeded in the debugger with this
dlg.setAttribute('noAutoFocus', 'noAutoFocus');
dlg.entryAnimation = 'scale-up-animation';
dlg.exitAnimation = 'fade-out-animation';
dlg.classList.add('fullscreen-editor-paper-dialog');
dlg.classList.add('ui-body-b');
dlg.classList.add('smoothScrollY');
var html = ''; var html = '';
html += '<h2 class="dialogHeader">'; html += '<h2 class="dialogHeader">';

View file

@ -66,15 +66,41 @@
function close(dlg) { function close(dlg) {
if (enableHashChange()) { if (enableHashChange()) {
history.back();
if (dlg.opened) {
history.back();
}
} else { } else {
dlg.close(); dlg.close();
} }
} }
function createDialog() {
var dlg = document.createElement('paper-dialog');
dlg.setAttribute('with-backdrop', 'with-backdrop');
dlg.setAttribute('role', 'alertdialog');
// without this safari will scroll the background instead of the dialog contents
// but not needed here since this is already on top of an existing dialog
dlg.setAttribute('modal', 'modal');
// seeing max call stack size exceeded in the debugger with this
dlg.setAttribute('noAutoFocus', 'noAutoFocus');
dlg.entryAnimation = 'scale-up-animation';
dlg.exitAnimation = 'fade-out-animation';
dlg.classList.add('fullscreen-editor-paper-dialog');
dlg.classList.add('ui-body-b');
dlg.classList.add('smoothScrollY');
return dlg;
}
globalScope.PaperDialogHelper = { globalScope.PaperDialogHelper = {
openWithHash: openWithHash, openWithHash: openWithHash,
close: close close: close,
createDialog: createDialog
}; };
})(this); })(this);

View file

@ -0,0 +1,10 @@
define([], function () {
return function (options) {
var result = prompt(options.text, options.defaultText || '');
if (options.callback) {
options.callback(result);
}
};
});

View file

@ -335,19 +335,7 @@
ApiClient.getItem(Dashboard.getCurrentUserId(), itemId).done(function (item) { ApiClient.getItem(Dashboard.getCurrentUserId(), itemId).done(function (item) {
var dlg = document.createElement('paper-dialog'); var dlg = PaperDialogHelper.createDialog();
dlg.setAttribute('with-backdrop', 'with-backdrop');
dlg.setAttribute('role', 'alertdialog');
// without this safari will scroll the background instead of the dialog contents
dlg.setAttribute('modal', 'modal');
// seeing max call stack size exceeded in the debugger with this
dlg.setAttribute('noAutoFocus', 'noAutoFocus');
dlg.entryAnimation = 'scale-up-animation';
dlg.exitAnimation = 'fade-out-animation';
dlg.classList.add('fullscreen-editor-paper-dialog');
dlg.classList.add('ui-body-b');
dlg.classList.add('smoothScrollY');
var html = ''; var html = '';
html += '<h2 class="dialogHeader">'; html += '<h2 class="dialogHeader">';

View file

@ -1,8 +1,16 @@
(function () { (function () {
var unlockId = "com.mb.android.unlock";
var updatedProducts = []; var updatedProducts = [];
function getStoreFeatureId(feature) {
if (feature == 'embypremieremonthly') {
return "emby.supporter.monthly";
}
return "com.mb.android.unlock";
}
function updateProductInfo(id, owned, price) { function updateProductInfo(id, owned, price) {
updatedProducts = updatedProducts.filter(function (r) { updatedProducts = updatedProducts.filter(function (r) {
@ -20,7 +28,10 @@
Events.trigger(IapManager, 'productupdated', [product]); Events.trigger(IapManager, 'productupdated', [product]);
} }
function getProduct(id) { function getProduct(feature) {
var id = getStoreFeatureId(feature);
var products = updatedProducts.filter(function (r) { var products = updatedProducts.filter(function (r) {
return r.id == id; return r.id == id;
}); });
@ -28,13 +39,14 @@
return products.length ? products[0] : null; return products.length ? products[0] : null;
} }
function isPurchaseAvailable(id) { function isPurchaseAvailable(feature) {
return NativeIapManager.isStoreAvailable(); return NativeIapManager.isStoreAvailable();
} }
function beginPurchase(id) { function beginPurchase(feature, email) {
return MainActivity.beginPurchase(id); var id = getStoreFeatureId(feature);
return MainActivity.beginPurchase(id, email);
} }
function onPurchaseComplete(result) { function onPurchaseComplete(result) {
@ -45,7 +57,31 @@
} }
function refreshPurchases() { function refreshPurchases() {
NativeIapManager.isPurchased(unlockId, "window.IapManager.updateProduct"); NativeIapManager.isPurchased(getStoreFeatureId("") + "|" + getStoreFeatureId("embypremieremonthly"), "window.IapManager.updateProduct");
//NativeIapManager.isPurchased(getStoreFeatureId("embypremieremonthly"), "window.IapManager.updateProduct");
}
function getSubscriptionOptions() {
var deferred = DeferredBuilder.Deferred();
var options = [];
options.push({
feature: 'embypremieremonthly',
buttonText: 'EmbyPremiereMonthlyWithPrice'
});
options = options.filter(function (o) {
return getProduct(o.feature) != null;
}).map(function (o) {
o.buttonText = Globalize.translate(o.buttonText, o.price);
return o;
});
deferred.resolveWith(null, [options]);
return deferred.promise();
} }
window.IapManager = { window.IapManager = {
@ -53,7 +89,9 @@
getProductInfo: getProduct, getProductInfo: getProduct,
updateProduct: updateProductInfo, updateProduct: updateProductInfo,
beginPurchase: beginPurchase, beginPurchase: beginPurchase,
onPurchaseComplete: onPurchaseComplete onPurchaseComplete: onPurchaseComplete,
getStoreFeatureId: getStoreFeatureId,
getSubscriptionOptions: getSubscriptionOptions
}; };
refreshPurchases(); refreshPurchases();

View file

@ -1,10 +1,16 @@
(function () { (function () {
var unlockAlias = "premium features";
var unlockAppProductId = 'appunlock';
var updatedProducts = []; var updatedProducts = [];
function getStoreFeatureId(feature) {
if (feature == 'embypremieremonthly') {
return 'emby.subscription.monthly';
}
return 'appunlock';
}
function updateProductInfo(product) { function updateProductInfo(product) {
updatedProducts = updatedProducts.filter(function (r) { updatedProducts = updatedProducts.filter(function (r) {
@ -16,17 +22,9 @@
Events.trigger(IapManager, 'productupdated', [product]); Events.trigger(IapManager, 'productupdated', [product]);
} }
function normalizeId(id) { function getProduct(feature) {
// This is what i named it in itunes var id = getStoreFeatureId(feature);
id = id.replace('premiumunlock', 'appunlock');
return id;
}
function getProduct(id) {
id = normalizeId(id);
var products = updatedProducts.filter(function (r) { var products = updatedProducts.filter(function (r) {
return r.id == id; return r.id == id;
@ -35,19 +33,19 @@
return products.length ? products[0] : null; return products.length ? products[0] : null;
} }
function isPurchaseAvailable(id) { function isPurchaseAvailable(feature) {
var product = getProduct(id);
var product = getProduct(feature);
return product != null && product.valid /*&& product.canPurchase*/; return product != null && product.valid /*&& product.canPurchase*/;
} }
function beginPurchase(id) { function beginPurchase(feature, email) {
id = normalizeId(id); var id = getStoreFeatureId(feature);
store.order(id); store.order(id);
} }
function restorePurchase(id) { function restorePurchase(id) {
id = normalizeId(id);
store.refresh(); store.refresh();
} }
@ -74,6 +72,36 @@
//callback(false, "Impossible to proceed with validation"); //callback(false, "Impossible to proceed with validation");
} }
function initProduct(id, alias, type) {
store.register({
id: id,
alias: alias,
type: type
});
// When purchase of the full version is approved,
// show some logs and finish the transaction.
store.when(id).approved(function (order) {
order.finish();
});
store.when(id).verified(function (p) {
p.finish();
});
// The play button can only be accessed when the user
// owns the full version.
store.when(id).updated(function (product) {
if (product.loaded && product.valid && product.state == store.APPROVED) {
Logger.log('finishing previously created transaction');
product.finish();
}
updateProductInfo(product);
});
}
function initializeStore() { function initializeStore() {
// Let's set a pretty high verbosity level, so that we see a lot of stuff // Let's set a pretty high verbosity level, so that we see a lot of stuff
@ -82,35 +110,8 @@
store.validator = validateProduct; store.validator = validateProduct;
// iOS initProduct(getStoreFeatureId(""), "premium features", store.NON_CONSUMABLE);
store.register({ initProduct(getStoreFeatureId("embypremieremonthly"), "emby premiere monthly", store.PAID_SUBSCRIPTION);
id: unlockAppProductId,
alias: unlockAlias,
type: store.NON_CONSUMABLE
});
// When purchase of the full version is approved,
// show some logs and finish the transaction.
store.when(unlockAppProductId).approved(function (order) {
log('You just unlocked the FULL VERSION!');
order.finish();
});
store.when(unlockAppProductId).verified(function (p) {
log("verified");
p.finish();
});
// The play button can only be accessed when the user
// owns the full version.
store.when(unlockAppProductId).updated(function (product) {
if (product.loaded && product.valid && product.state == store.APPROVED) {
Logger.log('finishing previously created transaction');
product.finish();
}
updateProductInfo(product);
});
// When every goes as expected, it's time to celebrate! // When every goes as expected, it's time to celebrate!
// The "ready" event should be welcomed with music and fireworks, // The "ready" event should be welcomed with music and fireworks,
@ -125,11 +126,36 @@
store.refresh(); store.refresh();
} }
function getSubscriptionOptions() {
var deferred = DeferredBuilder.Deferred();
var options = [];
options.push({
feature: 'embypremieremonthly',
buttonText: 'EmbyPremiereMonthlyWithPrice'
});
options = options.filter(function (o) {
return getProduct(o.feature) != null;
}).map(function (o) {
o.buttonText = Globalize.translate(o.buttonText, o.price);
return o;
});
deferred.resolveWith(null, [options]);
return deferred.promise();
}
window.IapManager = { window.IapManager = {
isPurchaseAvailable: isPurchaseAvailable, isPurchaseAvailable: isPurchaseAvailable,
getProductInfo: getProduct, getProductInfo: getProduct,
beginPurchase: beginPurchase, beginPurchase: beginPurchase,
restorePurchase: restorePurchase restorePurchase: restorePurchase,
getStoreFeatureId: getStoreFeatureId,
getSubscriptionOptions: getSubscriptionOptions
}; };
initializeStore(); initializeStore();

View file

@ -4,11 +4,11 @@
function onDeviceReady() { function onDeviceReady() {
var fetcher = window.BackgroundFetch; //var fetcher = window.BackgroundFetch;
fetcher.configure(onBackgroundFetch, onBackgroundFetchFailed, { //fetcher.configure(onBackgroundFetch, onBackgroundFetchFailed, {
stopOnTerminate: false // <-- false is default // stopOnTerminate: false // <-- false is default
}); //});
} }
function onSyncFinish() { function onSyncFinish() {
@ -86,7 +86,7 @@
}); });
}); });
pageClassOn('pageshow', "page", function () { pageClassOn('pageshow', "libraryPage", function () {
if (!Dashboard.getCurrentUserId()) { if (!Dashboard.getCurrentUserId()) {
return; return;

View file

@ -523,7 +523,7 @@
function downloadFile(url, localPath, enableBackground, enableNewDownloads) { function downloadFile(url, localPath, enableBackground, enableNewDownloads) {
if (!enableBackground) { if (!enableBackground) {
return downloadWithFileTransfer(url, localPath); return downloadWithFileTransfer(url, localPath, enableBackground);
} }
var deferred = DeferredBuilder.Deferred(); var deferred = DeferredBuilder.Deferred();

17
dashboard-ui/cordova/prompt.js vendored Normal file
View file

@ -0,0 +1,17 @@
define([], function () {
return function (options) {
var callback = function (result) {
if (result.buttonIndex == 1) {
options.callback(result.input1);
} else {
options.callback(null);
}
};
var buttonLabels = [Globalize.translate('ButtonOk'), Globalize.translate('ButtonCancel')];
navigator.notification.prompt(options.text, callback, options.title, buttonLabels, options.defaultText || '');
};
});

View file

@ -1,86 +1,56 @@
(function () { (function () {
function isAndroid() {
return $.browser.android;
}
function getPremiumUnlockFeatureId() {
if (isAndroid()) {
return "com.mb.android.unlock";
}
return 'appunlock';
}
function validatePlayback(deferred) {
// Don't require validation on android
if (isAndroid()) {
deferred.resolve();
return;
}
validateFeature(getPremiumUnlockFeatureId(), deferred);
}
function validateLiveTV(deferred) {
validateFeature(getPremiumUnlockFeatureId(), deferred);
}
function validateServerManagement(deferred) { function validateServerManagement(deferred) {
deferred.resolve(); deferred.resolve();
} }
function getRegistrationInfo(feature, enableSupporterUnlock) { function getRegistrationInfo(feature) {
if (!enableSupporterUnlock) {
var deferred = $.Deferred();
deferred.resolveWith(null, [{}]);
return deferred.promise();
}
return ConnectionManager.getRegistrationInfo(feature, ApiClient); return ConnectionManager.getRegistrationInfo(feature, ApiClient);
} }
var validatedFeatures = []; var validatedFeatures = [];
function validateFeature(id, deferred) { function validateFeature(feature, deferred) {
if (validatedFeatures.indexOf(id) != -1) { var id = IapManager.getStoreFeatureId(feature);
if (validatedFeatures.indexOf(feature) != -1) {
deferred.resolve(); deferred.resolve();
return; return;
} }
var info = IapManager.getProductInfo(id) || {}; var info = IapManager.getProductInfo(feature) || {};
if (info.owned) { if (info.owned) {
notifyServer(id); notifyServer(id);
validatedFeatures.push(id); validatedFeatures.push(feature);
deferred.resolve(); deferred.resolve();
return; return;
} }
var productInfo = { var productInfo = {
enableSupporterUnlock: true, enableAppUnlock: IapManager.isPurchaseAvailable(feature),
enableAppUnlock: IapManager.isPurchaseAvailable(id),
id: id, id: id,
price: info.price price: info.price,
feature: feature
}; };
var prefix = isAndroid() ? 'android' : 'ios'; var prefix = $.browser.android ? 'android' : 'ios';
// Get supporter status // Get supporter status
getRegistrationInfo(prefix + 'appunlock', productInfo.enableSupporterUnlock).done(function (registrationInfo) { getRegistrationInfo(prefix + 'appunlock').done(function (registrationInfo) {
if (registrationInfo.IsRegistered) { if (registrationInfo.IsRegistered) {
validatedFeatures.push(id); validatedFeatures.push(feature);
deferred.resolve(); deferred.resolve();
return; return;
} }
showInAppPurchaseInfo(productInfo, registrationInfo, deferred); IapManager.getSubscriptionOptions().done(function (subscriptionOptions) {
showInAppPurchaseInfo(productInfo, subscriptionOptions, registrationInfo, deferred);
});
}).fail(function () { }).fail(function () {
deferred.reject(); deferred.reject();
@ -114,42 +84,32 @@
}); });
} }
function getInAppPurchaseElement(info) { function getInAppPurchaseElement(info, subscriptionOptions) {
cancelInAppPurchase(); var dlg = PaperDialogHelper.createDialog();
var html = ''; var html = '';
html += '<div class="inAppPurchaseOverlay" style="background-image:url(css/images/splash.jpg);top:0;left:0;right:0;bottom:0;position:fixed;background-position:center center;background-size:100% 100%;background-repeat:no-repeat;z-index:999999;">'; html += '<h2 class="dialogHeader">';
html += '<div class="inAppPurchaseOverlayInner" style="background:rgba(10,10,10,.8);width:100%;height:100%;color:#eee;">'; html += '<paper-fab icon="arrow-back" class="mini btnCloseDialog"></paper-fab>';
html += '<div style="display:inline-block;margin-left:.6em;vertical-align:middle;">' + Globalize.translate('HeaderUnlockApp') + '</div>';
html += '</h2>';
html += '<div class="editorContent">';
html += '<div class="inAppPurchaseForm" style="margin: 0 auto;padding: 30px 1em 0;">'; html += '<form style="max-width: 800px;margin:auto;">';
html += '<h1 style="color:#fff;">' + Globalize.translate('HeaderUnlockApp') + '</h1>';
html += '<p style="margin:2em 0;">'; html += '<p style="margin:2em 0;">';
var showSupporterInfo = info.enableSupporterUnlock && !$.browser.safari; if (info.enableAppUnlock) {
if (showSupporterInfo && info.enableAppUnlock) {
html += Globalize.translate('MessageUnlockAppWithPurchaseOrSupporter'); html += Globalize.translate('MessageUnlockAppWithPurchaseOrSupporter');
} }
else if (showSupporterInfo) { else {
html += Globalize.translate('MessageUnlockAppWithSupporter'); html += Globalize.translate('MessageUnlockAppWithSupporter');
} else if (info.enableAppUnlock) {
html += Globalize.translate('MessageUnlockAppWithPurchase');
} else {
html += '<span style="color:red;">';
html += Globalize.translate('MessagePaymentServicesUnavailable');
html += '</span>';
} }
html += '</p>'; html += '</p>';
if (showSupporterInfo) { html += '<p style="margin:2em 0;">';
html += '<p style="margin:2em 0;">'; html += Globalize.translate('MessageToValidateSupporter');
html += Globalize.translate('MessageToValidateSupporter'); html += '</p>';
html += '</p>';
}
if (info.enableAppUnlock) { if (info.enableAppUnlock) {
@ -158,76 +118,118 @@
unlockText = Globalize.translate('ButtonUnlockPrice', info.price); unlockText = Globalize.translate('ButtonUnlockPrice', info.price);
} }
html += '<p>'; html += '<p>';
html += '<paper-button raised class="secondary block btnAppUnlock"><iron-icon icon="check"></iron-icon><span>' + unlockText + '</span></paper-button>'; html += '<paper-button raised class="secondary block btnPurchase" data-feature="' + info.feature + '"><iron-icon icon="check"></iron-icon><span>' + unlockText + '</span></paper-button>';
html += '</p>'; html += '</p>';
if (IapManager.restorePurchase) {
html += '<p>';
html += '<paper-button raised class="secondary block btnRestorePurchase" style="background-color: #673AB7;"><iron-icon icon="check"></iron-icon><span>' + Globalize.translate('ButtonRestorePreviousPurchase') + '</span></paper-button>';
html += '</p>';
}
} }
html += '<p>'; for (var i = 0, length = subscriptionOptions.length; i < length; i++) {
html += '<paper-button raised class="cancelDark block btnCancel"><iron-icon icon="close"></iron-icon><span>' + Globalize.translate('ButtonCancel') + '</span></paper-button>';
html += '</p>';
html += '<p>';
html += '<paper-button raised class="submit block btnPurchase" data-email="true" data-feature="' + subscriptionOptions[i].feature + '"><iron-icon icon="check"></iron-icon><span>';
html += subscriptionOptions[i].buttonText;
html += '</span></paper-button>';
html += '</p>';
}
if (IapManager.restorePurchase) {
html += '<p>';
html += '<paper-button raised class="secondary block btnRestorePurchase" style="background-color: #673AB7;"><iron-icon icon="check"></iron-icon><span>' + Globalize.translate('ButtonRestorePreviousPurchase') + '</span></paper-button>';
html += '</p>';
}
html += '</form>';
html += '</div>'; html += '</div>';
html += '</div>'; dlg.innerHTML = html;
html += '</div>'; document.body.appendChild(dlg);
$(document.body).append(html); // init dlg content here
return $('.inAppPurchaseOverlay'); PaperDialogHelper.openWithHash(dlg, 'iap');
$('.btnCloseDialog', dlg).on('click', function () {
PaperDialogHelper.close(dlg);
});
dlg.classList.add('inAppPurchaseOverlay');
return dlg;
} }
function cancelInAppPurchase() { function cancelInAppPurchase() {
$('.inAppPurchaseOverlay').remove(); var elem = document.querySelector('.inAppPurchaseOverlay');
if (elem) {
PaperDialogHelper.close(elem);
}
} }
var currentDisplayingProductInfo = null; var currentDisplayingProductInfos = [];
var currentDisplayingDeferred = null; var currentDisplayingDeferred = null;
var isCancelled = true;
function clearCurrentDisplayingInfo() { function clearCurrentDisplayingInfo() {
currentDisplayingProductInfo = null; currentDisplayingProductInfos = [];
currentDisplayingDeferred = null; currentDisplayingDeferred = null;
} }
function showInAppPurchaseInfo(info, serverRegistrationInfo, deferred) { function showInAppPurchaseInfo(info, subscriptionOptions, serverRegistrationInfo, deferred) {
var elem = getInAppPurchaseElement(info); require(['components/paperdialoghelper'], function () {
currentDisplayingProductInfo = info;
currentDisplayingDeferred = deferred;
$('.btnAppUnlock', elem).on('click', function () {
IapManager.beginPurchase(info.id);
});
$('.btnRestorePurchase', elem).on('click', function () {
IapManager.restorePurchase(info.id);
});
$('.btnCancel', elem).on('click', function () {
clearCurrentDisplayingInfo();
cancelInAppPurchase(); cancelInAppPurchase();
isCancelled = true;
deferred.reject(); var elem = getInAppPurchaseElement(info, subscriptionOptions);
});
$('.btnSignInSupporter', elem).on('click', function () {
clearCurrentDisplayingInfo(); // clone
currentDisplayingProductInfos = subscriptionOptions.slice(0);
currentDisplayingProductInfos.push(info);
Dashboard.alert({ currentDisplayingDeferred = deferred;
message: Globalize.translate('MessagePleaseSignInLocalNetwork'),
callback: function () { $('.btnPurchase', elem).on('click', function () {
isCancelled = false;
if (this.getAttribute('data-email') == 'true') {
promptForEmail(this.getAttribute('data-feature'));
} else {
IapManager.beginPurchase(this.getAttribute('data-feature'));
}
});
$('.btnRestorePurchase', elem).on('click', function () {
isCancelled = false;
IapManager.restorePurchase(info.feature);
});
$(elem).on('iron-overlay-closed', function () {
if (isCancelled) {
clearCurrentDisplayingInfo();
cancelInAppPurchase(); cancelInAppPurchase();
Dashboard.logout();
deferred.reject();
}
});
});
}
function promptForEmail(feature) {
require(['prompt'], function (prompt) {
prompt({
text: Globalize.translate('TextPleaseEnterYourEmailAddressForSubscription'),
title: Globalize.translate('HeaderEmailAddress'),
callback: function(email) {
if (email) {
IapManager.beginPurchase(this.getAttribute('data-feature'), email);
}
} }
}); });
}); });
@ -235,12 +237,15 @@
function onProductUpdated(e, product) { function onProductUpdated(e, product) {
var currentInfo = currentDisplayingProductInfo;
var deferred = currentDisplayingDeferred; var deferred = currentDisplayingDeferred;
if (currentInfo && deferred) { if (deferred && product.owned) {
if (product.owned && product.id == currentInfo.id) {
if (currentDisplayingProductInfos.filter(function (p) {
return product.id == p.id;
}).length) {
clearCurrentDisplayingInfo(); clearCurrentDisplayingInfo();
cancelInAppPurchase(); cancelInAppPurchase();
deferred.resolve(); deferred.resolve();
@ -305,11 +310,9 @@
var deferred = DeferredBuilder.Deferred(); var deferred = DeferredBuilder.Deferred();
if (name == 'playback') { if (name == 'playback') {
validatePlayback(deferred); validateFeature(name, deferred);
} else if (name == 'livetv') { } else if (name == 'livetv') {
validateLiveTV(deferred); validateFeature(name, deferred);
} else if (name == 'manageserver') {
validateServerManagement(deferred);
} else if (name == 'sync') { } else if (name == 'sync') {
validateSync(deferred); validateSync(deferred);
} else { } else {
@ -324,7 +327,7 @@
Events.on(IapManager, 'productupdated', onProductUpdated); Events.on(IapManager, 'productupdated', onProductUpdated);
} }
if (isAndroid()) { if ($.browser.android) {
requirejs(['cordova/android/iap'], onIapManagerLoaded); requirejs(['cordova/android/iap'], onIapManagerLoaded);
} else { } else {
requirejs(['cordova/iap'], onIapManagerLoaded); requirejs(['cordova/iap'], onIapManagerLoaded);

View file

@ -26,8 +26,9 @@
} else { } else {
var url = getUrl(name, culture); var url = getUrl(name, culture);
var requestUrl = url + "?v=" + window.dashboardVersion;
$.getJSON(url).done(function (dictionary) { $.getJSON(requestUrl).done(function (dictionary) {
dictionaries[url] = dictionary; dictionaries[url] = dictionary;
deferred.resolve(); deferred.resolve();

View file

@ -45,6 +45,7 @@
getPromise().done(function (item) { getPromise().done(function (item) {
reloadFromItem(page, item); reloadFromItem(page, item);
window.scrollTo(0, 0);
}); });
} }

View file

@ -548,13 +548,7 @@
closeMainDrawer(); closeMainDrawer();
requirejs(["scripts/registrationservices"], function () { Dashboard.navigate('dashboard.html');
RegistrationServices.validateFeature('manageserver').done(function () {
Dashboard.navigate('dashboard.html');
});
});
} }
function getTopParentId() { function getTopParentId() {

View file

@ -6,8 +6,6 @@
if (LocalSync.isSupported()) { if (LocalSync.isSupported()) {
page.querySelector('.localSyncStatus').classList.remove('hide');
var status = LocalSync.getSyncStatus(); var status = LocalSync.getSyncStatus();
page.querySelector('.labelSyncStatus').innerHTML = Globalize.translate('LabelLocalSyncStatusValue', status); page.querySelector('.labelSyncStatus').innerHTML = Globalize.translate('LabelLocalSyncStatusValue', status);
@ -20,9 +18,6 @@
page.querySelector('.btnSyncNow').classList.remove('hide'); page.querySelector('.btnSyncNow').classList.remove('hide');
} }
} else {
page.querySelector('.localSyncStatus').classList.add('hide');
page.querySelector('.syncSpinner').active = false;
} }
}); });
} }
@ -47,7 +42,19 @@
syncNow(page); syncNow(page);
}); });
}).on('pageshow', "#mySyncActivityPage", function () { require(['localsync'], function () {
if (LocalSync.isSupported()) {
page.querySelector('.localSyncStatus').classList.remove('hide');
} else {
page.querySelector('.localSyncStatus').classList.add('hide');
page.querySelector('.syncSpinner').active = false;
}
});
}).on('pagebeforeshow', "#mySyncActivityPage", function () {
var page = this; var page = this;

View file

@ -100,6 +100,12 @@ var Dashboard = {
return; return;
} }
// Don't bounce if the failure is in a sync service
if (url.indexOf('/sync') != -1) {
Dashboard.hideLoadingMsg();
return;
}
// Bounce to the login screen, but not if a password entry fails, obviously // Bounce to the login screen, but not if a password entry fails, obviously
if (url.indexOf('/password') == -1 && if (url.indexOf('/password') == -1 &&
url.indexOf('/authenticate') == -1 && url.indexOf('/authenticate') == -1 &&
@ -238,6 +244,8 @@ var Dashboard = {
importCss: function (url) { importCss: function (url) {
url += "?v=" + window.dashboardVersion;
if (!Dashboard.importedCss) { if (!Dashboard.importedCss) {
Dashboard.importedCss = []; Dashboard.importedCss = [];
} }
@ -2019,12 +2027,20 @@ var AppInfo = {};
urlArgs += new Date().getTime(); urlArgs += new Date().getTime();
} }
var paths = {
velocity: "bower_components/velocity/velocity.min"
};
if (Dashboard.isRunningInCordova()) {
paths.prompt = "cordova/prompt";
} else {
paths.prompt = "components/prompt";
}
requirejs.config({ requirejs.config({
urlArgs: urlArgs, urlArgs: urlArgs,
paths: { paths: paths
"velocity": "bower_components/velocity/velocity.min"
}
}); });
// Required since jQuery is loaded before requireJs // Required since jQuery is loaded before requireJs

View file

@ -788,11 +788,10 @@
"TabScenes": "Scenes", "TabScenes": "Scenes",
"HeaderUnlockApp": "Unlock App", "HeaderUnlockApp": "Unlock App",
"MessageUnlockAppWithPurchase": "Unlock the full features of the app with a small one-time purchase.", "MessageUnlockAppWithPurchase": "Unlock the full features of the app with a small one-time purchase.",
"MessageUnlockAppWithPurchaseOrSupporter": "Unlock the full features of the app with a small one-time purchase, or by signing in with an active Emby Supporter Membership.", "MessageUnlockAppWithPurchaseOrSupporter": "Unlock the full features of the app with a small one-time purchase, or with an active Emby Premiere subscription.",
"MessageUnlockAppWithSupporter": "Unlock the full features of the app by signing in with an active Emby Supporter Membership.", "MessageUnlockAppWithSupporter": "Unlock the full features of the app by signing in with an active Emby Premiere subscription.",
"MessageToValidateSupporter": "If you have an active Emby Supporter Membership, simply sign into the app using your Wifi connection within your home network.", "MessageToValidateSupporter": "If you have an active Emby Premiere subscription, simply sign into the app using your Wifi connection within your home network.",
"MessagePaymentServicesUnavailable": "Payment services are currently unavailable. Please try again later.", "MessagePaymentServicesUnavailable": "Payment services are currently unavailable. Please try again later.",
"ButtonUnlockWithSupporter": "Sign in with Emby Supporter Membership",
"MessagePleaseSignInLocalNetwork": "Before proceeding, please ensure that you're connected to your local network using a Wifi or LAN connection.", "MessagePleaseSignInLocalNetwork": "Before proceeding, please ensure that you're connected to your local network using a Wifi or LAN connection.",
"ButtonUnlockWithPurchase": "Unlock with Purchase", "ButtonUnlockWithPurchase": "Unlock with Purchase",
"ButtonUnlockPrice": "Unlock {0}", "ButtonUnlockPrice": "Unlock {0}",
@ -902,6 +901,9 @@
"HeaderEmbyForAndroidHasMoved": "Emby for Android has moved!", "HeaderEmbyForAndroidHasMoved": "Emby for Android has moved!",
"MessageEmbyForAndroidHasMoved": "Emby for Android has moved to a new home in the app store. Please consider checking out the new app. You may continue to use this app for as long as you wish.", "MessageEmbyForAndroidHasMoved": "Emby for Android has moved to a new home in the app store. Please consider checking out the new app. You may continue to use this app for as long as you wish.",
"HeaderNextUp": "Next Up", "HeaderNextUp": "Next Up",
"HeaderLatestMovies": "Latest Movies", "HeaderLatestMovies": "Latest Movies",
"HeaderLatestEpisodes": "Latest Episodes" "HeaderLatestEpisodes": "Latest Episodes",
"EmbyPremiereMonthlyWithPrice": "Emby Premiere Monthly {0}",
"HeaderEmailAddress": "E-Mail Address",
"TextPleaseEnterYourEmailAddressForSubscription": "Please enter your e-mail address."
} }

View file

@ -233,3 +233,6 @@ paper-tab {
.nowPlayingPage { .nowPlayingPage {
padding-top: 50px !important; padding-top: 50px !important;
} }
.localSyncStatus .labelSyncStatus {
display: none !important;
}

View file

@ -9835,7 +9835,8 @@ intent. Closing generally implies that the user acknowledged the content on the
it will cancel whenever the user taps outside it or presses the escape key. This behavior is it will cancel whenever the user taps outside it or presses the escape key. This behavior is
configurable with the `no-cancel-on-esc-key` and the `no-cancel-on-outside-click` properties. configurable with the `no-cancel-on-esc-key` and the `no-cancel-on-outside-click` properties.
`close()` should be called explicitly by the implementer when the user interacts with a control `close()` should be called explicitly by the implementer when the user interacts with a control
in the overlay element. in the overlay element. When the dialog is canceled, the overlay fires an 'iron-overlay-canceled'
event. Call `preventDefault` on this event to prevent the overlay from closing.
### Positioning ### Positioning
@ -10006,6 +10007,11 @@ context. You should place this element as a child of `<body>` whenever possible.
* Cancels the overlay. * Cancels the overlay.
*/ */
cancel: function() { cancel: function() {
var cancelEvent = this.fire('iron-overlay-canceled', undefined, {cancelable: true});
if (cancelEvent.defaultPrevented) {
return;
}
this.opened = false; this.opened = false;
this._setCanceled(true); this._setCanceled(true);
}, },