Skip to content

Commit acb8eb8

Browse files
committed
Add Nextcloud-style folder sync for notes and media
- Implement two-way folder sync for tags, entries, and media files - Add sync settings UI for enabling sync and choosing folder - Store images in app media directory and sync referenced files - Support manual sync, pull, and media cleanup from settings - Normalize image paths for portability and cross-device sync
1 parent 4c8911b commit acb8eb8

5 files changed

Lines changed: 809 additions & 19 deletions

File tree

src/Window.vala

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ namespace Notejot {
44
{ "edit-entry", on_edit_entry_clicked },
55
{ "delete-entry", on_delete_entry_clicked },
66
{ "restore-entry", on_restore_entry_clicked },
7+
{ "sync-now", on_sync_now_clicked },
78
};
89
private DataManager data_manager;
910
private InsightsView insights_view;
@@ -15,6 +16,7 @@ namespace Notejot {
1516
private EntriesView entries_view;
1617
private EmptyStateView empty_state_view;
1718
private DeletedEmptyStateView deleted_empty_state_view;
19+
private SettingsWindow? settings_window;
1820

1921
private string? current_tag_uuid = null; // null means "All Entries" here
2022
private Entry? selected_entry = null; // Track the currently selected entry
@@ -26,24 +28,34 @@ namespace Notejot {
2628

2729
this.set_default_size (1024, 800);
2830

29-
var main_paned = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
30-
this.set_child (main_paned);
31+
var main_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
32+
this.set_child (main_box);
3133

3234
// --- Sidebar ---
3335
this.sidebar = new Sidebar (this.data_manager);
3436
this.sidebar.tag_selected.connect (on_tag_selected);
3537
this.sidebar.add_tag_clicked.connect (on_add_tag_clicked);
3638
this.sidebar.settings_clicked.connect (() => {
37-
var win = new SettingsWindow (this);
38-
win.present ();
39+
if (this.settings_window == null) {
40+
this.settings_window = new SettingsWindow (this, this.data_manager);
41+
if (app != null) {
42+
this.settings_window.set_application (app);
43+
app.add_window (this.settings_window);
44+
}
45+
this.settings_window.close_request.connect (() => {
46+
this.settings_window = null;
47+
return false;
48+
});
49+
}
50+
this.settings_window.present ();
3951
});
4052
this.sidebar.view_switched.connect (switch_to_view);
41-
main_paned.append (this.sidebar);
53+
main_box.append (this.sidebar);
4254

4355
// --- Main Content Area Container ---
4456
this.main_content_container = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
4557
this.main_content_container.set_hexpand (true);
46-
main_paned.append (this.main_content_container);
58+
main_box.append (this.main_content_container);
4759

4860
// --- Main Content Views ---
4961
this.entries_view = new EntriesView (this.data_manager);
@@ -290,10 +302,27 @@ namespace Notejot {
290302
}
291303
existing.location_address = address;
292304
existing.modified_timestamp = new GLib.DateTime.now_utc ().to_unix ();
293-
// Rebuild image_paths to match editor selection and avoid duplicates
305+
// Rebuild and normalize image_paths: import to app media dir and store absolute paths
294306
existing.image_paths = new GLib.List<string> ();
307+
var app_dir = GLib.Path.build_filename (GLib.Environment.get_user_data_dir (), "io.github.lainsce.Notejot");
308+
var media_dir = GLib.Path.build_filename (app_dir, "media");
309+
GLib.DirUtils.create_with_parents (media_dir, 0755);
295310
foreach (var p in this.entry_editor_view.image_paths) {
296-
existing.image_paths.append (p);
311+
if (p == null || p.strip () == "")continue;
312+
string final_path = p;
313+
try {
314+
var file_base = GLib.Path.get_basename (p);
315+
var dest = GLib.Path.build_filename (media_dir, existing.uuid + "_" + file_base);
316+
var srcf = File.new_for_path (p);
317+
var dstf = File.new_for_path (dest);
318+
// Always overwrite to ensure the latest edit is saved in media dir
319+
srcf.copy (dstf, FileCopyFlags.OVERWRITE, null, null);
320+
final_path = dest;
321+
} catch (Error e) {
322+
// If copy fails, fall back to original path
323+
final_path = p;
324+
}
325+
existing.image_paths.append (final_path);
297326
}
298327
save_entry_with_geocode.begin (existing, false);
299328
}
@@ -440,6 +469,13 @@ namespace Notejot {
440469
this.update_stats ();
441470
}
442471

472+
private void on_sync_now_clicked () {
473+
this.data_manager.sync_push ();
474+
this.refresh_sidebar_tags ();
475+
this.refresh_entry_list ();
476+
this.update_stats ();
477+
}
478+
443479
public void open_new_entry () {
444480
// Don't allow adding entries when in "Recently Deleted" section
445481
if (this.current_tag_uuid == "deleted") {

0 commit comments

Comments
 (0)