8#include "absl/strings/str_format.h"
9#include "imgui/imgui.h"
17 version_mgr_(nullptr),
18 approval_mgr_(nullptr),
20 selected_rom_sync_(-1),
21 selected_snapshot_(-1),
22 selected_proposal_(-1),
23 show_sync_details_(false),
24 show_snapshot_preview_(true),
26 filter_pending_only_(false) {
31 colors_.sync_applied = ImVec4(0.2f, 0.8f, 0.2f, 1.0f);
32 colors_.sync_pending = ImVec4(0.8f, 0.8f, 0.2f, 1.0f);
33 colors_.sync_error = ImVec4(0.8f, 0.2f, 0.2f, 1.0f);
34 colors_.proposal_pending = ImVec4(0.7f, 0.7f, 0.7f, 1.0f);
35 colors_.proposal_approved = ImVec4(0.2f, 0.8f, 0.2f, 1.0f);
36 colors_.proposal_rejected = ImVec4(0.8f, 0.3f, 0.3f, 1.0f);
37 colors_.proposal_applied = ImVec4(0.2f, 0.6f, 0.8f, 1.0f);
43 if (snapshot.texture_id) {
46 snapshot.texture_id =
nullptr;
60 if (!ImGui::Begin(
"Collaboration", p_open, ImGuiWindowFlags_None)) {
66 if (ImGui::BeginTabBar(
"CollaborationTabs")) {
67 if (ImGui::BeginTabItem(
"ROM Sync")) {
73 if (ImGui::BeginTabItem(
"Version History")) {
79 if (ImGui::BeginTabItem(
"Snapshots")) {
85 if (ImGui::BeginTabItem(
"Proposals")) {
91 if (ImGui::BeginTabItem(
"đ Approvals")) {
104 ImGui::TextWrapped(
"ROM Synchronization History");
108 if (ImGui::Button(
"Clear History")) {
119 int applied_count = 0;
120 int pending_count = 0;
126 else if (!sync.error_message.empty())
132 ImGui::Text(
"Total: %zu | ",
rom_syncs_.size());
134 ImGui::TextColored(
colors_.sync_applied,
"Applied: %d", applied_count);
136 ImGui::TextColored(
colors_.sync_pending,
"Pending: %d", pending_count);
138 ImGui::TextColored(
colors_.sync_error,
"Errors: %d", error_count);
143 if (ImGui::BeginChild(
"SyncList", ImVec2(0, 0),
true)) {
144 for (
size_t i = 0; i <
rom_syncs_.size(); ++i) {
148 if (
auto_scroll_ && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
149 ImGui::SetScrollHereY(1.0f);
156 ImGui::TextWrapped(
"Shared Snapshots Gallery");
160 if (ImGui::Button(
"Clear Gallery")) {
171 if (ImGui::BeginChild(
"SnapshotGrid", ImVec2(0, 0),
true)) {
172 float thumbnail_size = 150.0f;
173 float padding = 10.0f;
174 float cell_size = thumbnail_size + padding;
177 std::max(1, (
int)((ImGui::GetContentRegionAvail().x) / cell_size));
179 for (
size_t i = 0; i <
snapshots_.size(); ++i) {
183 std::string sender_lower =
snapshots_[i].sender;
184 std::transform(search_lower.begin(), search_lower.end(),
185 search_lower.begin(), ::tolower);
186 std::transform(sender_lower.begin(), sender_lower.end(),
187 sender_lower.begin(), ::tolower);
189 if (sender_lower.find(search_lower) == std::string::npos &&
190 snapshots_[i].snapshot_type.find(search_lower) ==
199 if ((i + 1) % columns != 0 && i <
snapshots_.size() - 1) {
208 ImGui::TextWrapped(
"AI Proposals & Suggestions");
212 if (ImGui::Button(
"Clear All")) {
223 int pending = 0, approved = 0, rejected = 0, applied = 0;
225 if (proposal.status ==
"pending")
227 else if (proposal.status ==
"approved")
229 else if (proposal.status ==
"rejected")
231 else if (proposal.status ==
"applied")
237 ImGui::TextColored(
colors_.proposal_pending,
" | Pending: %d", pending);
239 ImGui::TextColored(
colors_.proposal_approved,
" | Approved: %d", approved);
241 ImGui::TextColored(
colors_.proposal_rejected,
" | Rejected: %d", rejected);
243 ImGui::TextColored(
colors_.proposal_applied,
" | Applied: %d", applied);
248 if (ImGui::BeginChild(
"ProposalList", ImVec2(0, 0),
true)) {
249 for (
size_t i = 0; i <
proposals_.size(); ++i) {
257 std::string sender_lower =
proposals_[i].sender;
258 std::string desc_lower =
proposals_[i].description;
259 std::transform(search_lower.begin(), search_lower.end(),
260 search_lower.begin(), ::tolower);
261 std::transform(sender_lower.begin(), sender_lower.end(),
262 sender_lower.begin(), ::tolower);
263 std::transform(desc_lower.begin(), desc_lower.end(), desc_lower.begin(),
266 if (sender_lower.find(search_lower) == std::string::npos &&
267 desc_lower.find(search_lower) == std::string::npos) {
280 ImGui::PushID(index);
284 const char* status_icon;
287 status_color =
colors_.sync_applied;
288 status_icon =
"[â]";
290 status_color =
colors_.sync_error;
291 status_icon =
"[â]";
293 status_color =
colors_.sync_pending;
294 status_icon =
"[âˇ]";
297 ImGui::TextColored(status_color,
"%s", status_icon);
307 ImGui::TextWrapped(
"ROM Hash: %s", entry.
rom_hash.substr(0, 16).c_str());
309 ImGui::TextColored(
colors_.sync_error,
"Error: %s",
321 ImGui::PushID(index);
327 ImGui::Image(entry.
texture_id, ImVec2(150, 150));
330 ImGui::BeginChild(
"SnapshotPlaceholder", ImVec2(150, 150),
true);
331 ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 50);
337 ImGui::TextWrapped(
"%s", entry.
sender.c_str());
342 if (ImGui::SmallButton(
"View")) {
347 if (ImGui::SmallButton(
"Export")) {
358 ImGui::PushID(index);
364 ImGui::TextColored(color,
"%s", icon);
368 bool is_open = ImGui::TreeNode(entry.
description.c_str());
373 ImGui::Text(
"From: %s", entry.
sender.c_str());
375 ImGui::Text(
"Status: %s", entry.
status.c_str());
383 if (entry.
status ==
"pending") {
385 if (ImGui::Button(
"â Approve")) {
389 if (ImGui::Button(
"â Reject")) {
393 if (ImGui::Button(
"âļ Apply Now")) {
419 const std::string& status) {
421 if (proposal.proposal_id == proposal_id) {
422 proposal.status = status;
436 if (proposal.proposal_id == proposal_id) {
444 std::time_t time = timestamp / 1000;
445 std::tm* tm = std::localtime(&time);
448 std::strftime(buffer,
sizeof(buffer),
"%H:%M:%S", tm);
449 return std::string(buffer);
453 const char* units[] = {
"B",
"KB",
"MB",
"GB"};
455 double size =
static_cast<double>(bytes);
457 while (size >= 1024.0 && unit_index < 3) {
463 snprintf(buffer,
sizeof(buffer),
"%.1f %s", size, units[unit_index]);
464 return std::string(buffer);
468 const std::string& status) {
469 if (status ==
"pending")
471 if (status ==
"approved")
473 if (status ==
"rejected")
475 if (status ==
"applied")
481 if (status ==
"pending")
482 return colors_.proposal_pending;
483 if (status ==
"approved")
484 return colors_.proposal_approved;
485 if (status ==
"rejected")
486 return colors_.proposal_rejected;
487 if (status ==
"applied")
488 return colors_.proposal_applied;
489 return ImVec4(0.7f, 0.7f, 0.7f, 1.0f);
494 ImGui::TextWrapped(
"Version management not initialized");
498 ImGui::TextWrapped(
"ROM Version History & Protection");
503 ImGui::Text(
"Total Snapshots: %zu", stats.total_snapshots);
505 ImGui::TextColored(
colors_.sync_applied,
"Safe Points: %zu",
508 ImGui::TextColored(
colors_.sync_pending,
"Auto-Backups: %zu",
511 ImGui::Text(
"Storage Used: %s",
517 if (ImGui::Button(
"đž Create Checkpoint")) {
523 if (ImGui::Button(
"đĄī¸ Mark Current as Safe Point")) {
528 if (ImGui::Button(
"đ Check for Corruption")) {
536 if (ImGui::BeginChild(
"VersionList", ImVec2(0, 0),
true)) {
539 for (
size_t i = 0; i < snapshots.size(); ++i) {
548 ImGui::TextWrapped(
"Approval management not initialized");
552 ImGui::TextWrapped(
"Proposal Approval System");
558 if (pending.empty()) {
559 ImGui::TextWrapped(
"No proposals pending approval.");
563 ImGui::Text(
"Pending Proposals: %zu", pending.size());
566 if (ImGui::BeginChild(
"ApprovalList", ImVec2(0, 0),
true)) {
567 for (
size_t i = 0; i < pending.size(); ++i) {
576 ImGui::PushID(index);
587 color =
colors_.proposal_approved;
593 ImGui::TextColored(color,
"%s", icon);
597 bool is_open = ImGui::TreeNode(snapshot.
description.c_str());
602 ImGui::Text(
"Creator: %s", snapshot.
creator.c_str());
604 ImGui::Text(
"Hash: %s", snapshot.
rom_hash.substr(0, 16).c_str());
608 ImGui::TextColored(
colors_.sync_applied,
"â Safe Point (Host Verified)");
614 if (ImGui::Button(
"âŠī¸ Restore This Version")) {
619 if (!snapshot.
is_safe_point && ImGui::Button(
"đĄī¸ Mark as Safe")) {
623 if (!snapshot.
is_safe_point && ImGui::Button(
"đī¸ Delete")) {
637 ImGui::PushID(index);
640 ImGui::TextColored(
colors_.proposal_pending,
"[âŗ]");
644 std::string short_id = status.
proposal_id.substr(0, 8);
646 ImGui::TreeNode(absl::StrFormat(
"Proposal %s", short_id.c_str()).c_str());
652 ImGui::Text(
"Snapshot Before: %s",
656 ImGui::TextWrapped(
"Votes:");
658 for (
const auto& [username, approved] : status.
votes) {
661 const char* vote_icon = approved ?
"â" :
"â";
662 ImGui::TextColored(vote_color,
" %s %s", vote_icon, username.c_str());
668 if (ImGui::Button(
"â Approve")) {
674 if (ImGui::Button(
"â Reject")) {
680 if (ImGui::Button(
"âŠī¸ 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.