Implement 'deleting' drawings

Enable the delete button that's been hidden away so far. When clicked, we
suffix the cached json file with '.deleted'. This also causes a popup with an
undo button to appear (taken from Nautilus). When clicked, that button will
restore the drawing again.

This is really all just renaming anyway, because nothing ever gets deleted
here.

An extra filter is needed to skip Tuhi drawings that have been deleted in the
GUI - we don't want to add the drawings we just deleted again just because
Tuhi still keeps them in cache.
pull/145/head
Peter Hutterer 2019-07-16 14:40:37 +10:00
parent ff35e5bfc5
commit a857b14b8a
5 changed files with 152 additions and 9 deletions

View File

@ -26,10 +26,11 @@
<property name="hexpand">True</property>
<child>
<object class="GtkButton" id="btn_remove">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">icon_remove</property>
<signal name="clicked" handler="_on_button_removed_clicked" swapped="no"/>
<signal name="clicked" handler="_on_delete_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>

View File

@ -88,19 +88,105 @@
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<object class="GtkOverlay">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="can_focus">False</property>
<child>
<object class="GtkViewport">
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkFlowBox" id="flowbox_drawings">
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkFlowBox" id="flowbox_drawings">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="homogeneous">True</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="index">-1</property>
</packing>
</child>
<child type="overlay">
<object class="GtkRevealer" id="overlay_undo">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">start</property>
<property name="transition_type">none</property>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">start</property>
<property name="margin_left">12</property>
<property name="margin_right">4</property>
<property name="margin_start">12</property>
<property name="margin_end">4</property>
<child>
<object class="GtkButton" id="notification_delete_undo">
<property name="label" translatable="yes">Undo delete drawing</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="no_show_all">True</property>
<property name="margin_right">6</property>
<property name="margin_end">6</property>
<signal name="clicked" handler="_on_undo_clicked" swapped="no"/>
<style>
<class name="text-button"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="notification_delete_close">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">True</property>
<property name="relief">none</property>
<signal name="clicked" handler="_on_undo_close_clicked" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">window-close-symbolic</property>
<property name="icon_size">2</property>
</object>
</child>
<style>
<class name="image-button"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<style>
<class name="app-notification"/>
</style>
</object>
</child>
</object>
@ -124,7 +210,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">3</property>
</packing>
</child>
</object>

View File

@ -90,12 +90,37 @@ class Config(GObject.Object):
if path.exists():
return
# Tuhi may still cache files we've 'deleted' locally. These need to
# be ignored because they're still technically deleted.
deleted = Path(ROOT_PATH, f'{timestamp}.json.deleted')
if deleted.exists():
return
with open(path, 'w') as fd:
fd.write(json_string)
self._drawings.append(json.loads(json_string))
self.notify('drawings')
def delete_drawing(self, timestamp):
# We don't delete json files immediately, we just rename them
# so we can resurrect them in the future if need be.
path = Path(ROOT_PATH, f'{timestamp}.json')
target = Path(ROOT_PATH, f'{timestamp}.json.deleted')
path.rename(target)
self._drawings = [d for d in self._drawings if d['timestamp'] != timestamp]
self.notify('drawings')
def undelete_drawing(self, timestamp):
path = Path(ROOT_PATH, f'{timestamp}.json')
target = Path(ROOT_PATH, f'{timestamp}.json.deleted')
target.rename(path)
with open(path) as fd:
self._drawings.append(json.load(fd))
self.notify('drawings')
@classmethod
def load(cls):
if cls._config_obj is None:

View File

@ -12,6 +12,8 @@
#
from gi.repository import GObject, Gtk
from .config import Config
import datetime
import time
import gi
@ -87,3 +89,7 @@ class Drawing(Gtk.Box):
# FIXME: error handling
dialog.destroy()
@Gtk.Template.Callback('_on_delete_button_clicked')
def _on_delete_button_clicked(self, button):
Config.load().delete_drawing(self.timestamp)

View File

@ -54,6 +54,9 @@ class DrawingPerspective(Gtk.Stack):
flowbox_drawings = Gtk.Template.Child()
spinner_sync = Gtk.Template.Child()
label_last_sync = Gtk.Template.Child()
overlay_undo = Gtk.Template.Child()
notification_delete_undo = Gtk.Template.Child()
notification_delete_close = Gtk.Template.Child()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@ -102,6 +105,19 @@ class DrawingPerspective(Gtk.Stack):
self.flowbox_drawings.insert(drawing, index)
# Remove deleted ones
deleted = [d for d in self.known_drawings if d not in config.drawings]
for d in deleted:
child = self.flowbox_drawings.get_child_at_index(0)
while child is not None:
if child.get_child().timestamp == d['timestamp']:
self.flowbox_drawings.remove(child)
self.known_drawings.remove(d)
self.notification_delete_undo.deleted_drawing = d['timestamp']
self.overlay_undo.set_reveal_child(True)
break
child = self.flowbox_drawings.get_child_at_index(0)
@GObject.Property
def device(self):
return self._device
@ -180,3 +196,12 @@ class DrawingPerspective(Gtk.Stack):
logger.debug(f'{device.name} - listening stopped, restarting')
# We never want to stop listening
device.start_listening()
@Gtk.Template.Callback('_on_undo_close_clicked')
def _on_undo_close_clicked(self, button):
self.overlay_undo.set_reveal_child(False)
@Gtk.Template.Callback('_on_undo_clicked')
def _on_undo_clicked(self, button):
Config.load().undelete_drawing(button.deleted_drawing)
self.overlay_undo.set_reveal_child(False)