Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions data/ui/notes.ui
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@
<attribute name="label" translatable="yes">Keyboard Shortcuts</attribute>
<attribute name="action">win.show-help-overlay</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Import Notes…</attribute>
<attribute name="action">app.import</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Export All Notes…</attribute>
<attribute name="action">app.export</attribute>
</item>
<item>
<attribute name="label" translatable="yes">About Sticky Notes</attribute>
<attribute name="action">app.about</attribute>
Expand Down
21 changes: 21 additions & 0 deletions po/pt_BR.po
Original file line number Diff line number Diff line change
Expand Up @@ -504,3 +504,24 @@ msgstr "Nota vazia"

#~ msgid "First beta release!"
#~ msgstr "Primeiro lançamento beta!"

#: src/application.ts:552
msgid "Export Notes"
msgstr "Exportar notas"

#: src/application.ts:581
msgid "Failed to Export Notes"
msgstr "Falha ao exportar notas"

#: src/application.ts:584 src/application.ts:613
msgid "OK"
msgstr "OK"

#: src/application.ts:592
msgid "Import Notes"
msgstr "Importar notas"

#: src/application.ts:610
msgid "Failed to Import Notes"
msgstr "Falha ao importar notas"

91 changes: 90 additions & 1 deletion src/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import Gtk from "gi://Gtk?version=4.0";
import Gdk from "gi://Gdk?version=4.0";

import { StickyNotes } from "./notes.js";
import { Note, settings } from "./util.js";
import { INote, Note, settings } from "./util.js";
import {
delete_note,
load_notes,
Expand Down Expand Up @@ -293,6 +293,14 @@ export class Application extends Adw.Application {
save.connect("activate", () => this.save());
this.add_action(save);

const export_notes = new Gio.SimpleAction({ name: "export" });
export_notes.connect("activate", () => this.export_notes());
this.add_action(export_notes);

const import_notes = new Gio.SimpleAction({ name: "import" });
import_notes.connect("activate", () => this.import_notes());
this.add_action(import_notes);

this.add_action(settings.create_action("color-scheme"));

this.set_accels_for_action("app.quit", ["<Primary>q"]);
Expand Down Expand Up @@ -539,6 +547,87 @@ export class Application extends Adw.Application {
window.present();
}

async export_notes() {
const dialog = new Gtk.FileDialog({
title: _("Export Notes"),
initial_name: "notes.json",
});

try {
const file = await dialog.save(this.active_window, null);
if (!file) return;

const notes = this.notes_array();
const data = {
v: 1,
notes: notes.map((n) => n.toJSON()),
};
const encoder = new TextEncoder();
file.replace_contents(
encoder.encode(JSON.stringify(data, null, 2)),
null,
false,
Gio.FileCreateFlags.NONE,
null,
);
} catch (err) {
if (err instanceof GLib.Error && err.matches(Gio.io_error_quark(), Gio.IOErrorEnum.CANCELLED)) {
return;
}
console.error("Failed to export notes:", err);
Comment thread
paulowender marked this conversation as resolved.
const error_dialog = Adw.MessageDialog.new(
this.active_window,
_("Failed to Export Notes"),
err instanceof Error ? err.message : String(err)
);
error_dialog.add_response("ok", _("OK"));
error_dialog.present();
}
}

async import_notes() {
const dialog = new Gtk.FileDialog({
title: _("Import Notes"),
});

try {
const file = await dialog.open(this.active_window, null);
if (!file) return;

const [success, contents] = file.load_contents(null);
if (!success) return;

const decoder = new TextDecoder();
const data = JSON.parse(decoder.decode(contents));

if (data.v !== 1 || !Array.isArray(data.notes)) return;

data.notes.forEach((noteData: INote) => {
// Avoid duplicates by UUID
if (!this.find_note(noteData.uuid)) {
const note = new Note(noteData);
note.connect("notify::modified", () => save_note(note));
note.connect("notify::open", () => save_note(note));
this.notes_list.append(note);
save_note(note);
}
});
this.sort_notes();
} catch (err) {
if (err instanceof GLib.Error && err.matches(Gio.io_error_quark(), Gio.IOErrorEnum.CANCELLED)) {
return;
}
console.error("Failed to import notes:", err);
Comment thread
paulowender marked this conversation as resolved.
const error_dialog = Adw.MessageDialog.new(
this.active_window,
_("Failed to Import Notes"),
err instanceof Error ? err.message : String(err)
);
error_dialog.add_response("ok", _("OK"));
error_dialog.present();
}
}

vfunc_startup() {
super.vfunc_startup();

Expand Down
3 changes: 3 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ Gio._promisify(
"replace_contents_finish",
);

Gio._promisify(Gtk.FileDialog.prototype, "save", "save_finish");
Gio._promisify(Gtk.FileDialog.prototype, "open", "open_finish");

export interface ITag {
name: string;
start: number;
Expand Down