Skip to content
Draft
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
10 changes: 10 additions & 0 deletions data/io.elementary.code.gschema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -244,4 +244,14 @@
<description>Opened folders that should be restored in startup.</description>
</key>
</schema>

<!--Relocatable schema for per project info-->
<schema id="io.elementary.code.Projects">
<key name="expanded" type="b">
<default>false</default>
<summary>Project Folder expanded</summary>
<description>Whether the project folder in the sidebar should be expanded on loading</description>
</key>
</schema>

</schemalist>
36 changes: 19 additions & 17 deletions src/FolderManager/ProjectFolderItem.vala
Original file line number Diff line number Diff line change
Expand Up @@ -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<span size='small' weight='normal'>%s</span>".printf (
name, monitored_repo.branch_name
);
} else { //Distinguish detached heads visually
markup = "%s\n <span size='small' weight='normal' style='italic'>%s</span>".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);
Expand All @@ -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<span size='small' weight='normal'>%s</span>".printf (
name, monitored_repo.branch_name
);
} else { //Distinguish detached heads visually
markup = "%s\n <span size='small' weight='normal' style='italic'>%s</span>".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) {
Expand Down
75 changes: 75 additions & 0 deletions src/FolderManager/ProjectInfoManager.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2026 elementary, Inc. <https://elementary.io>
*
* Authored by: Jeremy Wootten <jeremywootten@gmail.com>
*/

// 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<string, ProjectInfo>? map = null;
private static Gee.HashMap<string, ProjectInfo> project_info_map {
get {
if (map == null) {
map = new Gee.HashMap<string, ProjectInfo> ();
}

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;
}
}
}
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down