diff --git a/src/UI/UIDesktop.js b/src/UI/UIDesktop.js index 642f0b45..3576fa80 100644 --- a/src/UI/UIDesktop.js +++ b/src/UI/UIDesktop.js @@ -625,8 +625,28 @@ async function UIDesktop(options){ { html: i18n('sort_by'), items: [ + { + html: i18n('auto_arrange'), + icon: is_auto_arrange_enabled ? '✓' : '', + onClick: async function(){ + is_auto_arrange_enabled = !is_auto_arrange_enabled; + store_auto_arrange_preference(is_auto_arrange_enabled); + if(is_auto_arrange_enabled){ + sort_items(el_desktop, $(el_desktop).attr('data-sort_by'), $(el_desktop).attr('data-sort_order')); + set_sort_by(options.desktop_fsentry.uid, $(el_desktop).attr('data-sort_by'), $(el_desktop).attr('data-sort_order')) + clear_desktop_item_positions(el_desktop); + }else{ + set_desktop_item_positions(el_desktop) + } + } + }, + // ------------------------------------------- + // - + // ------------------------------------------- + '-', { html: i18n('name'), + disabled: !is_auto_arrange_enabled, icon: $(el_desktop).attr('data-sort_by') === 'name' ? '✓' : '', onClick: async function(){ sort_items(el_desktop, 'name', $(el_desktop).attr('data-sort_order')); @@ -635,6 +655,7 @@ async function UIDesktop(options){ }, { html: i18n('date_modified'), + disabled: !is_auto_arrange_enabled, icon: $(el_desktop).attr('data-sort_by') === 'modified' ? '✓' : '', onClick: async function(){ sort_items(el_desktop, 'modified', $(el_desktop).attr('data-sort_order')); @@ -643,6 +664,7 @@ async function UIDesktop(options){ }, { html: i18n('type'), + disabled: !is_auto_arrange_enabled, icon: $(el_desktop).attr('data-sort_by') === 'type' ? '✓' : '', onClick: async function(){ sort_items(el_desktop, 'type', $(el_desktop).attr('data-sort_order')); @@ -651,6 +673,7 @@ async function UIDesktop(options){ }, { html: i18n('size'), + disabled: !is_auto_arrange_enabled, icon: $(el_desktop).attr('data-sort_by') === 'size' ? '✓' : '', onClick: async function(){ sort_items(el_desktop, 'size', $(el_desktop).attr('data-sort_order')); @@ -663,6 +686,7 @@ async function UIDesktop(options){ '-', { html: i18n('ascending'), + disabled: !is_auto_arrange_enabled, icon: $(el_desktop).attr('data-sort_order') === 'asc' ? '✓' : '', onClick: async function(){ const sort_by = $(el_desktop).attr('data-sort_by') @@ -672,6 +696,7 @@ async function UIDesktop(options){ }, { html: i18n('descending'), + disabled: !is_auto_arrange_enabled, icon: $(el_desktop).attr('data-sort_order') === 'desc' ? '✓' : '', onClick: async function(){ const sort_by = $(el_desktop).attr('data-sort_by') diff --git a/src/UI/UIItem.js b/src/UI/UIItem.js index 183fbd5b..102a0205 100644 --- a/src/UI/UIItem.js +++ b/src/UI/UIItem.js @@ -187,6 +187,13 @@ function UIItem(options){ update_explorer_footer_item_count(el_window); } + // position + if(!is_auto_arrange_enabled && options.position && $(el_item).closest('.item-container').attr('data-path') === window.desktop_path){ + el_item.style.position = 'absolute'; + el_item.style.left = options.position.left + 'px'; + el_item.style.top = options.position.top + 'px'; + } + // -------------------------------------------------------- // Dragster // allow dragging of local files on this window, if it's is_dir @@ -335,6 +342,19 @@ function UIItem(options){ } }, stop: function(event, ui){ + // Allow rearranging only if item is on desktop, not trash container, auto arrange is disabled and item is not dropped into another item + if($(el_item).closest('.item-container').attr('data-path') === window.desktop_path && + !is_auto_arrange_enabled && $(el_item).attr('data-path') !== trash_path && !ui.helper.data('dropped') && + // Item must be dropped on the Desktop + mouseover_window === undefined){ + + el_item.style.position = 'absolute'; + el_item.style.left = ui.position.left + 'px'; + el_item.style.top = ui.position.top + 'px'; + $('.ui-draggable-dragging').remove(); + desktop_item_positions[$(el_item).attr('data-uid')] = ui.position; + save_desktop_item_positions() + } $('.item-selected-clone').remove(); $('.draggable-count-badge').remove(); // re-enable all droppable UIItems that are not a dir @@ -363,6 +383,9 @@ function UIItem(options){ if(event.ctrlKey && path.dirname($(ui.draggable).attr('data-path')) === window.trash_path) return; + // Adding a flag to know whether item is rearraged or dropped + ui.helper.data('dropped', true); + const items_to_move = [] // First item @@ -437,6 +460,10 @@ function UIItem(options){ } // Otherwise, move items else if(options.is_dir){ + if($(el_item).closest('.item-container').attr('data-path') === window.desktop_path){ + delete desktop_item_positions[$(el_item).attr('data-uid')]; + save_desktop_item_positions() + } move_items(items_to_move, $(el_item).attr('data-shortcut_to_path') !== '' ? $(el_item).attr('data-shortcut_to_path') : $(el_item).attr('data-path')); } } diff --git a/src/globals.js b/src/globals.js index fd799541..bade099c 100644 --- a/src/globals.js +++ b/src/globals.js @@ -169,3 +169,7 @@ window.feature_flags = { // if true, the user will be able to zip and download directories download_directory: true, } + +window.is_auto_arrange_enabled = true; +window.desktop_item_positions = {}; +window.reset_item_positions = true; // The variable decides if the item positions should be reset when the user enabled auto arrange \ No newline at end of file diff --git a/src/helpers.js b/src/helpers.js index 03128b9e..a318fb73 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -1295,6 +1295,7 @@ window.refresh_item_container = function(el_item_container, options){ if(item_path !== trash_path && item_path !== appdata_path){ // if this is trash, get original name from item metadata fsentry.name = (metadata && metadata.original_name !== undefined) ? metadata.original_name : fsentry.name; + const position = desktop_item_positions[fsentry.uid] ?? undefined; UIItem({ appendTo: el_item_container, uid: fsentry.uid, @@ -1317,6 +1318,7 @@ window.refresh_item_container = function(el_item_container, options){ suggested_apps: fsentry.suggested_apps, disabled: is_disabled, visible: visible, + position: position, }); } } @@ -3610,4 +3612,49 @@ window.get_html_element_from_options = async function(options){ h += ``; return h; +} + +window.store_auto_arrange_preference = (preference)=>{ + puter.kv.set('user_preferences.auto_arrange_desktop', preference); + localStorage.setItem('auto_arrange', preference); +} + +window.get_auto_arrange_data = async()=>{ + const preferenceValue = await puter.kv.get('user_preferences.auto_arrange_desktop'); + is_auto_arrange_enabled = preferenceValue === null ? true : preferenceValue; + const positions = await puter.kv.get('desktop_item_positions') + desktop_item_positions = (!positions || typeof positions !== 'object' || Array.isArray(positions)) ? {} : positions; +} + +window.clear_desktop_item_positions = async(el_desktop)=>{ + $(el_desktop).find('.item').each(function(){ + const el_item = $(this)[0]; + $(el_item).css('position', ''); + $(el_item).css('left', ''); + $(el_item).css('top', ''); + }); + if(reset_item_positions){ + delete_desktop_item_positions() + } +} + +window.set_desktop_item_positions = async(el_desktop)=>{ + $(el_desktop).find('.item').each(async function(){ + const position = desktop_item_positions[$(this).attr('data-uid')] + const el_item = $(this)[0]; + if(position){ + $(el_item).css('position', 'absolute'); + $(el_item).css('left', position.left + 'px'); + $(el_item).css('top', position.top + 'px'); + } + }); +} + +window.save_desktop_item_positions = ()=>{ + puter.kv.set('desktop_item_positions', desktop_item_positions); +} + +window.delete_desktop_item_positions = ()=>{ + desktop_item_positions = {} + puter.kv.del('desktop_item_positions'); } \ No newline at end of file diff --git a/src/i18n/i18n.js b/src/i18n/i18n.js index d9967ced..c3cea967 100644 --- a/src/i18n/i18n.js +++ b/src/i18n/i18n.js @@ -49,4 +49,4 @@ window.i18n = function (key, replacements = [], encode_html = true) { return str; } -export default {}; +export default {}; \ No newline at end of file diff --git a/src/initgui.js b/src/initgui.js index e66ad5b5..b01bd6f1 100644 --- a/src/initgui.js +++ b/src/initgui.js @@ -329,6 +329,7 @@ window.initgui = async function(){ // Load desktop, only if we're not embedded in a popup // ------------------------------------------------------------------------------------- if(!window.embedded_in_popup){ + await get_auto_arrange_data() puter.fs.stat(desktop_path, async function(desktop_fsentry){ UIDesktop({desktop_fsentry: desktop_fsentry}); }) @@ -680,6 +681,7 @@ window.initgui = async function(){ // Load desktop, if not embedded in a popup // ------------------------------------------------------------------------------------- if(!window.embedded_in_popup){ + await get_auto_arrange_data(); puter.fs.stat(desktop_path, function (desktop_fsentry) { UIDesktop({ desktop_fsentry: desktop_fsentry }); })