fix detail: resolve wrapped object + catalog fallback, native meta layout, Watch/Download buttons, back via keydown+Controller
This commit is contained in:
1 parent
2e7970ae7a
commit
202fb021b2
1 file changed
+106
-27
@@ -56,12 +56,18 @@
|
||||
var css =
|
||||
'.mymovies{padding:2.2em 3.4em;overflow-y:auto;height:100%;box-sizing:border-box}' +
|
||||
'.movies-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:1.4em}' +
|
||||
'.mymovies-detail{padding:3em;max-width:900px}' +
|
||||
'.detail-head{display:flex;gap:2em;flex-wrap:wrap}' +
|
||||
'.detail-poster{width:220px;border-radius:10px}' +
|
||||
'.detail-info h1{margin:0 0 .4em;font-size:1.8em}' +
|
||||
'.detail-info>div{margin:.3em 0;opacity:.85}' +
|
||||
'.detail-actions{margin-top:1.5em}' +
|
||||
'.mymovies-detail{padding:3em;max-width:980px;box-sizing:border-box}' +
|
||||
'.detail-head{display:flex;gap:2.2em;flex-wrap:wrap;align-items:flex-start}' +
|
||||
'.detail-poster{width:240px;max-width:40vw;border-radius:12px;display:block;background:#1b1b1f}' +
|
||||
'.detail-info{flex:1;min-width:260px}' +
|
||||
'.detail-info h1{margin:0 0 .35em;font-size:2em;line-height:1.15}' +
|
||||
'.detail-orig{opacity:.6;font-size:1.1em;margin-bottom:.6em}' +
|
||||
'.detail-meta{display:flex;flex-wrap:wrap;gap:.6em;margin:.4em 0 1em}' +
|
||||
'.detail-meta>span{padding:.25em .7em;border-radius:6px;background:rgba(255,255,255,.08);font-size:.95em}' +
|
||||
'.detail-desc{opacity:.85;line-height:1.5;font-size:1.05em;margin-top:.6em;max-width:60ch}' +
|
||||
'.detail-actions{display:flex;gap:1em;margin-top:1.8em;flex-wrap:wrap}' +
|
||||
'.detail-actions .btn{padding:.7em 1.8em;border-radius:8px;background:rgba(255,255,255,.1);font-size:1.1em;cursor:pointer}' +
|
||||
'.detail-actions .btn.focus,.detail-actions .btn:hover{background:var(--accent-color,#3a7afe);color:#fff}' +
|
||||
'.mymovies-empty{padding:2em;opacity:.6;font-size:1.2em}';
|
||||
$('<style id="mymovies-style">').text(css).appendTo('head');
|
||||
}
|
||||
@@ -77,6 +83,17 @@
|
||||
|
||||
this.create = function (b) {
|
||||
body = b;
|
||||
comp._onKey = function (e) {
|
||||
if (e.key === 'Backspace' || e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
Lampa.Activity.back();
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', comp._onKey, true);
|
||||
};
|
||||
|
||||
this.destroy = function () {
|
||||
if (comp._onKey) document.removeEventListener('keydown', comp._onKey, true);
|
||||
};
|
||||
|
||||
// Wire up keyboard/remote navigation (pattern from Shikimori plugin).
|
||||
@@ -139,6 +156,7 @@
|
||||
var movies = (data && data.movies) || [];
|
||||
movies = sortMovies(movies);
|
||||
comp._movies = movies;
|
||||
window.__mymovies_catalog = movies;
|
||||
console.log('[mymovies] loaded', movies.length, 'films');
|
||||
renderMovies($(grid), movies);
|
||||
// re-apply navigation once cards exist (activity.start may have run before load)
|
||||
@@ -187,30 +205,67 @@
|
||||
|
||||
// ---------- Component: movie detail ----------
|
||||
var selected = null;
|
||||
function resolveMovie(m) {
|
||||
// Lampa sometimes wraps the pushed object; normalize to the real film.
|
||||
if (m && m.object && (m.object.id || m.object.poster || m.object.title)) return m.object;
|
||||
return m;
|
||||
}
|
||||
function MyMoviesDetail() {
|
||||
var comp = this;
|
||||
var body;
|
||||
|
||||
this.create = function (b) {
|
||||
body = b;
|
||||
// Browser/keyboard fallback: Backspace / Escape -> back (remote uses Controller 'back')
|
||||
comp._onKey = function (e) {
|
||||
if (e.key === 'Backspace' || e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
Lampa.Activity.back();
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', comp._onKey, true);
|
||||
};
|
||||
|
||||
this.destroy = function () {
|
||||
if (comp._onKey) document.removeEventListener('keydown', comp._onKey, true);
|
||||
};
|
||||
|
||||
this.start = function () {
|
||||
// Remote: only "back" is needed on the detail screen.
|
||||
Lampa.Controller.add('mymovies_detail', {
|
||||
back: function () {
|
||||
Lampa.Activity.back();
|
||||
},
|
||||
gone: function () {
|
||||
Lampa.Controller.clear('mymovies_detail');
|
||||
}
|
||||
});
|
||||
Lampa.Controller.toggle('mymovies_detail');
|
||||
var apply = function () {
|
||||
var btns = $('.mymovies-detail .detail-actions .btn.selector');
|
||||
if (!btns.length) return;
|
||||
Lampa.Controller.add('mymovies_detail', {
|
||||
toggle: function () {
|
||||
Lampa.Controller.collectionSet($('.mymovies-detail .detail-actions'));
|
||||
Lampa.Controller.collectionFocus(btns[0], $('.mymovies-detail .detail-actions'));
|
||||
},
|
||||
back: function () { Lampa.Activity.back(); },
|
||||
right: function () { Navigator.move('right'); },
|
||||
left: function () { Navigator.move('left'); },
|
||||
enter: function () {
|
||||
var el = $('.mymovies-detail .detail-actions .btn.selector.focus')[0] || btns[0];
|
||||
if (!el) return;
|
||||
if (el.getAttribute('data-act') === 'download') download(m);
|
||||
else play(m);
|
||||
},
|
||||
gone: function () { Lampa.Controller.clear('mymovies_detail'); }
|
||||
});
|
||||
Lampa.Controller.toggle('mymovies_detail');
|
||||
};
|
||||
apply();
|
||||
setTimeout(apply, 300);
|
||||
};
|
||||
|
||||
this.render = function () {
|
||||
var m = (comp.activity && comp.activity.object) || selected;
|
||||
if (!m) { Lampa.Activity.back(); return document.createElement('div'); }
|
||||
var raw = (comp.activity && comp.activity.object) || selected;
|
||||
var m = resolveMovie(raw);
|
||||
// Fallback: lookup full record from the cached catalog by id.
|
||||
if ((!m || !m.poster) && window.__mymovies_catalog) {
|
||||
var id = m && m.id;
|
||||
var found = window.__mymovies_catalog.filter(function (x) { return x.id === id; })[0];
|
||||
if (found) m = found;
|
||||
}
|
||||
if (!m || !m.title) { Lampa.Activity.back(); return document.createElement('div'); }
|
||||
|
||||
injectStyles();
|
||||
var html = document.createElement('div');
|
||||
@@ -220,6 +275,7 @@
|
||||
var poster = document.createElement('img');
|
||||
poster.className = 'detail-poster';
|
||||
poster.src = resolve(m.poster || m.cover);
|
||||
poster.alt = m.title || '';
|
||||
head.appendChild(poster);
|
||||
var info = document.createElement('div');
|
||||
info.className = 'detail-info';
|
||||
@@ -227,22 +283,34 @@
|
||||
h1.textContent = m.title;
|
||||
info.appendChild(h1);
|
||||
if (m.original_title) { var d = document.createElement('div'); d.className = 'detail-orig'; d.textContent = m.original_title; info.appendChild(d); }
|
||||
if (m.year) { var d = document.createElement('div'); d.className = 'detail-year'; d.textContent = m.year; info.appendChild(d); }
|
||||
if (m.genre && m.genre.length) { var d = document.createElement('div'); d.className = 'detail-genre'; d.textContent = m.genre.join(', '); info.appendChild(d); }
|
||||
if (m.rating) { var d = document.createElement('div'); d.className = 'detail-rating'; d.textContent = '★ ' + m.rating; info.appendChild(d); }
|
||||
var meta = document.createElement('div');
|
||||
meta.className = 'detail-meta';
|
||||
if (m.year) { var s = document.createElement('span'); s.textContent = m.year; meta.appendChild(s); }
|
||||
if (m.genre && m.genre.length) { var s = document.createElement('span'); s.textContent = m.genre.join(', '); meta.appendChild(s); }
|
||||
if (m.rating) { var s = document.createElement('span'); s.textContent = '★ ' + m.rating; meta.appendChild(s); }
|
||||
if (meta.children.length) info.appendChild(meta);
|
||||
if (m.description) { var d = document.createElement('div'); d.className = 'detail-desc'; d.textContent = m.description; info.appendChild(d); }
|
||||
head.appendChild(info);
|
||||
html.appendChild(head);
|
||||
|
||||
var actions = document.createElement('div');
|
||||
actions.className = 'detail-actions';
|
||||
var btn = document.createElement('div');
|
||||
btn.className = 'btn selector';
|
||||
btn.setAttribute('data-act', 'play');
|
||||
btn.textContent = 'Watch';
|
||||
actions.appendChild(btn);
|
||||
var btnWatch = document.createElement('div');
|
||||
btnWatch.className = 'btn selector';
|
||||
btnWatch.setAttribute('data-act', 'play');
|
||||
btnWatch.textContent = 'Watch';
|
||||
actions.appendChild(btnWatch);
|
||||
if (m.torrent || m.magnet) {
|
||||
var btnDl = document.createElement('div');
|
||||
btnDl.className = 'btn selector';
|
||||
btnDl.setAttribute('data-act', 'download');
|
||||
btnDl.textContent = 'Download';
|
||||
actions.appendChild(btnDl);
|
||||
$(btnDl).on('hover:enter', function () { download(m); });
|
||||
}
|
||||
html.appendChild(actions);
|
||||
|
||||
$(btn).on('hover:enter', function () { play(m); });
|
||||
$(btnWatch).on('hover:enter', function () { play(m); });
|
||||
return html;
|
||||
};
|
||||
}
|
||||
@@ -270,6 +338,17 @@
|
||||
});
|
||||
}
|
||||
|
||||
function download(m) {
|
||||
var url = m.magnet ? m.magnet : resolve(m.torrent);
|
||||
if (!url) return;
|
||||
// Open the torrent/magnet in the system (player or download manager)
|
||||
if (Lampa.Player && Lampa.Player.play) {
|
||||
Lampa.Player.play({ url: url, title: m.title, img: resolve(m.poster || m.cover), season: 0, episode: 0 });
|
||||
} else {
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Menu item ----------
|
||||
// Lampa builds the main menu on the 'menu:start' event, e.body is the jQuery menu root.
|
||||
// Remove ALL old copies from the DOM first, then add exactly one button.
|
||||
|
||||
Reference in new issue
Block a user