fix(ui): finish refresh and diff navigation polish

This commit is contained in:
2026-06-19 00:36:53 -05:00
parent 1c730302d5
commit 76634c3fd3
2 changed files with 95 additions and 64 deletions

View File

@@ -1,73 +1,72 @@
#pragma once
#include "models/repository.h"
#include <string>
#include <vector>
class GitManager
{
public:
#pragma once
#include "models/repository.h"
#include <string>
#include <vector>
class GitManager
{
public:
GitManager();
~GitManager();
bool openRepositoryHandle(RepositoryView &repository, const std::string &path, std::string &error);
bool openRepositoryHandle(RepositoryView &repository, const std::string &path, std::string &error);
bool openRepository(RepositoryView &repository, const std::string &path, std::string &error);
bool initializeRepository(RepositoryView &repository, const std::string &path,
const std::string &initial_branch, std::string &error);
bool cloneRepository(RepositoryView &repository, const std::string &url,
const std::string &path, bool shallow, std::string &error);
bool reload(RepositoryView &repository, std::string &error);
bool cloneRepository(RepositoryView &repository, const std::string &url,
const std::string &path, bool shallow, std::string &error);
bool reload(RepositoryView &repository, std::string &error);
bool loadMoreCommits(RepositoryView &repository, size_t page_size, std::string &error);
bool checkoutBranch(RepositoryView &repository, const std::string &branch, std::string &error);
bool mergeBranch(RepositoryView &repository, const std::string &source_branch,
const std::string &target_branch, std::string &error);
bool fetch(RepositoryView &repository, const std::string &remote, std::string &error);
bool pull(RepositoryView &repository, int mode, std::string &error);
bool push(RepositoryView &repository, std::string &error);
bool pushBranch(RepositoryView &repository, const std::string &branch, std::string &error);
bool stash(RepositoryView &repository, std::string &error);
bool popStash(RepositoryView &repository, std::string &error);
bool undoCommit(RepositoryView &repository, std::string &error);
bool redoCommit(RepositoryView &repository, std::string &error);
bool stageAll(RepositoryView &repository, std::string &error);
bool unstageAll(RepositoryView &repository, std::string &error);
bool stageFile(RepositoryView &repository, const std::string &path, std::string &error);
bool unstageFile(RepositoryView &repository, const std::string &path, std::string &error);
bool discardFile(RepositoryView &repository, const std::string &path, std::string &error);
bool discardAll(RepositoryView &repository, std::string &error);
bool commit(RepositoryView &repository, const std::string &summary,
const std::string &description, bool amend, std::string &error);
bool createBranch(RepositoryView &repository, const std::string &name,
const std::string &start_point, bool checkout, std::string &error);
bool createTag(RepositoryView &repository, const std::string &name,
const std::string &target, std::string &error);
bool addRemote(RepositoryView &repository, const std::string &name,
const std::string &url, std::string &error);
bool addWorktree(RepositoryView &repository, const std::string &path,
const std::string &branch, std::string &error);
bool addSubmodule(RepositoryView &repository, const std::string &url,
const std::string &path, std::string &error);
bool updateSubmodule(RepositoryView &repository, const std::string &name, std::string &error);
std::string worktreePath(RepositoryView &repository, const std::string &name, std::string &error);
bool loadCommitChanges(RepositoryView &repository, int commit_index, std::string &error);
bool loadCommitFiles(RepositoryView &repository, int commit_index, std::string &error);
bool captureGit(RepositoryView &repository, const std::vector<std::string> &arguments,
std::string &output, std::string &error);
bool applyPatch(RepositoryView &repository, const std::string &patch, bool cached,
bool reverse, std::string &error);
private:
static std::string lastError(const char *fallback);
static std::string formatTime(git_time_t value, int offset_minutes);
void loadToolbarHistoryActions(RepositoryView &repository);
void readBranches(RepositoryView &repository, git_branch_t type, std::vector<std::string> &output);
void loadBranchDivergence(RepositoryView &repository);
void loadRefBadges(RepositoryView &repository);
void computeGraphLanes(RepositoryView &repository);
bool loadRepositoryData(RepositoryView &repository, std::string &error);
void loadWorkingTree(RepositoryView &repository);
bool prepareCredentials(RepositoryView &repository, std::string &error);
bool runGit(RepositoryView &repository, const std::vector<std::string> &arguments,
const char *success_message, std::string &message, bool reload = true);
};
bool pull(RepositoryView &repository, int mode, std::string &error);
bool push(RepositoryView &repository, std::string &error);
bool pushBranch(RepositoryView &repository, const std::string &branch, std::string &error);
bool stash(RepositoryView &repository, std::string &error);
bool popStash(RepositoryView &repository, std::string &error);
bool undoCommit(RepositoryView &repository, std::string &error);
bool redoCommit(RepositoryView &repository, std::string &error);
bool stageAll(RepositoryView &repository, std::string &error);
bool unstageAll(RepositoryView &repository, std::string &error);
bool stageFile(RepositoryView &repository, const std::string &path, std::string &error);
bool unstageFile(RepositoryView &repository, const std::string &path, std::string &error);
bool discardFile(RepositoryView &repository, const std::string &path, std::string &error);
bool discardAll(RepositoryView &repository, std::string &error);
bool commit(RepositoryView &repository, const std::string &summary,
const std::string &description, bool amend, std::string &error);
bool createBranch(RepositoryView &repository, const std::string &name,
const std::string &start_point, bool checkout, std::string &error);
bool createTag(RepositoryView &repository, const std::string &name,
const std::string &target, std::string &error);
bool addRemote(RepositoryView &repository, const std::string &name,
const std::string &url, std::string &error);
bool addWorktree(RepositoryView &repository, const std::string &path,
const std::string &branch, std::string &error);
bool addSubmodule(RepositoryView &repository, const std::string &url,
const std::string &path, std::string &error);
bool updateSubmodule(RepositoryView &repository, const std::string &name, std::string &error);
std::string worktreePath(RepositoryView &repository, const std::string &name, std::string &error);
bool loadCommitChanges(RepositoryView &repository, int commit_index, std::string &error);
bool loadCommitFiles(RepositoryView &repository, int commit_index, std::string &error);
bool captureGit(RepositoryView &repository, const std::vector<std::string> &arguments,
std::string &output, std::string &error);
bool applyPatch(RepositoryView &repository, const std::string &patch, bool cached,
bool reverse, std::string &error);
private:
static std::string lastError(const char *fallback);
static std::string formatTime(git_time_t value, int offset_minutes);
void loadToolbarHistoryActions(RepositoryView &repository);
void readBranches(RepositoryView &repository, git_branch_t type, std::vector<std::string> &output);
void loadBranchDivergence(RepositoryView &repository);
void loadRefBadges(RepositoryView &repository);
void computeGraphLanes(RepositoryView &repository);
bool loadRepositoryData(RepositoryView &repository, std::string &error);
void loadWorkingTree(RepositoryView &repository);
bool prepareCredentials(RepositoryView &repository, std::string &error);
bool runGit(RepositoryView &repository, const std::vector<std::string> &arguments,
const char *success_message, std::string &message, bool reload = true);
};

View File

@@ -48,6 +48,8 @@ AvatarCache* g_avatar_cache = nullptr;
std::array<char, 256> g_filter{};
std::array<char, 128> g_branch_filter{};
std::string g_notice;
std::string g_last_footer_notice;
std::chrono::steady_clock::time_point g_last_footer_notice_change{};
bool g_init_popup = false;
bool g_clone_popup = false;
bool g_about_popup = false;
@@ -304,6 +306,26 @@ void sync_notice_toast() {
push_toast(g_notice, infer_toast_kind(g_notice));
}
float footer_notice_alpha() {
if (g_notice.empty()) {
g_last_footer_notice.clear();
return 0.0f;
}
if (g_notice != g_last_footer_notice) {
g_last_footer_notice = g_notice;
g_last_footer_notice_change = RefreshClock::now();
}
if (g_notice.ends_with("...")) return 1.0f;
constexpr float notice_hold_seconds = 2.0f;
constexpr float notice_fade_seconds = 1.5f;
const float elapsed = std::chrono::duration<float>(
RefreshClock::now() - g_last_footer_notice_change).count();
if (elapsed <= notice_hold_seconds) return 1.0f;
if (elapsed >= notice_hold_seconds + notice_fade_seconds) return 0.0f;
return 1.0f - ((elapsed - notice_hold_seconds) / notice_fade_seconds);
}
void transfer_repository_state(RepositoryView& source, RepositoryView& target) {
if (&source == &target) return;
target.close();
@@ -381,8 +403,8 @@ GitAsyncResult execute_git_async_request(const GitAsyncRequest& request) {
bool action_ok = true;
switch (request.operation) {
case GitAsyncOperation::reload:
break;
action_ok = manager.reload(repository, result.notice);
break;
case GitAsyncOperation::capture: {
std::string output;
action_ok = manager.captureGit(repository, request.arguments, output, result.notice) &&
@@ -3528,7 +3550,17 @@ void draw_popups() {
void draw_footer() {
ImGui::Separator();
ImGui::TextDisabled("%s", g_notice.empty() ? "Ready" : g_notice.c_str());
const float notice_alpha = footer_notice_alpha();
const bool show_notice = !g_notice.empty() && notice_alpha > 0.02f;
if (show_notice) {
ImVec4 notice_color = ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled);
notice_color.w *= notice_alpha;
ImGui::PushStyleColor(ImGuiCol_TextDisabled, notice_color);
ImGui::TextDisabled("%s", g_notice.c_str());
ImGui::PopStyleColor();
} else {
ImGui::TextDisabled("Ready");
}
const char* version = "Gitree " GITREE_VERSION;
const std::string zoom_label = std::string(ICON_TB_MAGNIFYING_GLASS " ") +
std::to_string(g_zoom_percent) + "%";
@@ -4044,7 +4076,7 @@ int runGitree(int argc, char** argv) {
for (const std::string& path : user_data.openRepositories()) {
g_tabs.push_back(std::make_unique<RepositoryView>());
if (!path.empty() && git_manager.openRepositoryHandle(*g_tabs.back(), path, g_notice))
g_tabs.back()->pending_background_refresh = true;
g_tabs.back()->pending_background_refresh = true;
}
g_active_tab = std::min(user_data.activeRepository(), g_tabs.size() - 1);
g_tab_to_select = g_tabs[g_active_tab].get();