// © 2025 Naked People Team. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "CommonUserWidget.h" #include "ForumCommissionWidget.generated.h" class UButton; class UCommonTextBlock; class UCommission; struct FCommissionReward; // One commission entry on the forum board (GDD §13). Populated from a runtime UCommission by the // owning UForumCommissionsWidget; it shows the title, lore poster, reward, and per-objective progress, // and surfaces the accept / abandon control appropriate to the commission's lifecycle state. The row // owns no logic beyond display — it reports button taps up via delegates, like UPhoneAppIconWidget. UCLASS(Abstract) class NAKEDDESIRE_API UForumCommissionWidget : public UCommonUserWidget { GENERATED_BODY() public: // Bind a runtime commission and refresh the row. Passing null leaves the row blank. void SetCommission(UCommission* InCommission); DECLARE_DELEGATE_OneParam(FOnCommissionActionRequested, UCommission*); FOnCommissionActionRequested OnAcceptClicked; // Offered -> accept FOnCommissionActionRequested OnAbandonClicked; // Accepted -> abandon (§13.2, no penalty) protected: virtual void NativeOnInitialized() override; // Accepted commissions ramp progress continuously (travel distance, hold timers) with no per-tick // delegate, so the row polls its objectives here while live to keep the percentages current. virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override; private: UPROPERTY(meta = (BindWidget)) TObjectPtr TitleText; UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr PosterText; UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr RewardText; UPROPERTY(meta = (BindWidget)) TObjectPtr DescriptionText; UPROPERTY(meta = (BindWidget)) TObjectPtr AcceptButton; UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr AbandonButton; UFUNCTION() void HandleAcceptClicked(); UFUNCTION() void HandleAbandonClicked(); // Rebuild the per-objective progress text, but only push it to the widget when it actually changed, // so the poll doesn't churn SetText every tick. void UpdateObjectivesText(); FString BuildObjectivesString() const; static FText FormatReward(const FCommissionReward& Reward); UPROPERTY() TObjectPtr Commission; // Throttle for the in-progress poll (seconds between objective-text refreshes) and its accumulator. static constexpr float ProgressRefreshInterval = 0.25f; float TimeSinceProgressRefresh = 0.0f; // Last string pushed to DescriptionText; used to skip redundant SetText calls. FString CachedObjectivesString; };