[gnome-sound-recorder] undo delete recording



commit 6411a90f4e5340e05c43eed9c7c80f2124db9c60
Author: Kavan Mevada <kavanmevada gmail com>
Date:   Mon Aug 10 09:23:47 2020 +0530

    undo delete recording
    
    fixes #10

 data/ui/window.ui        | 427 +++++++++++++++++++++++++++--------------------
 src/recordingsListBox.js |   9 +-
 src/row.js               |   8 +-
 src/window.js            |  43 ++++-
 4 files changed, 293 insertions(+), 194 deletions(-)
---
diff --git a/data/ui/window.ui b/data/ui/window.ui
index 1750d038..7dcd6750 100644
--- a/data/ui/window.ui
+++ b/data/ui/window.ui
@@ -109,127 +109,193 @@
           </packing>
         </child>
         <child>
-          <object class="GtkStack" id="mainStack">
+          <object class="GtkOverlay">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="hexpand">True</property>
-            <property name="vexpand">True</property>
             <child>
-              <object class="GtkScrolledWindow" id="scrolledWindow">
+              <object class="GtkStack" id="mainStack">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
+                <property name="can_focus">False</property>
                 <property name="hexpand">True</property>
                 <property name="vexpand">True</property>
-                <property name="hscrollbar_policy">never</property>
                 <child>
-                  <object class="HdyClamp" id="column">
+                  <object class="GtkScrolledWindow" id="scrolledWindow">
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="maximum_size">650</property>
+                    <property name="can_focus">True</property>
+                    <property name="hexpand">True</property>
+                    <property name="vexpand">True</property>
+                    <property name="hscrollbar_policy">never</property>
+                    <child>
+                      <object class="HdyClamp" id="column">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="maximum_size">650</property>
+                      </object>
+                    </child>
                   </object>
+                  <packing>
+                    <property name="name">recordings</property>
+                  </packing>
                 </child>
-              </object>
-              <packing>
-                <property name="name">recordings</property>
-              </packing>
-            </child>
-            <child>
-              <object class="HdyWindowHandle">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
                 <child>
-                  <object class="GtkBox">
+                  <object class="HdyWindowHandle">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="margin_left">8</property>
-                    <property name="margin_right">8</property>
-                    <property name="margin_top">24</property>
-                    <property name="margin_bottom">24</property>
-                    <property name="orientation">vertical</property>
                     <child>
-                      <object class="GtkBox" id="recorderBox">
-                        <property name="height_request">230</property>
+                      <object class="GtkBox">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="valign">center</property>
+                        <property name="margin_left">8</property>
+                        <property name="margin_right">8</property>
+                        <property name="margin_top">24</property>
+                        <property name="margin_bottom">24</property>
                         <property name="orientation">vertical</property>
                         <child>
-                          <object class="GtkLabel" id="recorderTime">
+                          <object class="GtkBox" id="recorderBox">
+                            <property name="height_request">230</property>
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="margin_top">18</property>
-                            <style>
-                              <class name="dim-label"/>
-                              <class name="recorder-time-label"/>
-                            </style>
+                            <property name="valign">center</property>
+                            <property name="orientation">vertical</property>
+                            <child>
+                              <object class="GtkLabel" id="recorderTime">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="margin_top">18</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                  <class name="recorder-time-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="pack_type">end</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
                           </object>
                           <packing>
                             <property name="expand">False</property>
                             <property name="fill">True</property>
-                            <property name="pack_type">end</property>
                             <property name="position">0</property>
                           </packing>
                         </child>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkBox">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="halign">center</property>
-                        <property name="valign">center</property>
-                        <property name="margin_top">8</property>
-                        <property name="spacing">18</property>
                         <child>
-                          <object class="GtkStack" id="playbackStack">
+                          <object class="GtkBox">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="halign">start</property>
+                            <property name="halign">center</property>
                             <property name="valign">center</property>
+                            <property name="margin_top">8</property>
+                            <property name="spacing">18</property>
+                            <child>
+                              <object class="GtkStack" id="playbackStack">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="valign">center</property>
+                                <child>
+                                  <object class="GtkButton" id="playButton">
+                                    <property name="name">playButton</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="tooltip_text" translatable="yes">Resume 
Recording</property>
+                                    <property name="halign">center</property>
+                                    <property name="always_show_image">True</property>
+                                    <signal name="clicked" handler="onRecorderResume" swapped="no"/>
+                                    <child>
+                                      <object class="GtkImage" id="playIcon">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="icon_name">media-playback-start-symbolic</property>
+                                      </object>
+                                    </child>
+                                    <style>
+                                      <class name="pill-button"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="name">recorder-start</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkButton" id="pauseButton">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="tooltip_text" translatable="yes">Pause 
Recording</property>
+                                    <property name="halign">center</property>
+                                    <property name="always_show_image">True</property>
+                                    <signal name="clicked" handler="onRecorderPause" swapped="no"/>
+                                    <child>
+                                      <object class="GtkImage" id="pauseIcon">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="icon_name">media-playback-pause-symbolic</property>
+                                      </object>
+                                    </child>
+                                    <style>
+                                      <class name="pill-button"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="name">recorder-pause</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
                             <child>
-                              <object class="GtkButton" id="playButton">
-                                <property name="name">playButton</property>
+                              <object class="GtkButton">
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">True</property>
-                                <property name="tooltip_text" translatable="yes">Resume Recording</property>
+                                <property name="tooltip_text" translatable="yes">Stop Recording</property>
                                 <property name="halign">center</property>
-                                <property name="always_show_image">True</property>
-                                <signal name="clicked" handler="onRecorderResume" swapped="no"/>
+                                <property name="valign">center</property>
+                                <signal name="clicked" handler="onRecorderStop" swapped="no"/>
                                 <child>
-                                  <object class="GtkImage" id="playIcon">
+                                  <object class="GtkImage">
                                     <property name="visible">True</property>
                                     <property name="can_focus">False</property>
-                                    <property name="icon_name">media-playback-start-symbolic</property>
+                                    <property name="icon_name">media-playback-stop-symbolic</property>
+                                    <property name="icon_size">3</property>
                                   </object>
                                 </child>
                                 <style>
                                   <class name="pill-button"/>
+                                  <class name="destructive-action"/>
+                                  <class name="large-button"/>
                                 </style>
                               </object>
                               <packing>
-                                <property name="name">recorder-start</property>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
                               </packing>
                             </child>
                             <child>
-                              <object class="GtkButton" id="pauseButton">
+                              <object class="GtkButton">
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">True</property>
-                                <property name="tooltip_text" translatable="yes">Pause Recording</property>
+                                <property name="tooltip_text" translatable="yes">Cancel Recording</property>
                                 <property name="halign">center</property>
+                                <property name="valign">center</property>
                                 <property name="always_show_image">True</property>
-                                <signal name="clicked" handler="onRecorderPause" swapped="no"/>
+                                <signal name="clicked" handler="onRecorderCancel" swapped="no"/>
                                 <child>
-                                  <object class="GtkImage" id="pauseIcon">
+                                  <object class="GtkImage">
                                     <property name="visible">True</property>
                                     <property name="can_focus">False</property>
-                                    <property name="icon_name">media-playback-pause-symbolic</property>
+                                    <property name="icon_name">user-trash-symbolic</property>
                                   </object>
                                 </child>
                                 <style>
@@ -237,160 +303,153 @@
                                 </style>
                               </object>
                               <packing>
-                                <property name="name">recorder-pause</property>
-                                <property name="position">1</property>
+                                <property name="position">2</property>
                               </packing>
                             </child>
                           </object>
                           <packing>
                             <property name="expand">False</property>
                             <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkButton">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <property name="tooltip_text" translatable="yes">Stop Recording</property>
-                            <property name="halign">center</property>
-                            <property name="valign">center</property>
-                            <signal name="clicked" handler="onRecorderStop" swapped="no"/>
-                            <child>
-                              <object class="GtkImage">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_name">media-playback-stop-symbolic</property>
-                                <property name="icon_size">3</property>
-                              </object>
-                            </child>
-                            <style>
-                              <class name="pill-button"/>
-                              <class name="destructive-action"/>
-                              <class name="large-button"/>
-                            </style>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
+                            <property name="pack_type">end</property>
                             <property name="position">1</property>
                           </packing>
                         </child>
-                        <child>
-                          <object class="GtkButton">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <property name="tooltip_text" translatable="yes">Cancel Recording</property>
-                            <property name="halign">center</property>
-                            <property name="valign">center</property>
-                            <property name="always_show_image">True</property>
-                            <signal name="clicked" handler="onRecorderCancel" swapped="no"/>
-                            <child>
-                              <object class="GtkImage">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_name">user-trash-symbolic</property>
-                              </object>
-                            </child>
-                            <style>
-                              <class name="pill-button"/>
-                            </style>
-                          </object>
-                          <packing>
-                            <property name="position">2</property>
-                          </packing>
-                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="name">recorder</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="halign">center</property>
+                    <property name="valign">center</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkImage" id="emptyIcon">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="halign">center</property>
+                        <property name="valign">center</property>
+                        <property name="pixel_size">96</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="margin_top">8</property>
+                        <property name="label" translatable="yes">Add Recordings</property>
+                        <style>
+                          <class name="dim-label"/>
+                          <class name="title-1"/>
+                        </style>
                       </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">True</property>
-                        <property name="pack_type">end</property>
                         <property name="position">1</property>
                       </packing>
                     </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="margin_top">4</property>
+                        <property name="label" translatable="yes">Use the &lt;b&gt;Record&lt;/b&gt; button 
to make sound recordings</property>
+                        <property name="use_markup">True</property>
+                        <property name="justify">center</property>
+                        <property name="wrap">True</property>
+                        <property name="max_width_chars">50</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
                   </object>
+                  <packing>
+                    <property name="name">empty</property>
+                    <property name="position">2</property>
+                  </packing>
                 </child>
               </object>
-              <packing>
-                <property name="name">recorder</property>
-                <property name="position">1</property>
-              </packing>
             </child>
-            <child>
-              <object class="GtkBox">
+            <child type="overlay">
+              <object class="GtkRevealer" id="notificationRevealer">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="halign">center</property>
-                <property name="valign">center</property>
-                <property name="orientation">vertical</property>
-                <child>
-                  <object class="GtkImage" id="emptyIcon">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="halign">center</property>
-                    <property name="valign">center</property>
-                    <property name="pixel_size">96</property>
-                    <style>
-                      <class name="dim-label"/>
-                    </style>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
+                <property name="valign">start</property>
                 <child>
-                  <object class="GtkLabel">
+                  <object class="GtkBox">
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="margin_top">8</property>
-                    <property name="label" translatable="yes">Add Recordings</property>
-                    <style>
-                      <class name="dim-label"/>
-                      <class name="title-1"/>
-                    </style>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkLabel">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="margin_top">4</property>
-                    <property name="label" translatable="yes">Use the &lt;b&gt;Record&lt;/b&gt; button to 
make sound recordings</property>
-                    <property name="use_markup">True</property>
-                    <property name="justify">center</property>
-                    <property name="wrap">True</property>
-                    <property name="max_width_chars">50</property>
+                    <child>
+                      <object class="GtkLabel" id="notificationMessage">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="notificationUndoBtn">
+                        <property name="label" translatable="yes">Undo</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="halign">end</property>
+                        <property name="valign">end</property>
+                        <property name="margin_start">18</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="notificationCancelBtn">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="halign">end</property>
+                        <property name="valign">end</property>
+                        <property name="margin_start">8</property>
+                        <property name="relief">none</property>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="icon_name">window-close-symbolic</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
                     <style>
-                      <class name="dim-label"/>
+                      <class name="app-notification"/>
                     </style>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">2</property>
-                  </packing>
                 </child>
               </object>
-              <packing>
-                <property name="name">empty</property>
-                <property name="position">2</property>
-              </packing>
             </child>
           </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
         </child>
       </object>
     </child>
diff --git a/src/recordingsListBox.js b/src/recordingsListBox.js
index f248858a..c21d8d34 100644
--- a/src/recordingsListBox.js
+++ b/src/recordingsListBox.js
@@ -2,7 +2,11 @@
 const { GObject, GstPlayer, Gtk, Gst } = imports.gi;
 const { Row, RowState } = imports.row;
 
-var RecordingsListBox = new GObject.registerClass(class RecordingsListBox extends Gtk.ListBox {
+var RecordingsListBox = new GObject.registerClass({
+    Signals: {
+        'row-deleted': { param_types: [GObject.TYPE_OBJECT, GObject.TYPE_INT] },
+    },
+}, class RecordingsListBox extends Gtk.ListBox {
     _init(model, player) {
         this._player = player;
         super._init({
@@ -76,7 +80,7 @@ var RecordingsListBox = new GObject.registerClass(class RecordingsListBox extend
 
                 const index = row.get_index();
                 this.isolateAt(index, false);
-                model.remove(index);
+                this.emit('row-deleted', row._recording, index);
             });
 
             return row;
@@ -99,7 +103,6 @@ var RecordingsListBox = new GObject.registerClass(class RecordingsListBox extend
         this.activeRow = row;
     }
 
-
     isolateAt(index, expanded) {
         const before = this.get_row_at_index(index - 1);
         const current = this.get_row_at_index(index);
diff --git a/src/row.js b/src/row.js
index 8e281182..5bc9c8b9 100644
--- a/src/row.js
+++ b/src/row.js
@@ -98,6 +98,8 @@ var Row = GObject.registerClass({
             this._waveformStack.visible_child_name = 'loading';
         });
 
+
+        this._duration.label = formatTime(recording.duration / Gst.SECOND);
         recording.connect('notify::duration', () => {
             this._duration.label = formatTime(recording.duration / Gst.SECOND);
         });
@@ -119,11 +121,7 @@ var Row = GObject.registerClass({
 
         this._seekBackward.connect('clicked', _ => this.emit('seek-backward'));
         this._seekForward.connect('clicked', _ => this.emit('seek-forward'));
-
-        this._deleteBtn.connect('clicked', () => {
-            recording.delete();
-            this.emit('deleted');
-        });
+        this._deleteBtn.connect('clicked', () => this.emit('deleted'));
     }
 
     onSaveRecording() {
diff --git a/src/window.js b/src/window.js
index 930f5712..f04105ea 100644
--- a/src/window.js
+++ b/src/window.js
@@ -18,7 +18,7 @@
 *
 */
 
-const { GObject, GstPlayer, Gtk, Handy } = imports.gi;
+const { GLib, GObject, GstPlayer, Gtk, Handy } = imports.gi;
 
 const { Recorder } = imports.recorder;
 const { RecordingList } = imports.recordingList;
@@ -29,7 +29,7 @@ const { WaveForm, WaveType } = imports.waveform;
 
 var Window = GObject.registerClass({
     Template: 'resource:///org/gnome/SoundRecorder/ui/window.ui',
-    InternalChildren: ['recorderTime', 'mainStack', 'recorderBox', 'emptyIcon', 'playbackStack', 
'headerRevealer', 'column'],
+    InternalChildren: ['recorderTime', 'mainStack', 'recorderBox', 'emptyIcon', 'playbackStack', 
'headerRevealer', 'notificationRevealer', 'notificationMessage', 'notificationUndoBtn', 
'notificationCancelBtn', 'column'],
 }, class Window extends Handy.ApplicationWindow {
 
     _init(params) {
@@ -64,6 +64,25 @@ var Window = GObject.registerClass({
         this._recordingList.connect('items-changed', this._refreshView.bind(this));
 
         this._recordingListBox = new RecordingsListBox(this._recordingList, this.player);
+
+        this._recordingListBox.connect('row-deleted', (_listBox, recording, index) => {
+            this._recordingList.remove(index);
+            this.notify(_('"%s" deleted').format(recording.name),
+                _ => recording.delete(),
+                _ => this._recordingList.insert(index, recording),
+            );
+        });
+
+        this._notificationCancelBtn.connect('clicked', _ => {
+            this._notificationRevealer.reveal_child = false;
+            if (this.deleteSignalId && this.deleteSignalId > 0) {
+                GLib.source_remove(this.deleteSignalId);
+                this.deleteSignalId = 0;
+            }
+            this._notificationUndoBtn.disconnect(this.cancelSignalId);
+        });
+
+
         this._column.add(this._recordingListBox);
 
         this._emptyIcon.icon_name = `${pkg.name}-symbolic`;
@@ -120,4 +139,24 @@ var Window = GObject.registerClass({
         else
             this._mainStack.visible_child_name = 'recordings';
     }
+
+    notify(message, callback, cancelCallback) {
+        this._notificationMessage.label = message;
+        this._notificationRevealer.reveal_child = true;
+        this.deleteSignalId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 3, () => {
+            callback();
+            this._notificationRevealer.reveal_child = false;
+            this._notificationUndoBtn.disconnect(this.cancelSignalId);
+        });
+
+        this.cancelSignalId = this._notificationUndoBtn.connect('clicked', _ => {
+            cancelCallback();
+            this._notificationRevealer.reveal_child = false;
+            if (this.deleteSignalId && this.deleteSignalId > 0) {
+                GLib.source_remove(this.deleteSignalId);
+                this.deleteSignalId = 0;
+            }
+            this._notificationUndoBtn.disconnect(this.cancelSignalId);
+        });
+    }
 });


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]