mirror of https://github.com/vladmandic/automatic
modernui mobile optimizations
Signed-off-by: Vladimir Mandic <mandic00@live.com>pull/4175/head
parent
0697fb2287
commit
5f6edafc8b
|
|
@ -17,6 +17,8 @@
|
|||
- **UI**
|
||||
- default to **ModernUI**
|
||||
standard ui is still available via *settings -> user interface -> theme type*
|
||||
- mobile-friendly!
|
||||
- make hints touch-friendly: hold touch to display hint
|
||||
- improved image scaling in img2img and control interfaces
|
||||
- add base model type to networks display, thanks @Artheriax
|
||||
- additional hints to ui, thanks @Artheriax
|
||||
|
|
|
|||
20
installer.py
20
installer.py
|
|
@ -622,18 +622,22 @@ def check_transformers():
|
|||
t_start = time.time()
|
||||
if args.skip_all or args.skip_git or args.experimental:
|
||||
return
|
||||
pkg = pkg_resources.working_set.by_key.get('transformers', None)
|
||||
pkg_transofmers = pkg_resources.working_set.by_key.get('transformers', None)
|
||||
pkg_tokenizers = pkg_resources.working_set.by_key.get('tokenizers', None)
|
||||
if args.use_directml:
|
||||
target = '4.52.4'
|
||||
target_transformers = '4.52.4'
|
||||
target_tokenizers = '0.21.4'
|
||||
else:
|
||||
target = '4.56.0'
|
||||
if (pkg is None) or ((pkg.version != target) and (not args.experimental)):
|
||||
if pkg is None:
|
||||
log.info(f'Transformers install: version={target}')
|
||||
target_transformers = '4.56.0'
|
||||
target_tokenizers = '0.22.0'
|
||||
if (pkg_transofmers is None) or ((pkg_transofmers.version != target_transformers) or (pkg_tokenizers is None) or ((pkg_tokenizers.version != target_tokenizers) and (not args.experimental))):
|
||||
if pkg_transofmers is None:
|
||||
log.info(f'Transformers install: version={target_transformers}')
|
||||
else:
|
||||
log.info(f'Transformers update: current={pkg.version} target={target}')
|
||||
log.info(f'Transformers update: current={pkg_transofmers.version} target={target_transformers}')
|
||||
pip('uninstall --yes transformers', ignore=True, quiet=True, uv=False)
|
||||
pip(f'install --upgrade transformers=={target}', ignore=False, quiet=True, uv=False)
|
||||
pip(f'install --upgrade tokenizers=={target_tokenizers}', ignore=False, quiet=True, uv=False)
|
||||
pip(f'install --upgrade transformers=={target_transformers}', ignore=False, quiet=True, uv=False)
|
||||
ts('transformers', t_start)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -128,8 +128,8 @@ div:has(>#tab-browser-folders) { flex-grow: 0 !important; background-color: var(
|
|||
|
||||
/* loader */
|
||||
.splash { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 1000; display: block; text-align: center; }
|
||||
.motd { margin-top: 2em; color: var(--body-text-color-subdued); font-family: monospace; font-variant: all-petite-caps; }
|
||||
.splash-img { margin: 10% auto 0 auto; width: 512px; background-repeat: no-repeat; height: 512px; animation: color 10s infinite alternate; max-width: 80vw; background-size: contain; }
|
||||
.motd { margin-top: 2em; color: var(--body-text-color-subdued); font-family: monospace; font-variant: all-petite-caps; font-size: 1.2em; }
|
||||
.splash-img { margin: 10% auto 0 auto; width: 512px; background-repeat: no-repeat; height: 512px; animation: hue 5s infinite alternate; max-width: 80vw; background-size: contain; }
|
||||
.loading { color: white; position: absolute; top: 20%; left: 50%; transform: translateX(-50%); }
|
||||
.loader { width: 300px; height: 300px; border: var(--spacing-md) solid transparent; border-radius: 50%; border-top: var(--spacing-md) solid var(--primary-600); animation: spin 4s linear infinite; position: relative; }
|
||||
.loader::before, .loader::after { content: ""; position: absolute; top: 6px; bottom: 6px; left: 6px; right: 6px; border-radius: 50%; border: var(--spacing-md) solid transparent; }
|
||||
|
|
@ -137,4 +137,4 @@ div:has(>#tab-browser-folders) { flex-grow: 0 !important; background-color: var(
|
|||
.loader::after { border-top-color: var(--primary-300); animation: spin 1.5s linear infinite; }
|
||||
@keyframes move { from { background-position-x: 0, -40px; } to { background-position-x: 0, 40px; } }
|
||||
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
||||
@keyframes color { from { filter: hue-rotate(0deg) } to { filter: hue-rotate(360deg) } }
|
||||
@keyframes hue { from { filter: hue-rotate(0deg) } to { filter: hue-rotate(360deg) } }
|
||||
|
|
|
|||
|
|
@ -1007,11 +1007,11 @@ svg.feather.feather-image,
|
|||
}
|
||||
|
||||
.splash-img {
|
||||
margin: 0;
|
||||
margin: 10% auto 0 auto;
|
||||
width: 512px;
|
||||
height: 512px;
|
||||
background-repeat: no-repeat;
|
||||
animation: color 8s infinite alternate, move 3s infinite alternate;
|
||||
animation: hue 5s infinite alternate;
|
||||
}
|
||||
|
||||
.loading {
|
||||
|
|
|
|||
|
|
@ -1946,7 +1946,7 @@ div:has(>#tab-gallery-folders) {
|
|||
}
|
||||
|
||||
.splash-img {
|
||||
margin: 0;
|
||||
margin: 10% auto 0 auto;
|
||||
width: 512px;
|
||||
height: 512px;
|
||||
background-repeat: no-repeat;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ const localeData = {
|
|||
observer: null, // MutationObserver for DOM changes
|
||||
};
|
||||
let localeTimeout = null;
|
||||
const isTouchDevice = 'ontouchstart' in window;
|
||||
|
||||
async function cycleLocale() {
|
||||
clearTimeout(localeTimeout);
|
||||
|
|
@ -64,66 +65,48 @@ async function tooltipCreate() {
|
|||
if (window.opts.tooltips === 'Browser default') localeData.type = 1;
|
||||
if (window.opts.tooltips === 'UI tooltips') localeData.type = 2;
|
||||
|
||||
// Setup event delegation for tooltips instead of individual listeners
|
||||
if (localeData.type === 2) {
|
||||
gradioApp().addEventListener('mouseover', tooltipShowDelegated); // eslint-disable-line no-use-before-define
|
||||
gradioApp().addEventListener('mouseout', tooltipHideDelegated); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
|
||||
// Initialize DOM observer for immediate hint application
|
||||
if (!localeData.observer) {
|
||||
initializeDOMObserver(); // eslint-disable-line no-use-before-define
|
||||
if (localeData.type === 2) { // setup event delegation for tooltips instead of individual listeners
|
||||
if (isTouchDevice) {
|
||||
gradioApp().addEventListener('touchstart', tooltipShowDelegated); // eslint-disable-line no-use-before-define
|
||||
gradioApp().addEventListener('touchend', tooltipHideDelegated); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
gradioApp().addEventListener('pointerover', tooltipShowDelegated); // eslint-disable-line no-use-before-define
|
||||
gradioApp().addEventListener('pointerout', tooltipHideDelegated); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
if (!localeData.observer) initializeDOMObserver(); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
|
||||
async function expandTooltip(element, longHint) {
|
||||
if (localeData.currentElement === element && localeData.hint.classList.contains('tooltip-show')) {
|
||||
// Hide the progress ring
|
||||
const ring = localeData.hint.querySelector('.tooltip-progress-ring');
|
||||
if (ring) {
|
||||
ring.style.opacity = '0';
|
||||
}
|
||||
|
||||
// Expand the container
|
||||
if (ring) ring.style.opacity = '0';
|
||||
localeData.hint.classList.add('tooltip-expanded');
|
||||
|
||||
// After container starts expanding, reveal the long content
|
||||
setTimeout(() => {
|
||||
const longContent = localeData.hint.querySelector('.long-content');
|
||||
if (longContent) {
|
||||
longContent.classList.add('show');
|
||||
}
|
||||
if (longContent) longContent.classList.add('show');
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
async function tooltipShowDelegated(e) {
|
||||
// Use event delegation to handle dynamically created elements
|
||||
if (e.target.dataset && e.target.dataset.hint) {
|
||||
tooltipShow(e); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
async function tooltipShowDelegated(e) { // use event delegation to handle dynamically created elements
|
||||
if (e.target.dataset && e.target.dataset.hint) tooltipShow(e); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
|
||||
async function tooltipHideDelegated(e) {
|
||||
if (e.target.dataset && e.target.dataset.hint) {
|
||||
tooltipHide(e); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
if (e.target.dataset && e.target.dataset.hint) tooltipHide(e); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
|
||||
async function tooltipShow(e) {
|
||||
// Clear any existing expansion timeout
|
||||
if (localeData.expandTimeout) {
|
||||
if (localeData.expandTimeout) { // clear any existing expansion timeout
|
||||
clearTimeout(localeData.expandTimeout);
|
||||
localeData.expandTimeout = null;
|
||||
}
|
||||
|
||||
// Remove expanded class and reset current element
|
||||
localeData.hint.classList.remove('tooltip-expanded');
|
||||
localeData.hint.classList.remove('tooltip-expanded'); // remove expanded class and reset current element
|
||||
localeData.currentElement = e.target;
|
||||
|
||||
if (e.target.dataset.hint) {
|
||||
// Create progress ring SVG
|
||||
const progressRing = `
|
||||
const progressRing = ` // create progress ring SVG
|
||||
<div class="tooltip-progress-ring">
|
||||
<svg viewBox="0 0 12 12">
|
||||
<circle class="ring-background" cx="6" cy="6" r="5"></circle>
|
||||
|
|
@ -131,8 +114,7 @@ async function tooltipShow(e) {
|
|||
</svg>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Set up the complete content structure from the start
|
||||
// set up the complete content structure from the start
|
||||
let content = `
|
||||
<div class="tooltip-header">
|
||||
<b>${e.target.textContent}</b>
|
||||
|
|
@ -141,21 +123,12 @@ async function tooltipShow(e) {
|
|||
<div class="separator"></div>
|
||||
${e.target.dataset.hint}
|
||||
`;
|
||||
|
||||
// Add long content if available, but keep it hidden
|
||||
if (e.target.dataset.longHint) {
|
||||
content += `<div class="long-content"><div class="separator"></div>${e.target.dataset.longHint}</div>`;
|
||||
}
|
||||
|
||||
// Add reload notice if needed
|
||||
if (e.target.dataset.reload) {
|
||||
if (e.target.dataset.longHint) content += `<div class="long-content"><div class="separator"></div>${e.target.dataset.longHint}</div>`; // add long content if available, but keep it hidden
|
||||
if (e.target.dataset.reload) { // add reload notice if needed
|
||||
const reloadType = e.target.dataset.reload;
|
||||
let reloadText = '';
|
||||
if (reloadType === 'model') {
|
||||
reloadText = 'Requires model reload';
|
||||
} else if (reloadType === 'server') {
|
||||
reloadText = 'Requires server restart';
|
||||
}
|
||||
if (reloadType === 'model') reloadText = 'Requires model reload';
|
||||
else if (reloadType === 'server') reloadText = 'Requires server restart';
|
||||
if (reloadText) {
|
||||
content += `
|
||||
<div class="tooltip-reload-notice">
|
||||
|
|
@ -169,40 +142,28 @@ async function tooltipShow(e) {
|
|||
localeData.hint.innerHTML = content;
|
||||
localeData.hint.classList.add('tooltip-show');
|
||||
|
||||
if (e.clientX > window.innerWidth / 2) {
|
||||
localeData.hint.classList.add('tooltip-left');
|
||||
} else {
|
||||
localeData.hint.classList.remove('tooltip-left');
|
||||
}
|
||||
if (e.clientX > window.innerWidth / 2) localeData.hint.classList.add('tooltip-left');
|
||||
else localeData.hint.classList.remove('tooltip-left');
|
||||
|
||||
// Set up expansion timer if long hint is available
|
||||
if (e.target.dataset.longHint) {
|
||||
// Start progress ring animation
|
||||
const ring = localeData.hint.querySelector('.tooltip-progress-ring');
|
||||
if (e.target.dataset.longHint) { // set up expansion timer if long hint is available
|
||||
const ring = localeData.hint.querySelector('.tooltip-progress-ring'); // start progress ring animation
|
||||
const ringProgress = localeData.hint.querySelector('.ring-progress');
|
||||
|
||||
if (ring && ringProgress) {
|
||||
// Show the ring and start animation
|
||||
setTimeout(() => {
|
||||
ring.classList.add('active');
|
||||
ringProgress.classList.add('animate');
|
||||
}, 100);
|
||||
}
|
||||
|
||||
localeData.expandTimeout = setTimeout(() => {
|
||||
expandTooltip(e.target, e.target.dataset.longHint);
|
||||
}, 3000);
|
||||
localeData.expandTimeout = setTimeout(() => expandTooltip(e.target, e.target.dataset.longHint), 3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function tooltipHide(e) {
|
||||
// Clear expansion timeout when hiding
|
||||
if (localeData.expandTimeout) {
|
||||
clearTimeout(localeData.expandTimeout);
|
||||
localeData.expandTimeout = null;
|
||||
}
|
||||
|
||||
localeData.hint.classList.remove('tooltip-show', 'tooltip-expanded');
|
||||
localeData.currentElement = null;
|
||||
}
|
||||
|
|
@ -368,6 +329,7 @@ async function setHints(analyze = false) {
|
|||
localeData.initial = false;
|
||||
const t1 = performance.now();
|
||||
// localeData.btn.style.backgroundColor = localeData.locale !== 'en' ? 'var(--primary-500)' : '';
|
||||
log('touchDevice', isTouchDevice);
|
||||
log('setHints', { type: localeData.type, locale: localeData.locale, elements: elements.length, localized, hints, data: localeData.data.length, override: overrideData.length, time: Math.round(t1 - t0) });
|
||||
// sortUIElements();
|
||||
if (analyze) {
|
||||
|
|
@ -388,31 +350,22 @@ async function applyHintToElement(el) {
|
|||
if (!localeData.data || localeData.data.length === 0) return;
|
||||
if (!el.textContent) return;
|
||||
|
||||
// Check if element matches our selector criteria
|
||||
// check if element matches our selector criteria
|
||||
const isValidElement = el.tagName === 'BUTTON'
|
||||
|| el.tagName === 'H2'
|
||||
|| (el.tagName === 'SPAN' && (el.parentElement?.tagName === 'LABEL' || el.parentElement?.classList.contains('label-wrap')));
|
||||
|
||||
if (!isValidElement) return;
|
||||
|
||||
// Find matching hint data
|
||||
let found;
|
||||
if (el.dataset.original) {
|
||||
found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.dataset.original.toLowerCase().trim());
|
||||
} else {
|
||||
found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.textContent.toLowerCase().trim());
|
||||
}
|
||||
let found; // find matching hint data
|
||||
if (el.dataset.original) found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.dataset.original.toLowerCase().trim());
|
||||
else found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.textContent.toLowerCase().trim());
|
||||
|
||||
// Apply localization if found
|
||||
if (found?.localized?.length > 0) {
|
||||
if (found?.localized?.length > 0) { // apply localization if found
|
||||
if (!el.dataset.original) el.dataset.original = el.textContent;
|
||||
replaceTextContent(el, found.localized);
|
||||
}
|
||||
|
||||
// Apply hint if found
|
||||
if (found?.hint?.length > 0) {
|
||||
setHint(el, found);
|
||||
}
|
||||
if (found?.hint?.length > 0) setHint(el, found); // apply hint if found
|
||||
}
|
||||
|
||||
// Initialize MutationObserver for immediate hint application
|
||||
|
|
|
|||
|
|
@ -8,18 +8,18 @@ async function initStartup() {
|
|||
if (window.setupLogger) await setupLogger();
|
||||
|
||||
// all items here are non-blocking async calls
|
||||
initModels();
|
||||
getUIDefaults();
|
||||
initPromptChecker();
|
||||
initContextMenu();
|
||||
initDragDrop();
|
||||
initAccordions();
|
||||
initSettings();
|
||||
initImageViewer();
|
||||
initGallery();
|
||||
initiGenerationParams();
|
||||
initChangelog();
|
||||
setupControlUI();
|
||||
await initModels();
|
||||
await getUIDefaults();
|
||||
await initPromptChecker();
|
||||
await initContextMenu();
|
||||
await initDragDrop();
|
||||
await initAccordions();
|
||||
await initSettings();
|
||||
await initImageViewer();
|
||||
await initGallery();
|
||||
await initiGenerationParams();
|
||||
await initChangelog();
|
||||
await setupControlUI();
|
||||
|
||||
// reconnect server session
|
||||
await reconnectUI();
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ pandas==2.3.1
|
|||
numba==0.61.2
|
||||
protobuf==4.25.3
|
||||
pytorch_lightning==2.5.4
|
||||
tokenizers==0.22.0
|
||||
urllib3==1.26.19
|
||||
Pillow==10.4.0
|
||||
timm==1.0.16
|
||||
|
|
|
|||
Loading…
Reference in New Issue