Decouple sort button icon from sorting logic

pull/4687/head
awsr 2026-03-15 21:59:51 -07:00
parent b2f95b91bf
commit bbdaaae682
No known key found for this signature in database
2 changed files with 42 additions and 62 deletions

View File

@ -5,8 +5,6 @@ let currentImage = null;
let currentGalleryFolder = null;
let pruneImagesTimer;
let outstanding = 0;
let lastSort = 0;
let lastSortName = 'None';
let gallerySelection = { files: [], index: -1 };
let maintenanceController = new AbortController();
const folderStylesheet = new CSSStyleSheet();
@ -25,6 +23,20 @@ const el = {
const SUPPORTED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'webp', 'tiff', 'jp2', 'jxl', 'gif', 'mp4', 'mkv', 'avi', 'mjpeg', 'mpg', 'avr'];
const gallerySorter = {
nameA: { name: 'Name Ascending', func: (a, b) => a.name.localeCompare(b.name) },
nameD: { name: 'Name Descending', func: (b, a) => a.name.localeCompare(b.name) },
sizeA: { name: 'Size Ascending', func: (a, b) => a.size - b.size },
sizeD: { name: 'Size Descending', func: (b, a) => a.size - b.size },
resA: { name: 'Resolution Ascending', func: (a, b) => a.width * a.height - b.width * b.height },
resD: { name: 'Resolution Descending', func: (b, a) => a.width * a.height - b.width * b.height },
modA: { name: 'Modified Ascending', func: (a, b) => a.mtime - b.mtime },
modD: { name: 'Modified Descending', func: (b, a) => a.mtime - b.mtime },
none: { name: 'None', func: null },
};
let sortMode = gallerySorter.none;
async function getHash(str) {
let hex = '';
const strBuf = new TextEncoder().encode(str);
@ -683,7 +695,7 @@ const gallerySendImage = (_images) => [currentImage]; // invoked by gradio butto
*/
function updateStatusWithSort(...messages) {
if (!el.status) return;
messages.unshift(['Sort', lastSortName]);
messages.unshift(['Sort', sortMode.name]);
const fragment = document.createDocumentFragment();
for (let i = 0; i < messages.length; i++) {
const div = document.createElement('div');
@ -858,11 +870,14 @@ const findDuplicates = (arr, key) => {
});
};
async function gallerySort(btn) {
async function gallerySort(key) {
if (!Object.hasOwn(gallerySorter, key)) {
error(`Gallery: "${key}" is not a valid gallery sorting key`);
return;
}
const t0 = performance.now();
const arr = Array.from(el.files.children).filter((node) => node.name); // filter out separators
if (arr.length === 0) return; // no files to sort
if (btn) lastSort = btn.charCodeAt(0);
const fragment = document.createDocumentFragment();
// Helper to get directory path from a file node
@ -885,60 +900,17 @@ async function gallerySort(btn) {
folderGroups.get(dir).push(file);
}
// Sort function based on current sort mode
let sortFn;
switch (lastSort) {
case 61789: // name asc
lastSortName = 'Name Ascending';
sortFn = (a, b) => a.name.localeCompare(b.name);
break;
case 61790: // name dsc
lastSortName = 'Name Descending';
sortFn = (a, b) => b.name.localeCompare(a.name);
break;
case 61792: // size asc
lastSortName = 'Size Ascending';
sortFn = (a, b) => a.size - b.size;
break;
case 61793: // size dsc
lastSortName = 'Size Descending';
sortFn = (a, b) => b.size - a.size;
break;
case 61794: // resolution asc
lastSortName = 'Resolution Ascending';
sortFn = (a, b) => a.width * a.height - b.width * b.height;
break;
case 61795: // resolution dsc
lastSortName = 'Resolution Descending';
sortFn = (a, b) => b.width * b.height - a.width * a.height;
break;
case 61662:
lastSortName = 'Modified Ascending';
sortFn = (a, b) => a.mtime - b.mtime;
break;
case 61661:
lastSortName = 'Modified Descending';
sortFn = (a, b) => b.mtime - a.mtime;
break;
default:
lastSortName = 'None';
sortFn = null;
break;
}
sortMode = gallerySorter[key];
// Sort root files
if (sortFn) {
rootFiles.sort(sortFn);
}
rootFiles.sort(sortMode.func);
rootFiles.forEach((node) => fragment.appendChild(node));
// Sort folder names alphabetically, then sort files within each folder
const sortedFolderNames = Array.from(folderGroups.keys()).sort((a, b) => a.localeCompare(b));
for (const folderName of sortedFolderNames) {
const files = folderGroups.get(folderName);
if (sortFn) {
files.sort(sortFn);
}
files.sort(sortMode.func);
files.forEach((node) => fragment.appendChild(node));
}
@ -963,7 +935,7 @@ async function gallerySort(btn) {
}
const t1 = performance.now();
log(`gallerySort: char=${lastSort} len=${arr.length} time=${Math.floor(t1 - t0)} sort=${lastSortName}`);
log(`gallerySort: sort=${sortMode.name} len=${arr.length} time=${Math.floor(t1 - t0)}`);
updateStatusWithSort(['Images', arr.length.toLocaleString()], `${iconStopwatch} ${Math.floor(t1 - t0).toLocaleString()}ms`);
refreshGallerySelection();
}

View File

@ -59,19 +59,17 @@ def create_ui():
with gr.Blocks() as tab:
with gr.Row(elem_id='tab-gallery-sort-buttons'):
sort_buttons = []
sort_buttons.append(ToolButton(value=ui_symbols.sort_alpha_asc, elem_classes=['gallery-sort']))
sort_buttons.append(ToolButton(value=ui_symbols.sort_alpha_dsc, elem_classes=['gallery-sort']))
sort_buttons.append(ToolButton(value=ui_symbols.sort_size_asc, elem_classes=['gallery-sort']))
sort_buttons.append(ToolButton(value=ui_symbols.sort_size_dsc, elem_classes=['gallery-sort']))
sort_buttons.append(ToolButton(value=ui_symbols.sort_num_asc, elem_classes=['gallery-sort']))
sort_buttons.append(ToolButton(value=ui_symbols.sort_num_dsc, elem_classes=['gallery-sort']))
sort_buttons.append(ToolButton(value=ui_symbols.sort_time_asc, elem_classes=['gallery-sort']))
sort_buttons.append(ToolButton(value=ui_symbols.sort_time_dsc, elem_classes=['gallery-sort']))
sort_buttons.append(sort_nameA := ToolButton(value=ui_symbols.sort_alpha_asc, elem_classes=['gallery-sort']))
sort_buttons.append(sort_nameD := ToolButton(value=ui_symbols.sort_alpha_dsc, elem_classes=['gallery-sort']))
sort_buttons.append(sort_sizeA := ToolButton(value=ui_symbols.sort_size_asc, elem_classes=['gallery-sort']))
sort_buttons.append(sort_sizeD := ToolButton(value=ui_symbols.sort_size_dsc, elem_classes=['gallery-sort']))
sort_buttons.append(sort_resA := ToolButton(value=ui_symbols.sort_num_asc, elem_classes=['gallery-sort']))
sort_buttons.append(sort_resD := ToolButton(value=ui_symbols.sort_num_dsc, elem_classes=['gallery-sort']))
sort_buttons.append(sort_modA := ToolButton(value=ui_symbols.sort_time_asc, elem_classes=['gallery-sort']))
sort_buttons.append(sort_modD := ToolButton(value=ui_symbols.sort_time_dsc, elem_classes=['gallery-sort']))
gr.Textbox(show_label=False, placeholder='Search', elem_id='tab-gallery-search')
gr.HTML('', elem_id='tab-gallery-status')
gr.HTML('', elem_id='tab-gallery-progress')
for btn in sort_buttons:
btn.click(fn=None, _js='gallerySort', inputs=[btn], outputs=[])
with gr.Row():
with gr.Column():
gr.HTML('', elem_id='tab-gallery-folders')
@ -82,4 +80,14 @@ def create_ui():
gallery_video = gr.Video(None, elem_id='tab-gallery-video', show_label=False, visible=False)
gallery_images, gen_info, html_info, _html_info_formatted, html_log = ui_common.create_output_panel("gallery")
btn_gallery_image.click(fn=read_media, _js='gallerySendImage', inputs=[html_info], outputs=[gallery_images, gallery_video, html_info, gen_info, html_log])
sort_nameA.click(fn=None, _js='() => gallerySort("nameA")')
sort_nameD.click(fn=None, _js='() => gallerySort("nameD")')
sort_sizeA.click(fn=None, _js='() => gallerySort("sizeA")')
sort_sizeD.click(fn=None, _js='() => gallerySort("sizeD")')
sort_resA.click(fn=None, _js='() => gallerySort("resA")')
sort_resD.click(fn=None, _js='() => gallerySort("resD")')
sort_modA.click(fn=None, _js='() => gallerySort("modA")')
sort_modD.click(fn=None, _js='() => gallerySort("modD")')
return [(tab, 'Gallery', 'tab-gallery')]