1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 07:39:15 +03:00

next force snapshot

This commit is contained in:
Anton Afanasyeu
2026-05-30 16:23:01 +02:00
parent eebee1864d
commit 3b0a694aa6
34 changed files with 1759 additions and 130 deletions

View File

@@ -11,33 +11,32 @@
})();
</script>
<link rel="stylesheet" href="/app/androidcast_project/crashes/assets/css/app.css">
<link rel="stylesheet" href="hub.css?v=20260527v">
<link rel="stylesheet" href="hub.css?v=20260529a">
<link rel="stylesheet" href="hub-logo-layers.css">
<script src="assets/analytics.config.js"></script>
<script src="/app/androidcast_project/crashes/assets/js/analytics.js" defer></script>
</head>
<body class="hub-page">
<div id="overtime-alphabet-host" hidden aria-hidden="true"></div>
<div id="quartz-alphabet-host" hidden aria-hidden="true"></div>
<div id="hub-logo-stage" class="hub-logo-stage" hidden aria-hidden="true"></div>
<section class="hub-clock-widget" id="hub-clock-widget" aria-label="World clock widget">
<div class="cw-row cw-row-main">
<div class="cw-cell cw-main-cell">
<div class="cw-line cw-line-time">
<div class="cw-clock-inner">
<div class="cw-primary-block">
<div class="cw-line cw-row cw-row-clock cw-line-time">
<strong class="cw-time-main">
<span id="cw-hm-lcd" class="ot-lcd-line ot-lcd-bold" aria-label="Hours and minutes"></span>
<span id="cw-ss-lcd" class="ot-lcd-line ot-lcd-sec ot-lcd-bold" aria-label="Seconds"></span>
<span id="cw-tz-text" class="ot-lcd-line ot-lcd-tz ot-lcd-bold" aria-label="Timezone offset"></span>
<span id="cw-hm-lcd" class="ot-lcd-line ot-lcd-bold cw-col-hm" aria-label="Hours and minutes"></span>
<span id="cw-colon-lcd" class="ot-lcd-line ot-lcd-colon cw-colon-blink" aria-label="Separator"></span>
<span id="cw-ss-lcd" class="ot-lcd-line ot-lcd-sec cw-col-ss" aria-label="Seconds"></span>
<span id="cw-tz-text" class="ot-lcd-line ot-lcd-tz cw-col-tz" aria-label="Timezone offset"></span>
</strong>
</div>
<div class="cw-line cw-line-region" id="cw-region">EUROPE/WARSAW</div>
<div class="cw-line cw-line-date" id="cw-date-line">WED 27 MAY 2026</div>
<div class="cw-line cw-row cw-row-tz cw-line-region ot-lcd-subline" id="cw-region">EUROPE/WARSAW</div>
<div class="cw-line cw-row cw-row-date cw-line-date ot-lcd-subline" id="cw-date-line">WED 27 MAY 2026</div>
</div>
<div class="cw-separator" aria-hidden="true"></div>
<div class="cw-world-section" id="cw-world-row"></div>
</div>
<div class="cw-row cw-row-mid">
<div class="cw-cell"></div>
<div class="cw-cell"></div>
<div class="cw-cell"></div>
<div class="cw-cell"></div>
</div>
<div class="cw-row cw-row-world" id="cw-world-row"></div>
</section>
<div id="hub-docs-modal" class="hub-docs-modal" hidden aria-hidden="true">
<div class="hub-docs-backdrop" data-close-docs></div>
@@ -59,7 +58,10 @@
<header class="hub-header">
<div class="hub-brand">
<img class="hub-logo-mark" src="assets/hub-logo-transparent.svg" alt="" width="112" height="84" decoding="async">
<h1 class="hub-title">Android Cast</h1>
<div class="hub-title-with-thunder">
<h1 class="hub-title">Android Cast</h1>
<img class="hub-thunder" src="assets/hub-thunder.svg?v=20260527z" alt="" decoding="async">
</div>
</div>
<p class="muted hub-subtitle">Project hub</p>
<label class="toolbar-select hub-theme">
@@ -114,7 +116,7 @@
var supportsLayout = !!(window.CSS && CSS.supports && CSS.supports('object-fit', 'cover'));
if (!supportsSvg || !supportsLayout) return;
var logoBuild = '20260527s';
var logoBuild = '20260529a';
var fragments = {
space: 'assets/hub-logo-fragment-space.svg',
globe: 'assets/hub-logo-fragment-globe.svg',
@@ -464,12 +466,15 @@
var overtimeReady = false;
var overtimeSymbolIds = {};
var quartzReady = false;
var quartzSymbolIds = {};
function overtimeSymbolId(ch) {
if (ch >= '0' && ch <= '9') return 'ot-' + ch;
if (ch === ':') return 'ot-colon';
if (ch === '+') return 'ot-plus';
if (ch === '-') return 'ot-minus';
if (ch === '/') return 'ot-slash';
if (ch === ' ') return 'ot-space';
if (ch >= 'A' && ch <= 'Z') return 'ot-' + ch;
return null;
@@ -491,60 +496,96 @@
.catch(function () { done(false); });
}
function buildGlyphGrid(svg, vb) {
function quartzSymbolId(ch) {
if (ch >= '0' && ch <= '9') return 'qz-' + ch;
if (ch === ':') return 'qz-colon';
if (ch === '+') return 'qz-plus';
if (ch === '-') return 'qz-minus';
if (ch === '/') return 'qz-slash';
if (ch === ' ') return 'qz-space';
if (ch >= 'A' && ch <= 'Z') return 'qz-' + ch;
return null;
}
function loadQuartzAlphabet(done) {
var host = document.getElementById('quartz-alphabet-host');
if (!host) { done(false); return; }
fetch('assets/quartz-alphabet.svg?v=' + logoBuild)
.then(function (res) { return res.text(); })
.then(function (svgText) {
host.innerHTML = svgText;
host.querySelectorAll('symbol').forEach(function (sym) {
if (sym.id) quartzSymbolIds[sym.id] = sym;
});
quartzReady = true;
done(true);
})
.catch(function () { done(false); });
}
var OVERTIME_SEG_GRID = [
[3, 1, 14, 3], [1, 4, 3, 11], [16, 4, 3, 11],
[3, 15, 14, 3], [1, 17, 3, 11], [16, 17, 3, 11],
[3, 28, 14, 3]
];
function parseOvertimeRects(sym) {
var rects = [];
sym.querySelectorAll('rect').forEach(function (node) {
rects.push({
x: parseFloat(node.getAttribute('x') || 0),
y: parseFloat(node.getAttribute('y') || 0),
w: parseFloat(node.getAttribute('width') || 0),
h: parseFloat(node.getAttribute('height') || 0)
});
});
return rects;
}
function overtimeSegMatchesRect(seg, rect) {
var eps = 1.25;
return Math.abs(rect.x - seg[0]) <= eps
&& Math.abs(rect.y - seg[1]) <= eps
&& Math.abs(rect.w - seg[2]) <= eps
&& Math.abs(rect.h - seg[3]) <= eps;
}
function overtimeSegIsLit(seg, activeRects) {
for (var i = 0; i < activeRects.length; i++) {
if (overtimeSegMatchesRect(seg, activeRects[i])) return true;
}
return false;
}
function buildOvertimeInactiveGrid(svg, sym, glyphW) {
if (glyphW === 12 || glyphW === 8 || glyphW === 16) return;
if (glyphW !== 20 && glyphW < 22) return;
var activeRects = parseOvertimeRects(sym);
var seg = document.createElementNS('http://www.w3.org/2000/svg', 'g');
seg.setAttribute('class', 'ot-grid');
var w = vb.width || 20;
var h = vb.height || 32;
var hPad = Math.max(1, w * 0.12);
var topY = Math.max(1, h * 0.04);
var midY = h * 0.47;
var botY = h * 0.86;
var segW = Math.max(6, w - hPad * 2);
var segH = Math.max(2, h * 0.09);
var vW = Math.max(2, w * 0.14);
var vH = Math.max(6, h * 0.33);
var leftX = Math.max(1, hPad * 0.45);
var rightX = Math.max(leftX + vW + 1, w - leftX - vW);
var upperY = topY + segH;
var lowerY = midY + segH * 0.6;
var defs = [
[hPad, topY, segW, segH],
[leftX, upperY, vW, vH],
[rightX, upperY, vW, vH],
[hPad, midY, segW, segH],
[leftX, lowerY, vW, vH],
[rightX, lowerY, vW, vH],
[hPad, botY, segW, segH]
];
defs.forEach(function (d) {
OVERTIME_SEG_GRID.forEach(function (d) {
if (overtimeSegIsLit(d, activeRects)) return;
var r = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
r.setAttribute('x', d[0].toFixed(2));
r.setAttribute('y', d[1].toFixed(2));
r.setAttribute('width', d[2].toFixed(2));
r.setAttribute('height', d[3].toFixed(2));
r.setAttribute('x', String(d[0]));
r.setAttribute('y', String(d[1]));
r.setAttribute('width', String(d[2]));
r.setAttribute('height', String(d[3]));
r.setAttribute('rx', '1');
seg.appendChild(r);
});
if (w >= 22) {
var d1 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
d1.setAttribute('x', (w * 0.34).toFixed(2));
d1.setAttribute('y', (h * 0.15).toFixed(2));
d1.setAttribute('width', Math.max(2, w * 0.10).toFixed(2));
d1.setAttribute('height', Math.max(6, h * 0.34).toFixed(2));
d1.setAttribute('rx', '1');
d1.setAttribute('transform', 'rotate(22 ' + (w * 0.39).toFixed(2) + ' ' + (h * 0.32).toFixed(2) + ')');
seg.appendChild(d1);
var d2 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
d2.setAttribute('x', (w * 0.56).toFixed(2));
d2.setAttribute('y', (h * 0.15).toFixed(2));
d2.setAttribute('width', Math.max(2, w * 0.10).toFixed(2));
d2.setAttribute('height', Math.max(6, h * 0.34).toFixed(2));
d2.setAttribute('rx', '1');
d2.setAttribute('transform', 'rotate(-22 ' + (w * 0.61).toFixed(2) + ' ' + (h * 0.32).toFixed(2) + ')');
seg.appendChild(d2);
}
svg.appendChild(seg);
if (seg.childNodes.length) svg.appendChild(seg);
}
function cloneOvertimeSymbol(svg, sym) {
sym.querySelectorAll('rect').forEach(function (node) {
var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
['x', 'y', 'width', 'height', 'rx', 'transform'].forEach(function (attr) {
var val = node.getAttribute(attr);
if (val != null) rect.setAttribute(attr, val);
});
rect.setAttribute('class', 'ot-active');
svg.appendChild(rect);
});
}
function renderOvertimeText(el, text, opts) {
@@ -556,8 +597,21 @@
return;
}
String(text).toUpperCase().split('').forEach(function (ch) {
if (opts.forceFallback) {
var forced = document.createElement('span');
forced.className = 'ot-fallback-char' + (opts.bold ? ' ot-fallback-char--bold' : '');
forced.textContent = ch === ' ' ? '\u00A0' : ch;
el.appendChild(forced);
return;
}
var sid = overtimeSymbolId(ch);
if (!sid || !overtimeSymbolIds[sid]) return;
if (!sid || !overtimeSymbolIds[sid]) {
var fb = document.createElement('span');
fb.className = 'ot-fallback-char' + (opts.bold ? ' ot-fallback-char--bold' : '');
fb.textContent = ch === ' ' ? '\u00A0' : ch;
el.appendChild(fb);
return;
}
var wrap = document.createElement('span');
wrap.className = 'ot-glyph-wrap' + (opts.bold ? ' ot-glyph-wrap--bold' : '');
if (opts.blinkColon && ch === ':') wrap.className += ' ot-colon-blink';
@@ -566,19 +620,82 @@
var viewBox = sym.getAttribute('viewBox') || '0 0 20 32';
svg.setAttribute('viewBox', viewBox);
svg.setAttribute('class', 'ot-glyph');
svg.setAttribute('aria-hidden', 'true');
var vb = viewBox.split(/\s+/).map(function (v) { return Number(v) || 0; });
buildGlyphGrid(svg, { width: vb[2] || 20, height: vb[3] || 32 });
var glyphW = vb[2] || 20;
if (opts.ghost !== false) buildOvertimeInactiveGrid(svg, sym, glyphW);
cloneOvertimeSymbol(svg, sym);
wrap.appendChild(svg);
el.appendChild(wrap);
});
}
/* Clock digits: original Overtime path (<use> only, no ghost grid). */
function renderOvertimeDigits(el, text, blinkColon, bold) {
if (!el) return;
el.innerHTML = '';
if (!overtimeReady) {
el.textContent = text;
return;
}
text.split('').forEach(function (ch) {
var sid = overtimeSymbolId(ch);
if (!sid || !overtimeSymbolIds[sid]) {
el.appendChild(document.createTextNode(ch));
return;
}
var wrap = document.createElement('span');
wrap.className = 'ot-glyph-wrap' + (bold ? ' ot-glyph-wrap--bold' : '');
if (blinkColon && ch === ':') wrap.className += ' ot-colon-blink';
var sym = overtimeSymbolIds[sid];
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('viewBox', sym.getAttribute('viewBox') || '0 0 20 32');
svg.setAttribute('class', 'ot-glyph');
var use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
use.setAttribute('href', '#' + sid);
use.setAttribute('class', 'ot-active');
svg.appendChild(use);
wrap.appendChild(svg);
el.appendChild(wrap);
});
}
function renderOvertimeDigits(el, text, blinkColon, bold) {
renderOvertimeText(el, text, { blinkColon: blinkColon, bold: bold });
function renderQuartzText(el, text, opts) {
opts = opts || {};
if (!el) return;
el.innerHTML = '';
if (!quartzReady) {
el.textContent = text;
return;
}
String(text).toUpperCase().split('').forEach(function (ch) {
var sid = quartzSymbolId(ch);
if (!sid || !quartzSymbolIds[sid]) {
var fb = document.createElement('span');
fb.className = 'qz-fallback-char' + (opts.bold ? ' qz-fallback-char--bold' : '');
fb.textContent = ch === ' ' ? '\u00A0' : ch;
el.appendChild(fb);
return;
}
var wrap = document.createElement('span');
wrap.className = 'qz-glyph-wrap' + (opts.bold ? ' qz-glyph-wrap--bold' : '');
if (opts.blinkColon && ch === ':') wrap.className += ' qz-colon-blink';
var sym = quartzSymbolIds[sid];
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
var viewBox = sym.getAttribute('viewBox') || '0 0 20 32';
svg.setAttribute('viewBox', viewBox);
svg.setAttribute('class', 'qz-glyph');
var vb = viewBox.split(/\s+/).map(function (v) { return Number(v) || 0; });
var use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
use.setAttribute('href', '#' + sid);
use.setAttribute('class', 'qz-active');
svg.appendChild(use);
wrap.appendChild(svg);
el.appendChild(wrap);
});
}
function renderQuartzDigits(el, text, blinkColon, bold) {
renderQuartzText(el, text, { blinkColon: blinkColon, bold: bold });
}
function regionLabel(tz) {
@@ -623,11 +740,12 @@
function updateClockWidget() {
var now = new Date();
var p = timeParts(now, primaryTz);
renderOvertimeDigits(document.getElementById('cw-hm-lcd'), p.hh + ':' + p.mm, false, true);
renderOvertimeDigits(document.getElementById('cw-ss-lcd'), ':' + p.ss, true, true);
renderOvertimeText(document.getElementById('cw-tz-text'), gmtOffsetLabel(now, primaryTz), { bold: true });
document.getElementById('cw-region').textContent = regionLabel(primaryTz);
document.getElementById('cw-date-line').textContent = formatDateLine(now, primaryTz);
renderOvertimeDigits(document.getElementById('cw-hm-lcd'), p.hh + p.mm, false, false);
renderOvertimeDigits(document.getElementById('cw-colon-lcd'), ':', false, false);
renderOvertimeDigits(document.getElementById('cw-ss-lcd'), p.ss, false, false);
renderOvertimeText(document.getElementById('cw-tz-text'), gmtOffsetLabel(now, primaryTz), { bold: false });
renderOvertimeText(document.getElementById('cw-region'), regionLabel(primaryTz), { bold: false });
renderOvertimeText(document.getElementById('cw-date-line'), formatDateLine(now, primaryTz), { bold: false });
secondary.forEach(function (clock) {
var t = timeParts(now, clock.tz);
@@ -651,12 +769,15 @@
h.className = 'cw-resize-handle cw-resize-' + pos;
h.dataset.resize = pos;
h.setAttribute('aria-hidden', 'true');
var visual = document.createElement('span');
visual.className = 'cw-resize-handle-visual';
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('viewBox', '0 0 45.279 45.279');
var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
path.setAttribute('d', arrowPath);
svg.appendChild(path);
h.appendChild(svg);
visual.appendChild(svg);
h.appendChild(visual);
widget.appendChild(h);
});
@@ -687,7 +808,7 @@
widget.style.left = Math.max(0, ev.clientX - drag.dx) + 'px';
widget.style.top = Math.max(0, ev.clientY - drag.dy) + 'px';
} else {
var minW = 1, minH = 1;
var minW = 280, minH = 210;
var dx = ev.clientX - drag.x;
var dy = ev.clientY - drag.y;
var left = drag.left, top = drag.top, width = drag.width, height = drag.height;
@@ -704,7 +825,7 @@
widget.style.left = Math.max(0, left) + 'px';
widget.style.top = Math.max(0, top) + 'px';
widget.style.width = width + 'px';
widget.style.minWidth = '';
widget.style.minWidth = width + 'px';
widget.style.transform = 'none';
}
});