feat: lockscreen closes #1490

This commit is contained in:
Alfredo Monclus
2024-10-28 08:27:36 -03:00
parent 0d0715de19
commit 9a6aeaa43e
12 changed files with 474 additions and 24 deletions

View File

@@ -34,6 +34,12 @@ The options listed here are not editable from within the user interface.
# Define one or more moonraker power devices that turn on/off with the screensaver (CSV list)
# screen_on_devices: example1, example2
# screen_off_devices: example1, example2
# Define the password to use when locking the screen, this is not secure
# it's saved as plain text, it's meant to be a deterrent for kids or people at shows
# it will be redacted from the logs.
# default is no password
# lock_password: example_password
```
!!! tip

View File

@@ -168,6 +168,7 @@ class KlipperScreenConfig:
strs = (
'default_printer', 'language', 'print_sort_dir', 'theme', 'screen_blanking_printing', 'font_size',
'print_estimate_method', 'screen_blanking', "screen_on_devices", "screen_off_devices", 'print_view',
"lock_password"
)
numbers = (
'job_complete_timeout', 'job_error_timeout', 'move_speed_xy', 'move_speed_z',
@@ -584,14 +585,16 @@ class KlipperScreenConfig:
self.config.set(section, name, value)
def log_config(self, config):
sensitive_keys = [
r'(moonraker_api_key\s*(?:=|:)\s*)\S+',
r'(lock_password\s*(?:=|:)\s*)\S+',
]
config_str = self._build_config_string(config)
for pattern in sensitive_keys:
config_str = re.sub(pattern, r'\1[redacted]', config_str)
lines = [
" "
"===== Config File =====",
re.sub(
r'(moonraker_api_key\s*=\s*\S+)',
'moonraker_api_key = [redacted]',
self._build_config_string(config)
),
config_str,
"======================="
]
logging.info("\n".join(lines))

View File

@@ -10,7 +10,7 @@ from gi.repository import Gtk, GLib
class Keyboard(Gtk.Box):
langs = ["de", "en", "fr", "es"]
def __init__(self, screen, close_cb, entry=None):
def __init__(self, screen, close_cb, entry=None, box=None):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
self.shift = []
self.shift_active = False
@@ -20,6 +20,7 @@ class Keyboard(Gtk.Box):
self.timeout = self.clear_timeout = None
self.entry = entry
self.purpose = self.entry.get_input_purpose()
self.box = box or None
language = self.detect_language(screen._config.get_main_config().get("language", None))
@@ -218,7 +219,7 @@ class Keyboard(Gtk.Box):
if key == "":
Gtk.Entry.do_backspace(self.entry)
elif key == "":
self.close_cb(entry=self.entry)
self.close_cb(entry=self.entry, box=self.box)
return
elif key == "":
self.toggle_shift()

View File

@@ -0,0 +1,96 @@
import logging
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class LockScreen:
def __init__(self, screen):
self.screen = screen
self.lock_box = None
self.unlock_box = None
def lock(self, widget):
self.screen._menu_go_back(None, True)
logging.info("Locked the screen")
close = Gtk.Button()
close.connect("clicked", self.unlock)
self.lock_box = Gtk.Box(
width_request=self.screen.width, height_request=self.screen.height,
halign=Gtk.Align.CENTER
)
self.lock_box.pack_start(close, True, True, 0)
self.lock_box.get_style_context().add_class("lock")
self.screen.overlay.add_overlay(self.lock_box)
close.grab_focus()
self.lock_box.show_all()
def unlock(self, widget):
if not self.unlock_box:
self.unlock_box = self.create_unlock_box()
self.screen.overlay.add_overlay(self.unlock_box)
self.unlock_box.show_all()
self.screen.overlay.get_children()[0].hide()
def create_unlock_box(self):
box = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL,
width_request=self.screen.width, height_request=self.screen.height,
valign=Gtk.Align.CENTER
)
entry = Gtk.Entry(hexpand=True, vexpand=False, placeholder_text=_("Password"))
entry.set_input_purpose(Gtk.InputPurpose.PASSWORD)
entry.set_visibility(False)
entry.connect("focus-in-event", self.screen.show_keyboard, box, self.relock)
entry.connect("activate", self.unlock_attempt, entry)
entry.get_style_context().add_class("lockscreen_entry")
entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "view-reveal-symbolic")
entry.connect("icon-press", self.show_pass)
ok = Gtk.Button(label=_("Unlock"))
ok.connect("clicked", self.unlock_attempt, entry)
ok.get_style_context().add_class("lockscreen_button")
entry_row = Gtk.Box(hexpand=True, vexpand=True, valign=Gtk.Align.CENTER)
entry_row.pack_start(entry, True, True, 0)
entry_row.pack_start(ok, False, True, 0)
box.pack_start(entry_row, True, True, 0)
return box
@staticmethod
def show_pass(entry, icon_pos, event):
entry.grab_focus()
visible = not entry.get_visibility()
entry.set_visibility(visible)
if visible:
entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "view-conceal-symbolic")
entry.get_style_context().add_class("active")
else:
entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "view-reveal-symbolic")
entry.get_style_context().remove_class("active")
def relock(self, entry=None, box=None):
if not self.lock_box:
return
if self.unlock_box:
self.screen.overlay.remove(self.unlock_box)
self.unlock_box = None
self.lock_box.get_children()[0].grab_focus()
self.screen.overlay.get_children()[0].show_all()
def unlock_attempt(self, widget, entry):
if entry.get_text() != self.screen._config.get_main_config().get("lock_password", ""):
logging.info("Failed unlock")
self.screen.show_popup_message(_("Unlock failed"))
return
self.clear_lock()
def clear_lock(self):
if self.lock_box:
self.screen.overlay.remove(self.lock_box)
if self.unlock_box:
self.screen.overlay.remove(self.unlock_box)
self.lock_box = None
self.unlock_box = None
self.screen.remove_keyboard()
self.screen.overlay.get_children()[0].show()
logging.info("Unlocked")

View File

@@ -24,12 +24,16 @@ class Panel(ScreenPanel):
restart_ks = self._gtk.Button("refresh", _("Restart") + " KlipperScreen", "color3")
restart_ks.connect("clicked", self._screen.restart_ks)
lock_screen = self._gtk.Button("lock", _("Lock"), "color3")
lock_screen.connect("clicked", self._screen.lock_screen.lock)
self.main = Gtk.Grid(row_homogeneous=True, column_homogeneous=True)
if self._printer and self._printer.state not in {'disconnected', 'startup', 'shutdown', 'error'}:
self.main.attach(estop, 0, 0, 1, 1)
self.main.attach(estop, 0, 0, 1, 2)
self.main.attach(restart_ks, 1, 0, 1, 1)
self.main.attach(poweroff, 0, 1, 1, 1)
self.main.attach(restart, 1, 1, 1, 1)
self.main.attach(lock_screen, 2, 0, 1, 1)
self.main.attach(poweroff, 1, 1, 1, 1)
self.main.attach(restart, 2, 1, 1, 1)
self.content.add(self.main)
def reboot_poweroff(self, widget, method):

View File

@@ -29,9 +29,11 @@ from ks_includes.KlippyGtk import KlippyGtk
from ks_includes.printer import Printer
from ks_includes.widgets.keyboard import Keyboard
from ks_includes.widgets.prompts import Prompt
from ks_includes.widgets.lockscreen import LockScreen
from ks_includes.config import KlipperScreenConfig
from panels.base_panel import BasePanel
logging.getLogger("urllib3").setLevel(logging.WARNING)
klipperscreendir = pathlib.Path(__file__).parent.resolve()
@@ -77,6 +79,7 @@ class KlipperScreen(Gtk.Window):
prompt = None
tempstore_timeout = None
def __init__(self, args):
self.server_info = None
try:
@@ -150,7 +153,9 @@ class KlipperScreen(Gtk.Window):
self.set_icon_from_file(os.path.join(klipperscreendir, "styles", "icon.svg"))
self.base_panel = BasePanel(self)
self.change_theme(self.theme)
self.add(self.base_panel.main_grid)
self.overlay = Gtk.Overlay()
self.add(self.overlay)
self.overlay.add_overlay(self.base_panel.main_grid)
self.show_all()
self.update_cursor(self.show_cursor)
min_ver = (3, 8)
@@ -167,6 +172,7 @@ class KlipperScreen(Gtk.Window):
return
self.base_panel.activate()
self.set_screenblanking_timeout(self._config.get_main_config().get('screen_blanking'))
self.lock_screen = LockScreen(self)
self.log_notification("KlipperScreen Started", 1)
self.initial_connection()
@@ -639,8 +645,7 @@ class KlipperScreen(Gtk.Window):
box = Gtk.Box(halign=Gtk.Align.CENTER, width_request=self.width, height_request=self.height)
box.pack_start(close, True, True, 0)
box.get_style_context().add_class("screensaver")
self.remove(self.base_panel.main_grid)
self.add(box)
self.overlay.add_overlay(box)
# Avoid leaving a cursor-handle
close.grab_focus()
@@ -655,9 +660,8 @@ class KlipperScreen(Gtk.Window):
if self.screensaver is None:
return False
logging.debug("Closing Screensaver")
self.remove(self.screensaver)
self.overlay.remove(self.screensaver)
self.screensaver = None
self.add(self.base_panel.main_grid)
if self.use_dpms:
self.wake_screen()
else:
@@ -666,8 +670,8 @@ class KlipperScreen(Gtk.Window):
logging.info(f"Restoring Dialog {dialog}")
dialog.show()
self.gtk.set_cursor(self.show_cursor, window=self.get_window())
self.show_all()
self.power_devices(None, self._config.get_main_config().get("screen_on_devices", ""), on=True)
self.lock_screen.relock()
def check_dpms_state(self):
if not self.use_dpms:
@@ -1187,12 +1191,16 @@ class KlipperScreen(Gtk.Window):
self.remove_tempstore_timeout()
return self.init_tempstore()
def show_keyboard(self, entry=None, event=None):
def show_keyboard(self, entry=None, event=None, box=None, close_cb=None):
if entry is None:
logging.debug("Error: no entry provided for keyboard")
return
if box is None:
box = self.base_panel.content
if close_cb is None:
close_cb = self.remove_keyboard
if self.keyboard is not None:
self.remove_keyboard()
self.remove_keyboard(box=box)
entry.grab_focus()
kbd_grid = Gtk.Grid()
kbd_grid.set_size_request(self.gtk.content_width, self.gtk.keyboard_height)
@@ -1206,11 +1214,12 @@ class KlipperScreen(Gtk.Window):
kbd_grid.set_column_homogeneous(True)
kbd_width = 2 if purpose == Gtk.InputPurpose.DIGITS else 3
kbd_grid.attach(Gtk.Box(), 0, 0, 1, 1)
kbd_grid.attach(Keyboard(self, self.remove_keyboard, entry=entry), 1, 0, kbd_width, 1)
kbd = Keyboard(self, close_cb, entry=entry, box=box)
kbd_grid.attach(kbd, 1, 0, kbd_width, 1)
kbd_grid.attach(Gtk.Box(), kbd_width + 1, 0, 1, 1)
self.keyboard = {"box": kbd_grid}
self.base_panel.content.pack_end(kbd_grid, False, False, 0)
self.base_panel.content.show_all()
box.pack_end(kbd_grid, False, False, 0)
box.show_all()
def _show_matchbox_keyboard(self, kbd_grid):
env = os.environ.copy()
@@ -1240,12 +1249,14 @@ class KlipperScreen(Gtk.Window):
}
return
def remove_keyboard(self, entry=None, event=None):
def remove_keyboard(self, entry=None, event=None, box=None):
if self.keyboard is None:
return
if box is None:
box = self.base_panel.content
if 'process' in self.keyboard:
os.kill(self.keyboard['process'].pid, SIGTERM)
self.base_panel.content.remove(self.keyboard['box'])
box.remove(self.keyboard['box'])
self.keyboard = None
if entry:
entry.set_sensitive(False) # Move the focus

View File

@@ -563,6 +563,24 @@ popover button {
margin: 0;
}
.lock
.lock button
.lock button:hover,
.lock button:focus,
.lock button:active {
border: 0;
margin: 0;
background-color: Transparent;
}
.lockscreen_entry {
margin: 2em;
}
.lockscreen_button {
padding: 2em;
}
.screensaver,
.screensaver button,
.screensaver button:hover,

View File

@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg957"
sodipodi:docname="lock.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs961" />
<sodipodi:namedview
id="namedview959"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
showgrid="false"
inkscape:zoom="13"
inkscape:cx="9.5384615"
inkscape:cy="10.692308"
inkscape:window-width="1600"
inkscape:window-height="828"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg957"
inkscape:showpageshadow="2"
inkscape:deskcolor="#505050"
showguides="true">
<sodipodi:guide
position="7.5334069,21.1875"
orientation="0,1"
id="guide1503"
inkscape:locked="false" />
<sodipodi:guide
position="11.15053,22.721769"
orientation="0,-1"
id="guide1505"
inkscape:locked="false" />
</sodipodi:namedview>
<path
d="M 7.625,12.125 V 8.3750002 C 7.625,7.1645835 8.0515627,6.1328127 8.904688,5.2796878 9.757812,4.4265626 10.789582,4 11.999998,4 13.210416,4 14.242188,4.4265626 15.095313,5.2796878 15.948438,6.1328127 16.375,7.1645835 16.375,8.3750002 V 12.125 Z m 1.75,0 h 5.25 V 8.3750002 C 14.625,7.6458336 14.369792,7.0260419 13.859375,6.5156251 13.348958,6.0052084 12.729166,5.75 11.999998,5.75 11.270833,5.75 10.651041,6.0052084 10.140624,6.5156251 9.630208,7.0260419 9.375,7.6458336 9.375,8.3750002 Z"
id="path233"
style="font-variation-settings:normal;opacity:0.998;vector-effect:none;fill:#839496;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
sodipodi:nodetypes="csssssccccsssssc" />
<rect
style="font-variation-settings:normal;opacity:0.998;vector-effect:none;fill:#839496;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
id="rect676"
width="12.25"
height="10.208334"
x="5.875"
y="10.895833" />
<rect
style="opacity:0.998;fill:#657b83;fill-opacity:1;stroke:none;stroke-width:2.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stop-color:#000000"
id="rect1039-5"
width="12.25"
height="3.0625"
x="5.875"
y="10.895833" />
<rect
style="opacity:0.998;fill:#657b83;fill-opacity:1;stroke:none;stroke-width:2.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stop-color:#000000"
id="rect1039-5-6"
width="12.25"
height="3.0625"
x="5.875"
y="18.041666" />
<circle
style="font-variation-settings:normal;opacity:0.998;vector-effect:none;fill:#93a1a1;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
id="path1722"
cx="12"
cy="16"
r="3" />
<circle
style="font-variation-settings:normal;opacity:0.998;vector-effect:none;fill:#839496;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
id="path1722-0"
cx="12"
cy="16"
r="2" />
<rect
style="font-variation-settings:normal;opacity:0.998;vector-effect:none;fill:#073642;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
id="rect1965"
width="1"
height="3"
x="11.5"
y="14.5" />
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg957"
sodipodi:docname="lock.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs961" />
<sodipodi:namedview
id="namedview959"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
showgrid="false"
inkscape:zoom="13"
inkscape:cx="8.4230769"
inkscape:cy="13.615385"
inkscape:window-width="1600"
inkscape:window-height="828"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg957"
inkscape:showpageshadow="2"
inkscape:deskcolor="#505050" />
<path
d="m 6.75,21.1875 q -0.721876,0 -1.235938,-0.514062 Q 5,20.159375 5,19.4375 v -8.75 Q 5,9.9656252 5.514062,9.4515625 6.028124,8.9375001 6.75,8.9375001 H 7.625 V 7.1875002 Q 7.625,5.3718751 8.904688,4.0921878 10.184374,2.8125 11.999998,2.8125 q 1.815627,0 3.095315,1.2796878 Q 16.375,5.3718751 16.375,7.1875002 v 1.7499999 h 0.875 q 0.721875,0 1.235938,0.5140624 Q 19,9.9656252 19,10.6875 v 8.75 q 0,0.721875 -0.514062,1.235938 Q 17.971875,21.1875 17.25,21.1875 Z m 0,-1.75 h 10.5 v -8.75 H 6.75 Z m 5.249998,-2.625 q 0.721875,0 1.23594,-0.514062 Q 13.75,15.784375 13.75,15.062501 q 0,-0.721875 -0.514062,-1.235939 -0.514065,-0.514061 -1.23594,-0.514061 -0.721875,0 -1.235935,0.514061 Q 10.25,14.340626 10.25,15.062501 q 0,0.721874 0.514063,1.235937 0.51406,0.514062 1.235935,0.514062 z M 9.375,8.9375001 h 5.25 V 7.1875002 q 0,-1.0937499 -0.765625,-1.8593751 Q 13.09375,4.5625 11.999998,4.5625 10.90625,4.5625 10.140624,5.3281251 9.375,6.0937503 9.375,7.1875002 Z M 6.75,19.4375 v -8.75 z"
id="path233"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#e2e2e2;fill-opacity:1;stroke-width:0.999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg957"
sodipodi:docname="lock.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs961" />
<sodipodi:namedview
id="namedview959"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
showgrid="false"
inkscape:zoom="13"
inkscape:cx="-1.6923077"
inkscape:cy="13.615385"
inkscape:window-width="1600"
inkscape:window-height="828"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg957"
inkscape:showpageshadow="2"
inkscape:deskcolor="#505050" />
<path
d="m 6.75,21.1875 c -0.4812507,0 -0.89323,-0.171354 -1.235938,-0.514062 C 5.171354,20.330729 5,19.91875 5,19.4375 v -8.75 C 5,10.20625 5.171354,9.794271 5.514062,9.4515625 5.85677,9.1088542 6.2687493,8.9375001 6.75,8.9375001 H 7.625 V 7.1875002 C 7.625,5.9770835 8.0515627,4.9453127 8.904688,4.0921878 9.757812,3.2390626 10.789582,2.8125 11.999998,2.8125 c 1.210418,0 2.24219,0.4265626 3.095315,1.2796878 C 15.948438,4.9453127 16.375,5.9770835 16.375,7.1875002 v 1.7499999 h 0.875 c 0.48125,0 0.893229,0.1713541 1.235938,0.5140624 C 18.828646,9.794271 19,10.20625 19,10.6875 v 8.75 c 0,0.48125 -0.171354,0.893229 -0.514062,1.235938 C 18.143229,21.016146 17.73125,21.1875 17.25,21.1875 Z m 5.249998,-4.375 c 0.48125,0 0.89323,-0.171354 1.23594,-0.514062 C 13.578646,15.955729 13.75,15.54375 13.75,15.062501 c 0,-0.48125 -0.171354,-0.89323 -0.514062,-1.235939 -0.34271,-0.342707 -0.75469,-0.514061 -1.23594,-0.514061 -0.48125,0 -0.893228,0.171354 -1.235935,0.514061 C 10.421354,14.169271 10.25,14.581251 10.25,15.062501 c 0,0.481249 0.171354,0.893228 0.514063,1.235937 0.342707,0.342708 0.754685,0.514062 1.235935,0.514062 z M 9.375,8.9375001 h 5.25 V 7.1875002 C 14.625,6.4583336 14.369792,5.8385419 13.859375,5.3281251 13.348958,4.8177084 12.729166,4.5625 11.999998,4.5625 c -0.729165,0 -1.348957,0.2552084 -1.859374,0.7656251 C 9.630208,5.8385419 9.375,6.4583336 9.375,7.1875002 Z"
id="path233"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#e2e2e2;fill-opacity:1;stroke-width:0.999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
sodipodi:nodetypes="sssssscssssscssssssssssssssssccsssssc" />
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg957"
sodipodi:docname="lock.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs961" />
<sodipodi:namedview
id="namedview959"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
showgrid="false"
inkscape:zoom="13"
inkscape:cx="-1.6923077"
inkscape:cy="13.615385"
inkscape:window-width="1600"
inkscape:window-height="828"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg957"
inkscape:showpageshadow="2"
inkscape:deskcolor="#505050" />
<path
d="m 6.75,21.1875 q -0.721876,0 -1.235938,-0.514062 Q 5,20.159375 5,19.4375 v -8.75 Q 5,9.9656252 5.514062,9.4515625 6.028124,8.9375001 6.75,8.9375001 H 7.625 V 7.1875002 Q 7.625,5.3718751 8.904688,4.0921878 10.184374,2.8125 11.999998,2.8125 q 1.815627,0 3.095315,1.2796878 Q 16.375,5.3718751 16.375,7.1875002 v 1.7499999 h 0.875 q 0.721875,0 1.235938,0.5140624 Q 19,9.9656252 19,10.6875 v 8.75 q 0,0.721875 -0.514062,1.235938 Q 17.971875,21.1875 17.25,21.1875 Z m 0,-1.75 h 10.5 v -8.75 H 6.75 Z m 5.249998,-2.625 q 0.721875,0 1.23594,-0.514062 Q 13.75,15.784375 13.75,15.062501 q 0,-0.721875 -0.514062,-1.235939 -0.514065,-0.514061 -1.23594,-0.514061 -0.721875,0 -1.235935,0.514061 Q 10.25,14.340626 10.25,15.062501 q 0,0.721874 0.514063,1.235937 0.51406,0.514062 1.235935,0.514062 z M 9.375,8.9375001 h 5.25 V 7.1875002 q 0,-1.0937499 -0.765625,-1.8593751 Q 13.09375,4.5625 11.999998,4.5625 10.90625,4.5625 10.140624,5.3281251 9.375,6.0937503 9.375,7.1875002 Z M 6.75,19.4375 v -8.75 z"
id="path233"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="64"
height="64"
viewBox="0 0 64 64"
version="1.1"
id="svg10"
sodipodi:docname="lock.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata16">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>folder</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs14" />
<sodipodi:namedview
pagecolor="#bfbfbf"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1600"
inkscape:window-height="828"
id="namedview12"
showgrid="false"
inkscape:pagecheckerboard="false"
inkscape:zoom="10.827586"
inkscape:cx="26.229299"
inkscape:cy="44.423567"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg10"
inkscape:snap-bbox="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:document-rotation="0"
inkscape:showpageshadow="2"
inkscape:deskcolor="#bfbfbf" />
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
<title
id="title2">folder</title>
<desc
id="desc4">Created with Sketch.</desc>
<ellipse
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path5114"
cx="31.929701"
cy="41.06234"
rx="4.3648357"
ry="4.4511104" />
<rect
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
id="rect602"
width="32"
height="27"
x="16"
y="27.5" />
<g
id="g745"
transform="translate(0,1)">
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
id="path680"
sodipodi:type="arc"
sodipodi:cx="32"
sodipodi:cy="18"
sodipodi:rx="11"
sodipodi:ry="11"
sodipodi:start="3.1415927"
sodipodi:end="0"
sodipodi:arc-type="arc"
d="M 21,18 A 11,11 0 0 1 32,7 11,11 0 0 1 43,18"
sodipodi:open="true" />
<path
id="path738"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
d="m 43,18 v 8.5 M 21,18 v 8.5 h 22" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB