Files
Naked-Desire/Source/NakedDesire/UI/Phone/Apps/ForumCommissionWidget.cpp
T
2026-06-03 21:42:24 +03:00

126 lines
3.6 KiB
C++

// © 2025 Naked People Team. All Rights Reserved.
#include "ForumCommissionWidget.h"
#include "Components/Button.h"
#include "CommonTextBlock.h"
#include "NakedDesire/Commissions/Commission.h"
#include "NakedDesire/Commissions/CommissionObjective.h"
#include "NakedDesire/Commissions/CommissionTypes.h"
#define LOCTEXT_NAMESPACE "ForumCommission"
void UForumCommissionWidget::NativeOnInitialized()
{
Super::NativeOnInitialized();
if (AcceptButton)
AcceptButton->OnClicked.AddUniqueDynamic(this, &UForumCommissionWidget::HandleAcceptClicked);
if (AbandonButton)
AbandonButton->OnClicked.AddUniqueDynamic(this, &UForumCommissionWidget::HandleAbandonClicked);
}
void UForumCommissionWidget::SetCommission(UCommission* InCommission)
{
Commission = InCommission;
CachedObjectivesString.Reset(); // force a fresh push for the (possibly reused) row
TimeSinceProgressRefresh = 0.0f;
if (!Commission)
return;
if (TitleText)
TitleText->SetText(Commission->GetTitle());
if (PosterText)
PosterText->SetText(FText::Format(LOCTEXT("PosterFmt", "by {0}"), Commission->GetPosterUsername()));
if (RewardText)
RewardText->SetText(FormatReward(Commission->GetReward()));
UpdateObjectivesText();
// Accept only offers; abandon only commitments. Completed / expired rows show neither control.
const ECommissionState State = Commission->GetState();
if (AcceptButton)
AcceptButton->SetVisibility(State == ECommissionState::Offered ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
if (AbandonButton)
AbandonButton->SetVisibility(State == ECommissionState::Accepted ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
}
void UForumCommissionWidget::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
Super::NativeTick(MyGeometry, InDeltaTime);
// Only accepted rows have live progress; offered / completed / expired rows are static.
if (!Commission || Commission->GetState() != ECommissionState::Accepted)
return;
TimeSinceProgressRefresh += InDeltaTime;
if (TimeSinceProgressRefresh < ProgressRefreshInterval)
return;
TimeSinceProgressRefresh = 0.0f;
UpdateObjectivesText();
}
void UForumCommissionWidget::HandleAcceptClicked()
{
if (Commission)
OnAcceptClicked.ExecuteIfBound(Commission);
}
void UForumCommissionWidget::HandleAbandonClicked()
{
if (Commission)
OnAbandonClicked.ExecuteIfBound(Commission);
}
void UForumCommissionWidget::UpdateObjectivesText()
{
if (!DescriptionText)
return;
FString NewText = BuildObjectivesString();
if (NewText == CachedObjectivesString)
return; // nothing changed since the last refresh — skip the SetText churn
CachedObjectivesString = MoveTemp(NewText);
DescriptionText->SetText(FText::FromString(CachedObjectivesString));
}
FString UForumCommissionWidget::BuildObjectivesString() const
{
FString Result;
if (!Commission)
return Result;
for (const UCommissionObjective* Objective : Commission->GetObjectives())
{
if (!Objective)
continue;
if (!Result.IsEmpty())
Result += LINE_TERMINATOR;
const int32 Pct = FMath::RoundToInt(Objective->GetProgress() * 100.0f);
Result += FString::Printf(TEXT("• %s (%d%%)"), *Objective->GetDescription().ToString(), Pct);
}
return Result;
}
FText UForumCommissionWidget::FormatReward(const FCommissionReward& Reward)
{
TArray<FString> Parts;
if (Reward.Money != 0)
Parts.Add(FString::Printf(TEXT("¥%d"), Reward.Money)); // ¥ = yen sign
if (!FMath::IsNearlyZero(Reward.XP))
Parts.Add(FString::Printf(TEXT("%.0f XP"), Reward.XP));
if (Reward.Followers != 0)
Parts.Add(FString::Printf(TEXT("+%d followers"), Reward.Followers));
return FText::FromString(FString::Join(Parts, TEXT(" ")));
}
#undef LOCTEXT_NAMESPACE