8#include "imgui/imgui.h"
16 version_mgr_(nullptr),
17 approval_mgr_(nullptr),
19 selected_rom_sync_(-1),
20 selected_snapshot_(-1),
21 selected_proposal_(-1),
22 show_sync_details_(false),
23 show_snapshot_preview_(true),
25 filter_pending_only_(false) {
30 colors_.sync_applied = ImVec4(0.2f, 0.8f, 0.2f, 1.0f);
31 colors_.sync_pending = ImVec4(0.8f, 0.8f, 0.2f, 1.0f);
32 colors_.sync_error = ImVec4(0.8f, 0.2f, 0.2f, 1.0f);
33 colors_.proposal_pending = ImVec4(0.7f, 0.7f, 0.7f, 1.0f);
34 colors_.proposal_approved = ImVec4(0.2f, 0.8f, 0.2f, 1.0f);
35 colors_.proposal_rejected = ImVec4(0.8f, 0.3f, 0.3f, 1.0f);
36 colors_.proposal_applied = ImVec4(0.2f, 0.6f, 0.8f, 1.0f);
42 if (snapshot.texture_id) {
45 snapshot.texture_id =
nullptr;
59 if (!ImGui::Begin(
"Collaboration", p_open, ImGuiWindowFlags_None)) {
65 if (ImGui::BeginTabBar(
"CollaborationTabs")) {
66 if (ImGui::BeginTabItem(
"ROM Sync")) {
72 if (ImGui::BeginTabItem(
"Version History")) {
78 if (ImGui::BeginTabItem(
"Snapshots")) {
84 if (ImGui::BeginTabItem(
"Proposals")) {
90 if (ImGui::BeginTabItem(
"đ Approvals")) {
103 ImGui::TextWrapped(
"ROM Synchronization History");
107 if (ImGui::Button(
"Clear History")) {
118 int applied_count = 0;
119 int pending_count = 0;
125 else if (!sync.error_message.empty())
131 ImGui::Text(
"Total: %zu | ",
rom_syncs_.size());
133 ImGui::TextColored(
colors_.sync_applied,
"Applied: %d", applied_count);
135 ImGui::TextColored(
colors_.sync_pending,
"Pending: %d", pending_count);
137 ImGui::TextColored(
colors_.sync_error,
"Errors: %d", error_count);
142 if (ImGui::BeginChild(
"SyncList", ImVec2(0, 0),
true)) {
143 for (
size_t i = 0; i <
rom_syncs_.size(); ++i) {
147 if (
auto_scroll_ && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
148 ImGui::SetScrollHereY(1.0f);
155 ImGui::TextWrapped(
"Shared Snapshots Gallery");
159 if (ImGui::Button(
"Clear Gallery")) {
170 if (ImGui::BeginChild(
"SnapshotGrid", ImVec2(0, 0),
true)) {
171 float thumbnail_size = 150.0f;
172 float padding = 10.0f;
173 float cell_size = thumbnail_size + padding;
176 std::max(1, (
int)((ImGui::GetContentRegionAvail().x) / cell_size));
178 for (
size_t i = 0; i <
snapshots_.size(); ++i) {
182 std::string sender_lower =
snapshots_[i].sender;
183 std::transform(search_lower.begin(), search_lower.end(),
184 search_lower.begin(), ::tolower);
185 std::transform(sender_lower.begin(), sender_lower.end(),
186 sender_lower.begin(), ::tolower);
188 if (sender_lower.find(search_lower) == std::string::npos &&
189 snapshots_[i].snapshot_type.find(search_lower) ==
198 if ((i + 1) % columns != 0 && i <
snapshots_.size() - 1) {
207 ImGui::TextWrapped(
"AI Proposals & Suggestions");
211 if (ImGui::Button(
"Clear All")) {
222 int pending = 0, approved = 0, rejected = 0, applied = 0;
224 if (proposal.status ==
"pending")
226 else if (proposal.status ==
"approved")
228 else if (proposal.status ==
"rejected")
230 else if (proposal.status ==
"applied")
236 ImGui::TextColored(
colors_.proposal_pending,
" | Pending: %d", pending);
238 ImGui::TextColored(
colors_.proposal_approved,
" | Approved: %d", approved);
240 ImGui::TextColored(
colors_.proposal_rejected,
" | Rejected: %d", rejected);
242 ImGui::TextColored(
colors_.proposal_applied,
" | Applied: %d", applied);
247 if (ImGui::BeginChild(
"ProposalList", ImVec2(0, 0),
true)) {
248 for (
size_t i = 0; i <
proposals_.size(); ++i) {
256 std::string sender_lower =
proposals_[i].sender;
257 std::string desc_lower =
proposals_[i].description;
258 std::transform(search_lower.begin(), search_lower.end(),
259 search_lower.begin(), ::tolower);
260 std::transform(sender_lower.begin(), sender_lower.end(),
261 sender_lower.begin(), ::tolower);
262 std::transform(desc_lower.begin(), desc_lower.end(), desc_lower.begin(),
265 if (sender_lower.find(search_lower) == std::string::npos &&
266 desc_lower.find(search_lower) == std::string::npos) {
279 ImGui::PushID(index);
283 const char* status_icon;
286 status_color =
colors_.sync_applied;
287 status_icon =
"[â]";
289 status_color =
colors_.sync_error;
290 status_icon =
"[â]";
292 status_color =
colors_.sync_pending;
293 status_icon =
"[âˇ]";
296 ImGui::TextColored(status_color,
"%s", status_icon);
306 ImGui::TextWrapped(
"ROM Hash: %s", entry.
rom_hash.substr(0, 16).c_str());
308 ImGui::TextColored(
colors_.sync_error,
"Error: %s",
320 ImGui::PushID(index);
326 ImGui::Image(entry.
texture_id, ImVec2(150, 150));
329 ImGui::BeginChild(
"SnapshotPlaceholder", ImVec2(150, 150),
true);
330 ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 50);
336 ImGui::TextWrapped(
"%s", entry.
sender.c_str());
341 if (ImGui::SmallButton(
"View")) {
346 if (ImGui::SmallButton(
"Export")) {
357 ImGui::PushID(index);
363 ImGui::TextColored(color,
"%s", icon);
367 bool is_open = ImGui::TreeNode(entry.
description.c_str());
372 ImGui::Text(
"From: %s", entry.
sender.c_str());
374 ImGui::Text(
"Status: %s", entry.
status.c_str());
382 if (entry.
status ==
"pending") {
384 if (ImGui::Button(
"â Approve")) {
388 if (ImGui::Button(
"â Reject")) {
392 if (ImGui::Button(
"âļ Apply Now")) {
418 const std::string& status) {
420 if (proposal.proposal_id == proposal_id) {
421 proposal.status = status;
435 if (proposal.proposal_id == proposal_id) {
443 std::time_t time = timestamp / 1000;
444 std::tm* tm = std::localtime(&time);
447 std::strftime(buffer,
sizeof(buffer),
"%H:%M:%S", tm);
448 return std::string(buffer);
452 const char* units[] = {
"B",
"KB",
"MB",
"GB"};
454 double size =
static_cast<double>(bytes);
456 while (size >= 1024.0 && unit_index < 3) {
462 snprintf(buffer,
sizeof(buffer),
"%.1f %s", size, units[unit_index]);
463 return std::string(buffer);
467 const std::string& status) {
468 if (status ==
"pending")
470 if (status ==
"approved")
472 if (status ==
"rejected")
474 if (status ==
"applied")
480 if (status ==
"pending")
481 return colors_.proposal_pending;
482 if (status ==
"approved")
483 return colors_.proposal_approved;
484 if (status ==
"rejected")
485 return colors_.proposal_rejected;
486 if (status ==
"applied")
487 return colors_.proposal_applied;
488 return ImVec4(0.7f, 0.7f, 0.7f, 1.0f);
493 ImGui::TextWrapped(
"Version management not initialized");
497 ImGui::TextWrapped(
"ROM Version History & Protection");
502 ImGui::Text(
"Total Snapshots: %zu", stats.total_snapshots);
504 ImGui::TextColored(
colors_.sync_applied,
"Safe Points: %zu",
507 ImGui::TextColored(
colors_.sync_pending,
"Auto-Backups: %zu",
510 ImGui::Text(
"Storage Used: %s",
516 if (ImGui::Button(
"đž Create Checkpoint")) {
522 if (ImGui::Button(
"đĄī¸ Mark Current as Safe Point")) {
527 if (ImGui::Button(
"đ Check for Corruption")) {
535 if (ImGui::BeginChild(
"VersionList", ImVec2(0, 0),
true)) {
538 for (
size_t i = 0; i < snapshots.size(); ++i) {
547 ImGui::TextWrapped(
"Approval management not initialized");
551 ImGui::TextWrapped(
"Proposal Approval System");
557 if (pending.empty()) {
558 ImGui::TextWrapped(
"No proposals pending approval.");
562 ImGui::Text(
"Pending Proposals: %zu", pending.size());
565 if (ImGui::BeginChild(
"ApprovalList", ImVec2(0, 0),
true)) {
566 for (
size_t i = 0; i < pending.size(); ++i) {
575 ImGui::PushID(index);
586 color =
colors_.proposal_approved;
592 ImGui::TextColored(color,
"%s", icon);
596 bool is_open = ImGui::TreeNode(snapshot.
description.c_str());
601 ImGui::Text(
"Creator: %s", snapshot.
creator.c_str());
603 ImGui::Text(
"Hash: %s", snapshot.
rom_hash.substr(0, 16).c_str());
607 ImGui::TextColored(
colors_.sync_applied,
"â Safe Point (Host Verified)");
613 if (ImGui::Button(
"âŠī¸ Restore This Version")) {
618 if (!snapshot.
is_safe_point && ImGui::Button(
"đĄī¸ Mark as Safe")) {
622 if (!snapshot.
is_safe_point && ImGui::Button(
"đī¸ Delete")) {
636 ImGui::PushID(index);
639 ImGui::TextColored(
colors_.proposal_pending,
"[âŗ]");
643 std::string short_id = status.
proposal_id.substr(0, 8);
645 ImGui::TreeNode(absl::StrFormat(
"Proposal %s", short_id.c_str()).c_str());
651 ImGui::Text(
"Snapshot Before: %s",
655 ImGui::TextWrapped(
"Votes:");
657 for (
const auto& [username, approved] : status.
votes) {
660 const char* vote_icon = approved ?
"â" :
"â";
661 ImGui::TextColored(vote_color,
" %s %s", vote_icon, username.c_str());
667 if (ImGui::Button(
"â Approve")) {
673 if (ImGui::Button(
"â Reject")) {
679 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.