9#include "absl/strings/str_format.h"
10#include "imgui/imgui.h"
18 version_mgr_(nullptr),
19 approval_mgr_(nullptr),
21 selected_rom_sync_(-1),
22 selected_snapshot_(-1),
23 selected_proposal_(-1),
24 show_sync_details_(false),
25 show_snapshot_preview_(true),
27 filter_pending_only_(false) {
32 colors_.sync_applied = ImVec4(0.2f, 0.8f, 0.2f, 1.0f);
33 colors_.sync_pending = ImVec4(0.8f, 0.8f, 0.2f, 1.0f);
34 colors_.sync_error = ImVec4(0.8f, 0.2f, 0.2f, 1.0f);
35 colors_.proposal_pending = ImVec4(0.7f, 0.7f, 0.7f, 1.0f);
36 colors_.proposal_approved = ImVec4(0.2f, 0.8f, 0.2f, 1.0f);
37 colors_.proposal_rejected = ImVec4(0.8f, 0.3f, 0.3f, 1.0f);
38 colors_.proposal_applied = ImVec4(0.2f, 0.6f, 0.8f, 1.0f);
44 if (snapshot.texture_id) {
47 snapshot.texture_id =
nullptr;
61 if (!ImGui::Begin(
"Collaboration", p_open, ImGuiWindowFlags_None)) {
67 if (ImGui::BeginTabBar(
"CollaborationTabs")) {
68 if (ImGui::BeginTabItem(tr(
"ROM Sync"))) {
74 if (ImGui::BeginTabItem(tr(
"Version History"))) {
80 if (ImGui::BeginTabItem(tr(
"Snapshots"))) {
86 if (ImGui::BeginTabItem(tr(
"Proposals"))) {
92 if (ImGui::BeginTabItem(tr(
"đ Approvals"))) {
105 ImGui::TextWrapped(tr(
"ROM Synchronization History"));
109 if (ImGui::Button(tr(
"Clear History"))) {
120 int applied_count = 0;
121 int pending_count = 0;
127 else if (!sync.error_message.empty())
133 ImGui::Text(tr(
"Total: %zu | "),
rom_syncs_.size());
135 ImGui::TextColored(
colors_.sync_applied, tr(
"Applied: %d"), applied_count);
137 ImGui::TextColored(
colors_.sync_pending, tr(
"Pending: %d"), pending_count);
139 ImGui::TextColored(
colors_.sync_error, tr(
"Errors: %d"), error_count);
144 if (ImGui::BeginChild(
"SyncList", ImVec2(0, 0),
true)) {
145 for (
size_t i = 0; i <
rom_syncs_.size(); ++i) {
149 if (
auto_scroll_ && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
150 ImGui::SetScrollHereY(1.0f);
157 ImGui::TextWrapped(tr(
"Shared Snapshots Gallery"));
161 if (ImGui::Button(tr(
"Clear Gallery"))) {
172 if (ImGui::BeginChild(
"SnapshotGrid", ImVec2(0, 0),
true)) {
173 float thumbnail_size = 150.0f;
174 float padding = 10.0f;
175 float cell_size = thumbnail_size + padding;
178 std::max(1, (
int)((ImGui::GetContentRegionAvail().x) / cell_size));
180 for (
size_t i = 0; i <
snapshots_.size(); ++i) {
184 std::string sender_lower =
snapshots_[i].sender;
185 std::transform(search_lower.begin(), search_lower.end(),
186 search_lower.begin(), ::tolower);
187 std::transform(sender_lower.begin(), sender_lower.end(),
188 sender_lower.begin(), ::tolower);
190 if (sender_lower.find(search_lower) == std::string::npos &&
191 snapshots_[i].snapshot_type.find(search_lower) ==
200 if ((i + 1) % columns != 0 && i <
snapshots_.size() - 1) {
209 ImGui::TextWrapped(tr(
"AI Proposals & Suggestions"));
213 if (ImGui::Button(tr(
"Clear All"))) {
224 int pending = 0, approved = 0, rejected = 0, applied = 0;
226 if (proposal.status ==
"pending")
228 else if (proposal.status ==
"approved")
230 else if (proposal.status ==
"rejected")
232 else if (proposal.status ==
"applied")
236 ImGui::Text(tr(
"Total: %zu"),
proposals_.size());
238 ImGui::TextColored(
colors_.proposal_pending, tr(
" | Pending: %d"), pending);
240 ImGui::TextColored(
colors_.proposal_approved, tr(
" | Approved: %d"),
243 ImGui::TextColored(
colors_.proposal_rejected, tr(
" | Rejected: %d"),
246 ImGui::TextColored(
colors_.proposal_applied, tr(
" | Applied: %d"), applied);
251 if (ImGui::BeginChild(
"ProposalList", ImVec2(0, 0),
true)) {
252 for (
size_t i = 0; i <
proposals_.size(); ++i) {
260 std::string sender_lower =
proposals_[i].sender;
261 std::string desc_lower =
proposals_[i].description;
262 std::transform(search_lower.begin(), search_lower.end(),
263 search_lower.begin(), ::tolower);
264 std::transform(sender_lower.begin(), sender_lower.end(),
265 sender_lower.begin(), ::tolower);
266 std::transform(desc_lower.begin(), desc_lower.end(), desc_lower.begin(),
269 if (sender_lower.find(search_lower) == std::string::npos &&
270 desc_lower.find(search_lower) == std::string::npos) {
283 ImGui::PushID(index);
287 const char* status_icon;
290 status_color =
colors_.sync_applied;
291 status_icon =
"[â]";
293 status_color =
colors_.sync_error;
294 status_icon =
"[â]";
296 status_color =
colors_.sync_pending;
297 status_icon =
"[âˇ]";
300 ImGui::TextColored(status_color,
"%s", status_icon);
310 ImGui::TextWrapped(tr(
"ROM Hash: %s"),
311 entry.
rom_hash.substr(0, 16).c_str());
313 ImGui::TextColored(
colors_.sync_error, tr(
"Error: %s"),
325 ImGui::PushID(index);
331 ImGui::Image(entry.
texture_id, ImVec2(150, 150));
334 ImGui::BeginChild(
"SnapshotPlaceholder", ImVec2(150, 150),
true);
335 ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 50);
341 ImGui::TextWrapped(
"%s", entry.
sender.c_str());
346 if (ImGui::SmallButton(tr(
"View"))) {
351 if (ImGui::SmallButton(tr(
"Export"))) {
362 ImGui::PushID(index);
368 ImGui::TextColored(color,
"%s", icon);
372 bool is_open = ImGui::TreeNode(entry.
description.c_str());
377 ImGui::Text(tr(
"From: %s"), entry.
sender.c_str());
379 ImGui::Text(tr(
"Status: %s"), entry.
status.c_str());
387 if (entry.
status ==
"pending") {
389 if (ImGui::Button(tr(
"â Approve"))) {
393 if (ImGui::Button(tr(
"â Reject"))) {
397 if (ImGui::Button(tr(
"âļ Apply Now"))) {
423 const std::string& status) {
425 if (proposal.proposal_id == proposal_id) {
426 proposal.status = status;
440 if (proposal.proposal_id == proposal_id) {
448 std::time_t time = timestamp / 1000;
449 std::tm* tm = std::localtime(&time);
452 std::strftime(buffer,
sizeof(buffer),
"%H:%M:%S", tm);
453 return std::string(buffer);
457 const char* units[] = {
"B",
"KB",
"MB",
"GB"};
459 double size =
static_cast<double>(bytes);
461 while (size >= 1024.0 && unit_index < 3) {
467 snprintf(buffer,
sizeof(buffer),
"%.1f %s", size, units[unit_index]);
468 return std::string(buffer);
472 const std::string& status) {
473 if (status ==
"pending")
475 if (status ==
"approved")
477 if (status ==
"rejected")
479 if (status ==
"applied")
485 if (status ==
"pending")
486 return colors_.proposal_pending;
487 if (status ==
"approved")
488 return colors_.proposal_approved;
489 if (status ==
"rejected")
490 return colors_.proposal_rejected;
491 if (status ==
"applied")
492 return colors_.proposal_applied;
493 return ImVec4(0.7f, 0.7f, 0.7f, 1.0f);
498 ImGui::TextWrapped(tr(
"Version management not initialized"));
502 ImGui::TextWrapped(tr(
"ROM Version History & Protection"));
507 ImGui::Text(tr(
"Total Snapshots: %zu"), stats.total_snapshots);
509 ImGui::TextColored(
colors_.sync_applied, tr(
"Safe Points: %zu"),
512 ImGui::TextColored(
colors_.sync_pending, tr(
"Auto-Backups: %zu"),
515 ImGui::Text(tr(
"Storage Used: %s"),
521 if (ImGui::Button(tr(
"đž Create Checkpoint"))) {
527 if (ImGui::Button(tr(
"đĄī¸ Mark Current as Safe Point"))) {
532 if (ImGui::Button(tr(
"đ Check for Corruption"))) {
540 if (ImGui::BeginChild(
"VersionList", ImVec2(0, 0),
true)) {
543 for (
size_t i = 0; i < snapshots.size(); ++i) {
552 ImGui::TextWrapped(tr(
"Approval management not initialized"));
556 ImGui::TextWrapped(tr(
"Proposal Approval System"));
562 if (pending.empty()) {
563 ImGui::TextWrapped(tr(
"No proposals pending approval."));
567 ImGui::Text(tr(
"Pending Proposals: %zu"), pending.size());
570 if (ImGui::BeginChild(
"ApprovalList", ImVec2(0, 0),
true)) {
571 for (
size_t i = 0; i < pending.size(); ++i) {
580 ImGui::PushID(index);
591 color =
colors_.proposal_approved;
597 ImGui::TextColored(color,
"%s", icon);
601 bool is_open = ImGui::TreeNode(snapshot.
description.c_str());
606 ImGui::Text(tr(
"Creator: %s"), snapshot.
creator.c_str());
608 ImGui::Text(tr(
"Hash: %s"), snapshot.
rom_hash.substr(0, 16).c_str());
609 ImGui::Text(tr(
"Size: %s"),
613 ImGui::TextColored(
colors_.sync_applied,
614 tr(
"â Safe Point (Host Verified)"));
620 if (ImGui::Button(tr(
"âŠī¸ Restore This Version"))) {
625 if (!snapshot.
is_safe_point && ImGui::Button(tr(
"đĄī¸ Mark as Safe"))) {
629 if (!snapshot.
is_safe_point && ImGui::Button(tr(
"đī¸ Delete"))) {
643 ImGui::PushID(index);
646 ImGui::TextColored(
colors_.proposal_pending,
"[âŗ]");
650 std::string short_id = status.
proposal_id.substr(0, 8);
652 ImGui::TreeNode(absl::StrFormat(
"Proposal %s", short_id.c_str()).c_str());
658 ImGui::Text(tr(
"Snapshot Before: %s"),
662 ImGui::TextWrapped(tr(
"Votes:"));
664 for (
const auto& [username, approved] : status.
votes) {
667 const char* vote_icon = approved ?
"â" :
"â";
668 ImGui::TextColored(vote_color,
" %s %s", vote_icon, username.c_str());
674 if (ImGui::Button(tr(
"â Approve"))) {
680 if (ImGui::Button(tr(
"â Reject"))) {
686 if (ImGui::Button(tr(
"âŠī¸ Rollback"))) {
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
void RenderVersionHistoryTab()
std::string FormatFileSize(size_t bytes)
ProposalEntry * GetProposal(const std::string &proposal_id)
net::RomVersionManager * version_mgr_
void RenderVersionSnapshot(const net::RomSnapshot &snapshot, int index)
void RenderProposalEntry(const ProposalEntry &entry, int index)
std::string FormatTimestamp(int64_t timestamp)
void AddSnapshot(const SnapshotEntry &entry)
bool show_snapshot_preview_
void AddProposal(const ProposalEntry &entry)
void UpdateProposalStatus(const std::string &proposal_id, const std::string &status)
void RenderProposalsTab()
const char * GetProposalStatusIcon(const std::string &status)
std::vector< ProposalEntry > proposals_
void RenderSnapshotsTab()
void RenderSnapshotEntry(const SnapshotEntry &entry, int index)
void AddRomSync(const RomSyncEntry &entry)
void RenderApprovalProposal(const net::ProposalApprovalManager::ApprovalStatus &status, int index)
struct yaze::gui::CollaborationPanel::@0 colors_
ImVec4 GetProposalStatusColor(const std::string &status)
void Render(bool *p_open=nullptr)
std::vector< RomSyncEntry > rom_syncs_
net::ProposalApprovalManager * approval_mgr_
void RenderRomSyncEntry(const RomSyncEntry &entry, int index)
std::vector< SnapshotEntry > snapshots_
bool filter_pending_only_
void Initialize(Rom *rom, net::RomVersionManager *version_mgr, net::ProposalApprovalManager *approval_mgr)
Manages proposal approval workflow for collaborative sessions.
std::vector< ApprovalStatus > GetPendingProposals() const
Manages ROM versioning, snapshots, and rollback capabilities.
absl::StatusOr< std::string > CreateSnapshot(const std::string &description, const std::string &creator, bool is_checkpoint=false)
std::string GetCurrentHash() const
absl::StatusOr< bool > DetectCorruption()
absl::Status RestoreSnapshot(const std::string &snapshot_id)
absl::Status MarkAsSafePoint(const std::string &snapshot_id)
absl::Status DeleteSnapshot(const std::string &snapshot_id)
std::vector< RomSnapshot > GetSnapshots(bool safe_points_only=false) const
Represents an AI-generated proposal.
std::string proposal_data
Represents a ROM synchronization event.
std::string error_message
Represents a shared snapshot (image, map state, etc.)
std::string snapshot_type
std::string snapshot_before
std::map< std::string, bool > votes
Represents a versioned snapshot of ROM state.