diff --git a/data/io.elementary.code.gschema.xml b/data/io.elementary.code.gschema.xml
index 0cfce65a0..956f94d1d 100644
--- a/data/io.elementary.code.gschema.xml
+++ b/data/io.elementary.code.gschema.xml
@@ -244,4 +244,14 @@
Opened folders that should be restored in startup.
+
+
+
+
+ false
+ Project Folder expanded
+ Whether the project folder in the sidebar should be expanded on loading
+
+
+
diff --git a/src/FolderManager/ProjectFolderItem.vala b/src/FolderManager/ProjectFolderItem.vala
index 996fcd908..7d7a3792f 100644
--- a/src/FolderManager/ProjectFolderItem.vala
+++ b/src/FolderManager/ProjectFolderItem.vala
@@ -56,23 +56,6 @@ namespace Scratch.FolderManager {
modified_icon = new ThemedIcon ("emblem-git-modified-symbolic");
}
- private void branch_or_name_changed () {
- if (monitored_repo != null) {
- //As SourceList items are not widgets we have to use markup to change appearance of text.
- if (monitored_repo.head_is_branch) {
- markup = "%s\n%s".printf (
- name, monitored_repo.branch_name
- );
- } else { //Distinguish detached heads visually
- markup = "%s\n %s".printf (
- name, monitored_repo.branch_name
- );
- }
-
- checkout_local_branch_action.set_state (monitored_repo.branch_name);
- }
- }
-
construct {
monitored_repo = Scratch.Services.GitManager.get_instance ().add_project (this);
notify["name"].connect (branch_or_name_changed);
@@ -95,6 +78,25 @@ namespace Scratch.FolderManager {
checkout_local_branch_action.activate.connect (handle_checkout_local_branch_action);
checkout_remote_branch_action.activate.connect (handle_checkout_remote_branch_action);
}
+
+ ProjectInfoManager.get_project_info (this);
+ }
+
+ private void branch_or_name_changed () {
+ if (monitored_repo != null) {
+ //As SourceList items are not widgets we have to use markup to change appearance of text.
+ if (monitored_repo.head_is_branch) {
+ markup = "%s\n%s".printf (
+ name, monitored_repo.branch_name
+ );
+ } else { //Distinguish detached heads visually
+ markup = "%s\n %s".printf (
+ name, monitored_repo.branch_name
+ );
+ }
+
+ checkout_local_branch_action.set_state (monitored_repo.branch_name);
+ }
}
protected override void on_changed (GLib.File source, GLib.File? dest, GLib.FileMonitorEvent event) {
diff --git a/src/FolderManager/ProjectInfoManager.vala b/src/FolderManager/ProjectInfoManager.vala
new file mode 100644
index 000000000..7b687b3f4
--- /dev/null
+++ b/src/FolderManager/ProjectInfoManager.vala
@@ -0,0 +1,75 @@
+/*
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * SPDX-FileCopyrightText: 2026 elementary, Inc.
+ *
+ * Authored by: Jeremy Wootten
+ */
+
+// Using static methods unless we find we require singleton
+// We keep a separate list of project infos for future use in e.g. recently closed project list
+// and for re-opening projects without recreating info object
+public class Scratch.FolderManager.ProjectInfoManager : Object {
+ private class ProjectInfo : Object {
+ const string PROJECT_INFO_SCHEMA_ID = "io.elementary.code.Projects";
+ const string PROJECT_INFO_SCHEMA_PATH_PREFIX = "/io/elementary/code/Projects/";
+ public string path {
+ owned get {
+ return project.path;
+ }
+ }
+
+ public ProjectFolderItem project { get; construct; }
+ private Settings settings;
+
+ public ProjectInfo (ProjectFolderItem project) {
+ Object (
+ project: project
+ );
+ }
+
+ construct {
+ var settings_path = PROJECT_INFO_SCHEMA_PATH_PREFIX +
+ schema_name_from_path (path) +
+ Path.DIR_SEPARATOR_S;
+
+ settings = new Settings.with_path (
+ PROJECT_INFO_SCHEMA_ID,
+ settings_path
+ );
+
+ settings.bind ("expanded", project, "expanded", DEFAULT);
+ }
+
+ //Combine basename and parent folder name and convert to camelcase
+ private string schema_name_from_path (string path) {
+ var dir = Path.get_basename (Path.get_dirname (path)).normalize ();
+ var basename = Path.get_basename (path).normalize ();
+ var name = dir.substring (0, 1).up () +
+ dir.substring (1, -1).down () +
+ basename.substring (0, 1).up () +
+ basename.substring (1, -1).down ();
+
+ return name;
+ }
+ }
+
+ private static Gee.HashMap? map = null;
+ private static Gee.HashMap project_info_map {
+ get {
+ if (map == null) {
+ map = new Gee.HashMap ();
+ }
+
+ return map;
+ }
+ }
+
+ //Called when folder created
+ public static void get_project_info (ProjectFolderItem project_folder) {
+ var info = project_info_map[project_folder.path];
+ if (info == null) {
+ info = new ProjectInfo (project_folder);
+ project_info_map[project_folder.path] = info;
+ }
+ }
+}
diff --git a/src/meson.build b/src/meson.build
index b5a5aca59..2b01d3ec5 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -31,6 +31,7 @@ code_files = files(
'FolderManager/FolderItem.vala',
'FolderManager/Item.vala',
'FolderManager/ProjectFolderItem.vala',
+ 'FolderManager/ProjectInfoManager.vala',
'Services/CommentToggler.vala',
'Services/Document.vala',
'Services/DocumentManager.vala',