Просмотр исходного кода

Save confirmations and improved dark mode

Billy Barrow 2 лет назад
Родитель
Сommit
c1d9c68a61
3 измененных файлов с 125 добавлено и 5 удалено
  1. 85 0
      src/Editor.vala
  2. 20 1
      src/Editors/MarkdownEditor.vala
  3. 20 4
      src/Editors/MetadataEditor.vala

+ 85 - 0
src/Editor.vala

@@ -72,11 +72,14 @@ namespace Publicate {
             tab_box.append(tab_view);
             leaflet.append(tab_box);
 
+            tab_view.close_page.connect(editor_closing);
+
             save_tab_button = new Button.from_icon_name("document-save-symbolic");
             save_tab_button.clicked.connect(save_tab);
             header.pack_end(save_tab_button);
 
             tab_view.notify["selected-page"].connect(() => select_file_from_tab());
+            window.close_request.connect(app_close_request);
 
             append(leaflet);
         }
@@ -116,6 +119,36 @@ namespace Publicate {
 
         }
 
+        private bool editor_closing(TabPage page) {
+            var editor = (Editors.EditorWidget)page.child;
+            if(editor.has_unsaved_changes && open_editors.has_key(editor.asset_name)) {
+                var prompt = new Adw.MessageDialog(window, "Save Changes?", "This editor has unsaved changes, would you like to save them before closing?");
+                prompt.add_response("cancel", "Cancel");
+                prompt.add_response("discard", "Discard");
+                prompt.add_response("save", "Save");
+                prompt.response.connect(r => {
+                    if(r == "save") {
+                        save_and_close_tab_page.begin(page);
+                    }
+                    else if(r == "discard") {
+                        open_editors.unset(editor.asset_name);
+                        tab_view.close_page(page);
+                        tab_view.close_page_finish(page, true);
+                    }
+                    else {
+                        tab_view.close_page_finish(page, false);
+                    }
+                });
+
+                prompt.present();
+                return Gdk.EVENT_STOP;
+            }
+
+            open_editors.unset(editor.asset_name);
+            tab_view.close_page_finish(page, true);
+            return Gdk.EVENT_STOP;
+        }
+
         private void add_editor(Editors.EditorWidget editor, Ppub.Asset asset) {
             editor.load_asset(publication, asset);
             open_editors.set(asset.name, editor);
@@ -147,6 +180,29 @@ namespace Publicate {
             yield save(to_save);
         }
 
+        private async void save_all() {
+            var to_save = publication.assets.select<Savable>(get_savable_editor_or_asset);
+            yield save(to_save);
+        }
+
+        private Savable get_savable_editor_or_asset(Ppub.Asset asset) {
+            if(open_editors.has_key(asset.name)) {
+                var editor = open_editors[asset.name];
+                if(editor.has_unsaved_changes) {
+                    return (Savable)editor;
+                }
+            }
+            return new SavableAsset(publication, asset);
+        }
+
+        private async void save_and_close_tab_page(TabPage page) {
+            var editor = (Editors.EditorWidget)page.child;
+            var to_save = publication.assets.select<Savable>(a => a.name == editor.asset_name ? (Savable)editor : new SavableAsset(publication, a));
+            yield save(to_save);
+            open_editors.unset(editor.asset_name);
+            tab_view.close_page_finish(page, true);
+        }
+
 
         private void select_file_from_tab() {
             var editor = (Editors.EditorWidget)tab_view.selected_page.child;
@@ -181,5 +237,34 @@ namespace Publicate {
             var mimetype = Ppub.guess_mimetype(file.get_basename(), sample);
             yield add_asset(file.get_basename(), mimetype, stream, compression);
         }
+
+        private bool app_close_request() {
+            if(Invercargill.gte(open_editors.values).any(e => e.has_unsaved_changes)) {
+                var prompt = new Adw.MessageDialog(window, "Save Changes?", "There are editors with unsaved changes, would you like to save them before closing?");
+                prompt.add_response("cancel", "Cancel");
+                prompt.add_response("discard", "Discard");
+                prompt.add_response("save", "Save All");
+                prompt.response.connect(r => {
+                    if(r == "save") {
+                        save_all_and_close.begin();
+                    }
+                    else if(r == "discard") {
+                        open_editors.clear();
+                        window.close();
+                    }
+                });
+                prompt.present();
+                return Gdk.EVENT_STOP;
+            }
+
+            return Gdk.EVENT_PROPAGATE;
+        }
+
+        private async void save_all_and_close() {
+            yield save_all();
+            window.close();
+        }
+
+        
     }
 }

+ 20 - 1
src/Editors/MarkdownEditor.vala

@@ -13,6 +13,7 @@ namespace Publicate.Editors {
         private GtkSource.View text_view;
         private GtkSource.Buffer source_buffer;
         private GtkSource.LanguageManager language_manager;
+        private GtkSource.StyleSchemeManager style_manager;
         
         private ScrolledWindow source_scroller;
         private ScrolledWindow markdown_scroller;
@@ -20,6 +21,8 @@ namespace Publicate.Editors {
         private ViewerWindow window;
         private TabPage page;
 
+        private Gee.HashMap<string, Gdk.Pixbuf> pixbuf_cache = new Gee.HashMap<string, Gdk.Pixbuf>();
+
         public Adw.TabPage tab_page { get {
             return page;
         } }
@@ -47,6 +50,7 @@ namespace Publicate.Editors {
 
             text_view = new GtkSource.View ();
             language_manager = new GtkSource.LanguageManager ();
+            style_manager = new GtkSource.StyleSchemeManager();
             text_view.monospace = true;
             text_view.show_line_numbers = true;
             text_view.auto_indent = true;
@@ -124,7 +128,15 @@ namespace Publicate.Editors {
             image.content_fit = Gtk.ContentFit.FILL;
             widget.append (image);
 
-            var pixbuf = yield new Gdk.Pixbuf.from_stream_async (publication.read_asset (file), null);
+            Gdk.Pixbuf pixbuf;
+            if(pixbuf_cache.has_key(file)) {
+                pixbuf = pixbuf_cache[file];
+            }
+            else {
+                pixbuf = yield new Gdk.Pixbuf.from_stream_async (publication.read_asset (file), null);
+                pixbuf_cache.set(file, pixbuf);
+            }
+
             image.set_pixbuf (pixbuf);
 
             widget.available_width_changed.connect(wid => {
@@ -138,6 +150,13 @@ namespace Publicate.Editors {
         private void configure_tags() {
             var link = new LinkButton("");
             markdown_view.tag_manager.update_link_colour(link.get_color());
+
+            if(Gtk.Settings.get_default().gtk_application_prefer_dark_theme) {
+                source_buffer.style_scheme = style_manager.get_scheme("Adwaita-dark");
+            }
+            else {
+                source_buffer.style_scheme = style_manager.get_scheme("Adwaita");
+            }
         }
 
         private void update_preview() {

+ 20 - 4
src/Editors/MetadataEditor.vala

@@ -51,28 +51,33 @@ namespace Publicate.Editors {
 
             title = new EntryRow ();
             title.title = "Title";
-            title.changed.connect (() => metadata.title = title.text);
+            title.changed.connect (something_changed);
             group.add(title);
 
             author = new EntryRow ();
             author.title = "Author";
+            author.changed.connect (something_changed);
             group.add(author);
 
             author_email = new EntryRow ();
             author_email.title = "Author Email";
+            author_email.changed.connect (something_changed);
             group.add(author_email);
 
             poster = new FileChooserRow (window);
             poster.title = "Poster Image";
+            poster.asset_selected.connect (something_changed);
             group.add(poster);
 
             description = new EntryRow ();
             description.enable_emoji_completion = true;
             description.title = "Description";
+            description.changed.connect (something_changed);
             group.add(description);
 
             tags = new EntryRow ();
             tags.title = "Tags (space separated)";
+            tags.changed.connect (something_changed);
             group.add(tags);
 
             box.append(group);
@@ -87,16 +92,17 @@ namespace Publicate.Editors {
 
             copyright = new EntryRow ();
             copyright.title = "Copyright Notice";
+            copyright.changed.connect (something_changed);
             group2.add(copyright);
 
             licence = new FileChooserRow (window);
             licence.title = "Licence";
+            licence.asset_selected.connect (something_changed);
             group2.add(licence);
 
             box.append(group2);
 
             this.page = tab_view.add_page (this, null);
-            this.page.title = "Publication Metadata";
         }
 
         public async void load_asset (Ppub.Publication publication, Ppub.Asset asset) {
@@ -119,7 +125,7 @@ namespace Publicate.Editors {
             copyright.text = metadata.copyright ?? "";
             licence.set_selected_item (metadata.licence ?? "");
 
-
+            set_changed(false);
         }
 
         public string asset_name { get {
@@ -155,7 +161,7 @@ namespace Publicate.Editors {
             metadata.copyright = process_string(copyright.text);
             metadata.licence = process_string (licence.selected_asset);
 
-            // TODO, this should probably done on every save?
+            // TODO, this should probably done on every save globally?
             metadata.date = new DateTime.now_local();
 
             var stream = new MemoryInputStream.from_data((uint8[])metadata.to_string().to_utf8());
@@ -163,6 +169,16 @@ namespace Publicate.Editors {
             stream.seek(0, SeekType.SET);
 
             builder.add_asset(asset.name, asset.mimetype, stream, Invercargill.empty<string>(), compression_info);
+            set_changed(false);
+        }
+
+        private void set_changed(bool changed) {
+            this.page.title = changed ? "⏺  Publication Metadata" : "Publication Metadata";
+            unsaved = changed;
+        }
+
+        private void something_changed() {
+            set_changed(true);
         }
     }