From 03b28552033129083543784e09051d3dc5b0fc53 Mon Sep 17 00:00:00 2001 From: flatsiedatsie Date: Tue, 23 Jan 2024 20:04:51 +0100 Subject: [PATCH] Add files via upload --- css/extension.css | 7 +- images/position_edit-old.svg | 13 + js/extension.js | 460 +++++++++++++++++++++++------------ manifest.json | 6 +- pkg/floorplanner.py | 265 +++++++++++++++----- requirements.txt | 2 +- views/content.html | 17 +- 7 files changed, 551 insertions(+), 219 deletions(-) create mode 100644 images/position_edit-old.svg diff --git a/css/extension.css b/css/extension.css index b2d22e0..5ede6c2 100644 --- a/css/extension.css +++ b/css/extension.css @@ -13,7 +13,7 @@ #extension-floorplanner-border-tab-menu, #extension-floorplanner-border-root #extension-floorplanner-border-menu{ - padding-left:8.6rem; + padding-left:8.6rem; } @@ -1213,6 +1213,9 @@ body:not(.developer) .extension-floorplanner-show-if-developer{ pointer-events:none; } +.extension-floorplanner-scale-linked #extension-floorplanner-scale-link-toggle-button{ + background-color:#08d; +} #extension-floorplanner-content .extension-floorplanner-vertical-flex-between{ display:flex; @@ -1915,6 +1918,8 @@ body.touch #extension-floorplanner-content .extension-floorplanner-floorplan-ite #extension-floorplanner-content #extension-floorplanner-settings{ display:none; width:200px; + font-size:1.3rem; + line-height: 1.7rem; } diff --git a/images/position_edit-old.svg b/images/position_edit-old.svg new file mode 100644 index 0000000..75373fd --- /dev/null +++ b/images/position_edit-old.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/js/extension.js b/js/extension.js index 04472c7..74cf6ea 100644 --- a/js/extension.js +++ b/js/extension.js @@ -30,100 +30,16 @@ this.content = ''; this.revealed = false; + + + /* + else { + localStorage.setItem('extension-floorplanner-local-settings-only', JSON.stringify(false)); + } + */ - - - // Check if screensaver should be active - window.API.postJson( - `/extensions/${this.id}/api/ajax`, { - 'action': 'init' - } - - ).then((body) => { - - - if (typeof body.debug != 'undefined') { - this.debug = body.debug; - - } - if (this.debug) { - console.log("floorplanner init response: ", body); - } - /* - // Search URL - if(typeof body.search_url != 'undefined'){ - window.extension_floorplanner_search_url = body.search_url; - localStorage.setItem("extension_floorplanner_search_url",body.search_url); - } - - - // save history - if(typeof body.history_length != 'undefined'){ - window.extension_floorplanner_history_length = parseInt(body.history_length); - if(body.history_length){ - window.extension_floorplanner_recent_urls = localStorage.getItem("extension_floorplanner_recent_urls"); - - if(window.extension_floorplanner_recent_urls == null){ - window.extension_floorplanner_recent_urls = []; - } - else{ - window.extension_floorplanner_recent_urls = JSON.parse(window.extension_floorplanner_recent_urls); - } - if(this.debug){ - console.log("floorplanner: window.extension_floorplanner_recent_urls: ",typeof window.extension_floorplanner_recent_urls, window.extension_floorplanner_recent_urls); - } - } - else{ - window.extension_floorplanner_recent_urls = []; - localStorage.setItem("extension_floorplanner_recent_urls","[]"); - } - } - - - // restore tabs - if(typeof body.restore_tabs != 'undefined'){ - if(body.restore_tabs){ - window.extension_floorplanner_restore_tabs = true; - window.extension_floorplanner_restoring_tabs = true; - window.extension_floorplanner_open_tabs = localStorage.getItem("extension_floorplanner_open_tabs"); - if(window.extension_floorplanner_open_tabs == null){ - window.extension_floorplanner_open_tabs = []; - } - else{ - window.extension_floorplanner_open_tabs = JSON.parse(window.extension_floorplanner_open_tabs); - } - } - else{ - window.extension_floorplanner_open_tabs = []; - localStorage.setItem("extension_floorplanner_open_tabs","[]"); - } - } - if(this.debug){ - console.log("floorplanner: window.extension_floorplanner_restore_tabs: ", window.extension_floorplanner_restore_tabs); - } - - // fullscreen delay - if(typeof body.fullscreen_delay != 'undefined'){ - window.extension_floorplanner_fullscreen_delay = parseInt(body.fullscreen_delay); - this.fullscreen_delay = parseInt(body.fullscreen_delay) * 1000; - } - - // slideshow - if(typeof body.slideshow != 'undefined'){ - window.extension_floorplanner_slideshow = body.slideshow; - this.slideshow = body.slideshow; - } - - if(this.debug){ - console.log("floorplanner: fullscreen_delay: ", this.fullscreen_delay); - } - */ - - - }).catch((e) => { - console.log("Floorplanner: error in ealy init function: ", e); - }); + @@ -190,11 +106,33 @@ floorplan_view_el.appendChild(fp_container_el); //generate_floorplans_list(); - console.log("floorplanner: document.location.pathname ", document.location.pathname); - this.revealed = true; - setTimeout(() => { - this.reveal_floorplanner(); - },1); + //console.log("floorplanner: document.location.pathname ", document.location.pathname); + + + window.API.postJson( + `/extensions/floorplanner/api/ajax`, { + 'action': 'init' + } + + ).then((body) => { + + if (typeof body.debug != 'undefined') { + this.debug = body.debug; + + } + if (this.debug) { + console.log("floorplanner init response: ", body); + } + + //this.revealed = true; + + this.reveal_floorplanner(body); + + }).catch((e) => { + console.log("Floorplanner: error in early init function: ", e); + }); + + } } } @@ -231,7 +169,7 @@ - delete_file(filename) { + save_file(filename) { //console.log("Deleting file:" + filename); //const pre = document.getElementById('extension-floorplanner-response-data'); @@ -239,7 +177,7 @@ const photo_list = document.getElementById('extension-floorplanner-photo-list'); window.API.postJson( - `/extensions/${this.id}/api/delete`, { + `/extensions/floorplanner/api/delete`, { 'action': 'delete', 'filename': filename } @@ -256,25 +194,60 @@ } - reveal_floorplanner() { + reveal_floorplanner(body = null) { console.log("floorplanner: in reveal_floorplanner"); - this.revealed = true; + if(typeof body == null){ + console.error("\n\nERROR:\nreveal_floorplanner: no/invalid data from server? body: ", body); + // TODO: show an error to the user that is non-blocking + return + } + + this.revealed = true; // Avoid starting floorplanner more than once - var currently_editing = true; - var currently_editing_an_object = false; - var currently_cloning_an_object = false; - let settings = { - 'auto_save': true, - 'multi_line': true, - 'dark_mode': null, - 'thing_icons_size':3 + var local_settings_only = false; + var currently_editing_an_object = false; // used by UI to remember state + var currently_cloning_an_object = false; // used by UI to remember state + var skip_first_save_to_floorplans = true; // quick hacky fix which allows users to view a floorplan without immediately losing their edit history. + + // Currently editing? If true, immediately return to the editor + var currently_editing = true; + if (localStorage.getItem('extension-floorplanner-currently-editing') != null) { + currently_editing = JSON.parse(localStorage.getItem('extension-floorplanner-currently-editing')); + } else { + localStorage.setItem('extension-floorplanner-currently-editing', JSON.stringify(true)); } - // settings.thing_icons_size can be between 1 and 5. + + let current_filename = JSON.parse(localStorage.getItem('extension-floorplanner-current-filename')); + if (current_filename != null) { + document.getElementById('extension-floorplanner-current-filename').textContent = current_filename; + } + + + // FLOORPLANS + let floorplans = {}; + + if(typeof body.floorplans != 'undefined'){ + floorplans = body.floorplans; + } + else if (localStorage.getItem('extension-floorplanner-floorplans') != null) { + console.warn("floorplanner: falling back to floorplans data in browser local storage"); + floorplans = JSON.parse(localStorage.getItem('extension-floorplanner-floorplans')); + } + else{ + console.warn("NO FLOORPLANS DATA AVAILABLE. body: ", body); + } + console.log("initial floorplans: ", floorplans); + + + // VISIBLE THINGS var visible_things = {}; - if (localStorage.getItem('extension-floorplanner-visible-things') != null) { - console.log("floorplanner: spotted visible_things info in browser local storage"); + if(typeof body.visible_things != 'undefined'){ + visible_things = body.visible_things; + } + else if (localStorage.getItem('extension-floorplanner-visible-things') != null) { + console.warn("floorplanner: falling back to visible_things data in browser local storage"); try{ visible_things = JSON.parse(localStorage.getItem('extension-floorplanner-visible-things')); } @@ -283,31 +256,43 @@ visible_things = {}; } } + console.log("initial visible_things: ", visible_things); + // Set initial CSS that hides things from specific floorplans + update_thing_styles(); - var skip_first_save_to_floorplans = true; // quick hacky fix which allows users to view a floorplan without immediately losing their edit history. - if (localStorage.getItem('extension-floorplanner-settings') != null) { - settings = JSON.parse(localStorage.getItem('extension-floorplanner-settings')); - load_floorplanner_settings(); + + // SETTINGS + + let settings = { + 'auto_save': true, + 'multi_line': true, + 'dark_mode': null, + 'thing_icons_size':3 } + // settings.thing_icons_size can be between 1 and 5. + + if (localStorage.getItem('extension-floorplanner-local-settings-only') != null) { + local_settings_only = JSON.parse(localStorage.getItem('extension-floorplanner-local-settings-only')); + } + + if(local_settings_only == false && typeof body.settings != 'undefined' && body.settings != null){ + settings = body.settings; + } + else if (localStorage.getItem('extension-floorplanner-settings') != null) { + settings = JSON.parse(localStorage.getItem('extension-floorplanner-settings')); + } + load_floorplanner_settings(); - if (localStorage.getItem('extension-floorplanner-currently-editing') != null) { - currently_editing = JSON.parse(localStorage.getItem('extension-floorplanner-currently-editing')); - } else { - localStorage.setItem('extension-floorplanner-currently-editing', JSON.stringify(true)); - } + //console.log("currently_editing: ", typeof currently_editing, currently_editing); - let current_filename = JSON.parse(localStorage.getItem('extension-floorplanner-current-filename')); - if (current_filename != null) { - document.getElementById('extension-floorplanner-current-filename').textContent = current_filename; - } + //console.log("current_filename: ", current_filename); - // Set initial CSS that hides things from specific floorplans - update_thing_styles(); + let tactile = false; @@ -347,12 +332,7 @@ } - let floorplans = JSON.parse(localStorage.getItem('extension-floorplanner-floorplans')); - if (floorplans == null) { - floorplans = {}; - } else { - //console.log("FLOORPLANS FROM LOCAL STORAGE: ", floorplans); - } + let bounding_padding = -10; @@ -5495,7 +5475,7 @@ // ************************************************************************** function initHistory(boot = false) { - //console.log("in initHistory. boot,current_filename: ", boot, current_filename); + console.log("in initHistory. boot,current_filename: ", boot, current_filename); //clear_floorplan(); @@ -5507,10 +5487,12 @@ clear_floorplan(true,true); current_filename = new_floorplan_name; localStorage.setItem('extension-floorplanner-current-filename', JSON.stringify(new_floorplan_name)); - document.getElementById('extension-floorplanner-newFileModal').style.display = 'none'; + newFileModal.style.display = 'none'; + document.getElementById('extension-floorplanner-modal-new-floorplan-name-input').style.border = 'none'; } else if (boot !== "recovery") { - alert("Please provide a valid floorplan name"); + //alert("Please provide a valid floorplan name"); + document.getElementById('extension-floorplanner-modal-new-floorplan-name-input').style.border = '2px dashed red'; return } @@ -9152,7 +9134,7 @@ } else { document.getElementById('extension-floorplanner-plan-exists-warning').style.display = 'none'; } - document.querySelector('#extension-floorplanner-newFileModal').style.display = 'block'; + newFileModal.style.display = 'block'; } @@ -9265,15 +9247,13 @@ localStorage.removeItem('extension-floorplanner-current-filename'); clear_floorplan(true); document.getElementById('extension-floorplanner-current-filename').textContent = ''; - generate_floorplans_list(); + //generate_floorplans_list(); } - if (floorplans.length == 0) { - //console.log("all floorplans have been deleted"); - } else { - console.warn('cannot delete, no current_filename'); - //floorplans[floorplans.length-1]; - } + if (floorplans.length === 0) { + console.log("all floorplans have been deleted"); + new_floorplan(); + } generate_floorplans_list(true); } } @@ -9328,7 +9308,7 @@ localStorage.setItem('extension-floorplanner-current-filename', JSON.stringify(current_filename)); generate_floorplans_list(); - + save_floorplans_to_controller(); } /* @@ -9345,6 +9325,135 @@ if (HISTORY.index > 1) document.querySelector('#extension-floorplanner-undo').classList.remove('extension-floorplanner-disabled'); */ } + + + const get_init = () => { + + window.API.postJson( + `/extensions/floorplanner/api/ajax`, { + 'action': 'init' + } + + ).then((body) => { + //console.log(body); + parse_server_response(body); + + }).catch((e) => { + console.log("Floorplanner: caught error in get_init response: ", e); + //alert("Could not get floorplanner data - connection error?"); + }); + } + + const save_floorplans_to_controller = () => { + console.log("in save_floorplans_to_controller. this.debug: ", this.debug); + + window.API.postJson( + `/extensions/floorplanner/api/ajax`, { + 'action': 'save', + 'floorplans':floorplans + } + + ).then((body) => { + if(this.debug){ + console.log("Floorplanner: debug: save floorplans response: ", body); + } + //console.log(body); + //this.parse_server_response(body); + + }).catch((e) => { + console.log("Floorplanner: caught error in save floorplans response: ", e); + //alert("Could not get floorplanner data - connection error?"); + }); + } + + + const save_visible_things_to_controller = () => { + + window.API.postJson( + `/extensions/floorplanner/api/ajax`, { + 'action': 'save', + 'visible_things':visible_things + } + + ).then((body) => { + if(this.debug){ + console.log("Floorplanner: debug: save visible_things response: ", body); + } + //console.log(body); + //this.parse_server_response(body); + + }).catch((e) => { + console.log("Floorplanner: caught error in save visible_things response: ", e); + //alert("Could not get floorplanner data - connection error?"); + }); + } + + const save_settings_to_controller = () => { + if(local_settings_only == false){ + window.API.postJson( + `/extensions/floorplanner/api/ajax`, { + 'action': 'save', + 'settings':settings + } + + ).then((body) => { + if(this.debug){ + console.log("Floorplanner: debug: save visible_things response: ", body); + } + //console.log(body); + //this.parse_server_response(body); + + }).catch((e) => { + console.log("Floorplanner: caught error in save visible_things response: ", e); + //alert("Could not get floorplanner data - connection error?"); + }); + } + + } + + + // A general api response parser + const parse_server_response = (body) => { + try{ + + if(typeof body.debug != 'undefined'){ + this.debug = body.debug; + } + + if (this.debug) { + console.log("floorplanner: parsing response: ", body); + } + + // printer + /* + if (typeof body.peripage_printer_available != 'undefined' && typeof body.cups_printer_available != 'undefined') { + this.peripage_printer_available = body.peripage_printer_available; + this.cups_printer_available = body.cups_printer_available; + } + */ + + // visible things + if (typeof body.visible_things != 'undefined') { + visible_things = body.peripage_printer_available; + } + + // floorplans + if (typeof body.floorplans != 'undefined') { + floorplans = body.floorplans; + } + + // settings + if (typeof body.settings != 'undefined' && local_settings_only === false) { + settings = body.settings; + } + + } + catch(e){ + console.error("floorplanner: caught error parsing server response: ", e); + } + } + + function save_floorplan_as() { @@ -9670,6 +9779,7 @@ icon_index++; } localStorage.setItem('extension-floorplanner-floorplans', JSON.stringify(floorplans)); + save_floorplans_to_controller(); } @@ -9841,6 +9951,11 @@ panel_el.style.display = 'block'; } + document.getElementById('extension-floorplanner-local-settings-only-checkbox').addEventListener('change', () => { + local_settings_only = document.getElementById('extension-floorplanner-auto-save-checkbox').checked; + save_floorplanner_settings(); + }, true); + document.getElementById('extension-floorplanner-auto-save-checkbox').addEventListener('change', () => { settings.auto_save = document.getElementById('extension-floorplanner-auto-save-checkbox').checked; save_floorplanner_settings(); @@ -9864,21 +9979,27 @@ function load_floorplanner_settings() { - + if(typeof settings == 'undefined' || settings == null){ + console.error("load_floorplanner_settings: invalid settings data: ", settings); + return + } if(typeof settings.thing_icons_size != 'number'){ console.warn("settings.thing_icons_size was not a number: ", settings.thing_icons_size); settings.thing_icons_size = 3; } + document.getElementById('extension-floorplanner-local-settings-only-checkbox').checked = local_settings_only; document.getElementById('extension-floorplanner-auto-save-checkbox').checked = settings.auto_save; document.getElementById('extension-floorplanner-multi').checked = settings.multi_line; document.getElementById('extension-floorplanner-thing-icons-size').value = settings.thing_icons_size; set_thing_icon_scale(settings.thing_icons_size); + } function save_floorplanner_settings() { localStorage.setItem('extension-floorplanner-settings', JSON.stringify(settings)); + save_settings_to_controller(); } @@ -9922,6 +10043,25 @@ if (document.body.classList.contains('cups-printing')) { // send svg to Candle backend to print + + if(current_filename != null && typeof floorplans[current_filename] != 'undefined' && && typeof floorplans[current_filename].svg_data != 'undefined'){ + console.log("printing SVG via controller: ", floorplans[current_filename].svg_data); + window.API.postJson( + `/extensions/floorplanner/api/ajax`, { + 'action': 'print', + 'svg': floorplans[current_filename].svg_data + } + + ).then((body) => { + console.log("floorplanner: print response: ", body); + //console.log(body); + //this.show_list(body['data']); + + }).catch((e) => { + console.log("Floorplanner: caught error sending print command: ", e); + }); + } + } else if (document.body.classList.contains('kiosk')) { // heck, try to print? Or show a warning that printing is not possible from the kiosk? //window.print(); @@ -10200,15 +10340,15 @@ else{ let all_things = document.querySelectorAll('#floorplan .floorplan-thing'); - console.log("all_things: ", all_things); + //console.log("all_things: ", all_things); let css_filename = makeSafeForCSS(current_filename); - console.log("current_filename -> css filename: ", current_filename, ' -> ',css_filename); + //console.log("current_filename -> css filename: ", current_filename, ' -> ',css_filename); // Remove old filename class if it exists, and set current floorplan css class floorplan_view_el.classList.remove.apply(floorplan_view_el.classList, Array.from(floorplan_view_el.classList).filter(v=>v.startsWith('extension-floorplanner-p-'))); floorplan_view_el.classList.add('extension-floorplanner-p-' + css_filename); - console.log("floorplan_view_el.classList: ", floorplan_view_el.classList); + //console.log("floorplan_view_el.classList: ", floorplan_view_el.classList); //let cleaned_things = {}; let messy_things = {}; @@ -10247,7 +10387,7 @@ thing_label_el.setAttribute('for',css_name); thing_checkbox_el.addEventListener('change', (event) => { - console.log("checkbox changed: ", thing_checkbox_el.checked, thing_href, thing_title, css_name); + //console.log("checkbox changed: ", thing_checkbox_el.checked, thing_href, thing_title, css_name); if(current_filename != null){ if(typeof visible_things[css_filename] == 'undefined'){ @@ -10260,7 +10400,7 @@ } localStorage.setItem('extension-floorplanner-visible-things', JSON.stringify(visible_things)); update_thing_styles(); - + save_visible_things_to_controller(); } }); @@ -10367,11 +10507,23 @@ generate_floorplans_list(); root_el.classList.remove('extension-floorplanner-view-mode'); floorplan_view_el.classList.add('extension-floorplanner-edit-mode'); - if (localStorage.getItem('extension-floorplanner-history')) { + + if(Object.keys(floorplans).length){ + if (current_filename != null && typeof floorplans[current_filename] != 'undefined') { + load_from_floorplans( floorplans[current_filename] ); + } + else{ + current_filename = Object.keys(floorplans)[0]; + localStorage.setItem('extension-floorplanner-current-filename', JSON.stringify(current_filename)); + load_from_floorplans( floorplans[current_filename] ); + } + } + else if (current_filename != null && localStorage.getItem('extension-floorplanner-history')) { setTimeout(() => { initHistory('recovery'); }, 10); - } else if (localStorage.getItem('extension-floorplanner-floorplans')) { + } + else if (localStorage.getItem('extension-floorplanner-floorplans')) { let temp_floorplans = JSON.parse(localStorage.getItem('extension-floorplanner-floorplans')); //console.log("start_floorplanner: temp_floorplans: ", temp_floorplans); @@ -10401,7 +10553,7 @@ newFileModal.style.display = 'block'; } } else { - //console.log("temp_floorplans was not an object: ", temp_floorplans); + console.log("temp_floorplans was not an object: ", temp_floorplans); newFileModal.style.display = 'block'; } diff --git a/manifest.json b/manifest.json index 4ac1d4d..0a40573 100644 --- a/manifest.json +++ b/manifest.json @@ -6,7 +6,7 @@ "css/extension.css" ], "js": [ - "js/extension.js" + "js/extension.js" ] } ], @@ -26,7 +26,7 @@ "name": "Floorplanner", "options": { "default": { - "Debugging": false + "Debugging": false }, "schema": { "properties": { @@ -40,7 +40,7 @@ } }, "short_name": "Floorplanner", - "version": "0.0.1", + "version": "0.0.2", "web_accessible_resources": [ "css/*.css", "images/*.svg", diff --git a/pkg/floorplanner.py b/pkg/floorplanner.py index ea86110..1fc7324 100644 --- a/pkg/floorplanner.py +++ b/pkg/floorplanner.py @@ -12,9 +12,9 @@ #from time import sleep, time #import random #import datetime -#import subprocess +import subprocess #import threading -#import requests +import requests #import base64 try: @@ -54,18 +54,19 @@ def __init__(self, verbose=False): """Initialize the object.""" #print("INSIDE API HANDLER INIT") + self.ready = False self.addon_name = 'floorplanner' self.DEBUG = False #self.things = [] # Holds all the things, updated via the API. Used to display a nicer thing name instead of the technical internal ID. - self.fullscreen_delay = 60 - self.search_url = "https://swisscows.com/en/web?query=" + self.per_browser_settings = False + + self.cups_printer_available = False + self.peripage_printer_available = False + + self.persistent_data = {} - self.restore_tabs = True - self.history_length = 10 - self.slideshow = False - try: manifest_fname = os.path.join( os.path.dirname(__file__), @@ -93,29 +94,41 @@ def __init__(self, verbose=False): except Exception as e: print("Failed to init UX extension API handler: " + str(e)) - try: - self.addon_path = os.path.join(self.user_profile['addonsDir'], self.addon_name) - #self.persistence_file_folder = os.path.join(self.user_profile['configDir']) - self.persistence_file_path = os.path.join(self.user_profile['dataDir'], self.addon_name, 'persistence.json') - - except Exception as e: - print("Failed to make paths: " + str(e)) + + # PATHS + self.addon_path = os.path.join(self.user_profile['addonsDir'], self.addon_name) + #self.persistence_file_folder = os.path.join(self.user_profile['configDir']) + self.persistence_file_path = os.path.join(self.user_profile['dataDir'], self.addon_name, 'persistence.json') + + self.printable_file_path = os.path.join(self.user_profile['dataDir'], 'floorplan.svg') + self.external_picture_drop_dir = os.path.join(self.user_profile['dataDir'], 'privacy-manager', 'printme') + # Get persistent data - self.persistent_data = {} try: with open(self.persistence_file_path) as f: self.persistent_data = json.load(f) if self.DEBUG: print('self.persistent_data loaded from file: ' + str(self.persistent_data)) - except: - pass - #if self.DEBUG: - # print("could not load persistent data (if you just installed the add-on then this is normal)") - + except Exception as ex: + #pass + if self.DEBUG: + print("could not load persistent data (if you just installed the add-on then this is normal): " + str(ex)) + if not 'floorplans' in self.persistent_data: + self.persistent_data['floorplans'] = {} + + if not 'visible_things' in self.persistent_data: + self.persistent_data['visible_things'] = {} + + if not 'settings' in self.persistent_data or self.per_browser_settings == True: + self.persistent_data['settings'] = None + + self.check_photo_printer() + self.ready = True + # Read the settings from the add-on settings page def add_from_config(self): @@ -129,44 +142,69 @@ def add_from_config(self): config = database.load_config() database.close() - except: - print("Error! Failed to open settings database.") + except Exception as ex: + print("Error! Failed to open settings database: " + str(ex)) self.close_proxy() if not config: print("Error loading config from database") return + if 'Per browser settings' in config: + self.per_browser_settings = bool(config['Per device settings']) + if self.DEBUG: + print("-Per device settings preference was in config: " + str(self.per_browser_settings)) + if 'Debugging' in config: self.DEBUG = bool(config['Debugging']) if self.DEBUG: print("-Debugging preference was in config: " + str(self.DEBUG)) - if 'Restore tabs' in config: - self.restore_tabs = bool(config['Restore tabs']) - if self.DEBUG: - print("-Restore tabs preference was in config: " + str(self.restore_tabs)) - - if 'Browsing history length' in config: - self.history_length = int(config['Browsing history length']) - if self.DEBUG: - print("-Browsing history length preference was in config: " + str(self.history_length)) - - if 'Fullscreen delay' in config: - self.fullscreen_delay = int(config['Fullscreen delay']) - if self.DEBUG: - print("-Fullscreen delay preference was in config: " + str(self.fullscreen_delay)) + + + def check_photo_printer(self): + if self.DEBUG: + print("Checking if a cups or bluetooth photo printer is paired") + + self.cups_printer_available = False + self.peripage_printer_available = False + + try: + + lpstat_output = run_command("lpstat -v") + if 'No destinations added' in lpstat_output: + if self.DEBUG: + print("No network printers connected") - if 'Slideshow' in config: - self.slideshow = bool(config['Slideshow']) - if self.DEBUG: - print("-Slideshow preference was in config: " + str(self.slideshow)) - if 'Search URL' in config: - self.search_url = str(config['Search URL']) - if self.DEBUG: - print("-Search url preference was in config: " + str(self.search_url)) + # See if there is a Peripage photo printer connected + if os.path.isdir(self.external_picture_drop_dir): + if self.DEBUG: + print("privacy manager photo drop-off dir existed") + bluetooth_printer_check = run_command('sudo bluetoothctl devices Paired') + if self.DEBUG: + print("bluetooth_printer_check: " + str(bluetooth_printer_check)) + if 'peripage' in bluetooth_printer_check.lower(): + self.peripage_printer_available = True + if self.DEBUG: + print("paired bluetooth printer was detected") + return True + + + + else: + if self.DEBUG: + print("a cups printer is connected") + self.cups_printer_available = True + return True + + + except Exception as ex: + print("Error while checking for printer: " + str(ex)) + return False + + def handle_request(self, request): @@ -189,19 +227,132 @@ def handle_request(self, request): # INIT if action == 'init': + if self.DEBUG: + print("handling init request") + + #print("request.body: " + str(type(request.body))); + + try: + if 'visible_things' in request.body: + self.persistent_data['visible_things'] = request.body['visible_things'] + + if 'floorplans' in request.body: + self.persistent_data['floorplans'] = request.body['floorplans'] + + if 'settings' in request.body: + self.persistent_data['settings'] = request.body['settings'] + self.save_persistent_data() + + except Exception as ex: + if self.DEBUG: + print("Error handling save: " + str(ex)) + return APIResponse( status=200, content_type='application/json', content=json.dumps({ 'action':action, - 'search_url':str(self.search_url), - 'fullscreen_delay':self.fullscreen_delay, - 'restore_tabs':self.restore_tabs, - 'history_length':self.history_length, - 'slideshow':self.slideshow + 'debug':self.DEBUG, + 'visible_things':self.persistent_data['visible_things'], + 'floorplans':self.persistent_data['floorplans'], + 'settings':self.persistent_data['settings'], }), ) + # 'per_browser_settings':self.per_browser_settings + + + + # INIT + if action == 'save': + if self.DEBUG: + print("handling save request") + + #print("request.body: " + str(type(request.body))); + state = False + try: + if 'visible_things' in request.body: + self.persistent_data['visible_things'] = request.body['visible_things'] + + if 'floorplans' in request.body: + self.persistent_data['floorplans'] = request.body['floorplans'] + + if 'settings' in request.body: + self.persistent_data['settings'] = request.body['settings'] + + self.save_persistent_data() + state = True + + except Exception as ex: + if self.DEBUG: + print("Error handling save: " + str(ex)) + + return APIResponse( + status=200, + content_type='application/json', + content=json.dumps({ + 'state':state, + 'action':action, + }), + ) + + + + elif action == 'print': + if self.DEBUG: + print("printing") + state = 'unable to print' + + try: + if 'svg' in request.body: + + self.check_photo_printer() + + with open(self.printable_file_path, 'w+') as f: + if type(request.body[svg]) == 'string': + f.write(request.body[svg]) + if self.DEBUG: + print("saved svg data to file: " + str(self.printable_file_path)) + + if self.cups_printer_available: + print_command = 'lp -o printer-error-policy=abort-job ' + str(self.printable_file_path) + if self.DEBUG: + print("printing using cups. Print command: \n" + str(print_command)) + os.system(print_command) + state = "Photo sent to (network) printer" + + elif self.peripage_printer_available: + if os.path.isdir(self.external_picture_drop_dir): + to_filename = os.path.join(self.external_picture_drop_dir, str(request.body['filename'])) + copy_command = 'mv -n ' + str(from_filename) + ' ' + str(to_filename) + if self.DEBUG: + print("move command: " + str(copy_command)) + os.system(copy_command) + state = "Floorplan sent to bluetooth printer" + # TODO: can it even print SVG files? + else: + if self.DEBUG: + print("photo drop dir (no longer) exists?") + state = 'peripage printer drop off directory did not exist' + + else: + state = 'No printer available?' + else: + if self.DEBUG: + print("file to be printed did not exist") + state = 'no file to print provided' + + return APIResponse( + status=200, + content_type='application/json', + content=json.dumps({'state':state}), + ) + except Exception as ex: + print("Error sending photo to printer: " + str(ex)) + return APIResponse( + status=500, + ) + # UNSUPPORTED ACTION else: @@ -264,14 +415,14 @@ def save_persistent_data(self): if self.DEBUG: print("Persistence file existed. Will try to save to it.") - with open(self.persistence_file_path) as f: - if self.DEBUG: - print("saving: " + str(self.persistent_data)) - try: - json.dump( self.persistent_data, open( self.persistence_file_path, 'w+' ) ) - except Exception as ex: - print("Error saving to persistence file: " + str(ex)) + try: + json.dump( self.persistent_data, open( self.persistence_file_path, 'w+' ) ) return True + except Exception as ex: + print("Error saving to persistence file: " + str(ex)) + + return False + #self.previous_persistent_data = self.persistent_data.copy() except Exception as ex: diff --git a/requirements.txt b/requirements.txt index 8b13789..663bd1f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ - +requests \ No newline at end of file diff --git a/views/content.html b/views/content.html index 45203ff..6ed9d0c 100644 --- a/views/content.html +++ b/views/content.html @@ -150,10 +150,21 @@

🏠 Floorplanner

-

⚙️ Settings

-
+

⚙️ Settings

+
    +
  • +
    +

    Local settings

    +

    Normally Floorplanner's settings are stored centrally on the controller. You can circumvent this for your current browser. Your settings will be saved in a cookie instead. This allows you to have per-browser settings, such as dark mode or bigger icons for your current display (browser) only.

    +
    +
    + + +
    +
  • +
  • Auto-save

    @@ -366,7 +377,7 @@

    Modify door/window



  • -