Files
ft/Client/Assets/Scripts/MiniBP/UI/MiniBattlePassPanel.cs
2026-06-29 21:18:33 +08:00

277 lines
9.2 KiB
C#

using asap.core;
using DG.Tweening;
using GameCore;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UniRx;
using UnityEngine;
using UnityEngine.UI;
public struct RefreshPanelEvent
{
}
/// <summary>
/// 由 <see cref="MiniBattlePassSecondVideoPanel"/> 实现:列表行上点领奖时先走路、砸,再发奖。
/// </summary>
public interface IMiniBattlePassAnimatedClaim
{
bool ClaimAnimationInProgress { get; }
/// <returns>true 表示已交给面板播动画,调用方勿再直接 <c>ReceiveReward</c>。</returns>
bool TryScheduleClaim(int tierIndex, bool isFreeReward);
}
public class MiniBattlePassPanel : MonoBehaviour
{
[SerializeField] protected MiniBattlePassType Type = MiniBattlePassType.LuckMagic;
protected virtual int NormalizedPosition => 1;
protected MiniBattlePassDataModel miniBP;
Button btn_close;
TMP_Text text_time;
protected GameObject buy;
Button btn_buy;
protected Button btn_claim;
protected Button btn_claim_gray;
protected GameObject claim;
GameObject done;
protected TMP_Text text_buy;
protected GameObject item;
protected RectTransform contentRect;
protected Transform content;
protected ScrollRect scrollRect;
protected VerticalLayoutGroup layoutGroup;
int addSizeDelta;
int startAdd;
protected float itemHeight = 164f;
protected float allHeight = 0f;
protected virtual int showCount => 2;
protected List<MiniBPItemData> miniBPItemDatas;
protected List<IMiniBattlePassItem> miniBattlePassItems = new List<IMiniBattlePassItem>();
protected CompositeDisposable disposables = new CompositeDisposable();
protected string timerFormat;
protected virtual void Awake()
{
miniBP = GContext.container.Resolve<MiniBattlePassDataProvider>().GetModel(Type);
miniBP.SetPanelData();
item = transform.Find("root/ScrollView/Viewport/Content/item").gameObject;
item.SetActive(false);
scrollRect = transform.Find("root/ScrollView").GetComponent<ScrollRect>();
content = transform.Find("root/ScrollView/Viewport/Content");
contentRect = content.GetComponent<RectTransform>();
layoutGroup = content.GetComponent<VerticalLayoutGroup>();
float spacing = layoutGroup.spacing;
addSizeDelta = layoutGroup.padding.vertical;
startAdd = layoutGroup.padding.top;
itemHeight = item.GetComponent<RectTransform>().sizeDelta.y + spacing;
btn_close = transform.Find("root/btn_close").GetComponent<Button>();
text_time = transform.Find("root/bg_time/text_time").GetComponent<TMP_Text>();
buy = transform.Find("root/bottom/buy").gameObject;
btn_buy = transform.Find("root/bottom/buy/btn_buy/btn_green").GetComponent<Button>();
text_buy = transform.Find("root/bottom/buy/btn_buy/btn_green/Ani_Container/p_text").GetComponent<TMP_Text>();
claim = transform.Find("root/bottom/claim").gameObject;
btn_claim = transform.Find("root/bottom/claim/btn_claim/btn_green").GetComponent<Button>();
btn_claim_gray = transform.Find("root/bottom/claim/btn_claim_gray/btn_green").GetComponent<Button>();
done = transform.Find("root/bottom/done").gameObject;
timerFormat = LocalizationMgr.GetText("UI_COMMON_end");
GContext.OnEvent<RefreshPanelEvent>().Subscribe(_ =>
{
RefreshPanel();
}).AddTo(disposables);
}
protected virtual void Start()
{
btn_close.onClick.AddListener(OnClickClose);
btn_buy.onClick.AddListener(OnClickBuy);
btn_claim.onClick.AddListener(ClickClaimAll);
SetItem();
ShowTimer();
SetButtonShow();
RefreshPanel();
var _tables = GContext.container.Resolve<cfg.Tables>();
var _iapItem = miniBP.GetIAPItem();
SKUDetailDataEvent sKUDetailDataEvent = new SKUDetailDataEvent(_iapItem);
GContext.Publish(sKUDetailDataEvent);
text_buy.text = sKUDetailDataEvent.price;
miniBP.CheckIfGetLastBpRewards();
}
protected virtual void SetButtonShow()
{
buy.SetActive(!miniBP.IsVip);
claim.SetActive(miniBP.IsVip && !miniBP.IsDone());
done.SetActive(miniBP.IsDone());
}
async void OnClickBuy()
{
if (miniBP.IsVip)
{
return;
}
bool Result = await miniBP.BuyBattlePass();
if (Result)
{
BuySuccess();
}
}
[ContextMenu("PlayVipUnlock")]
protected void BuySuccess()
{
StartCoroutine(PlayVipUnlock());
if (!miniBP.IsVip)
{
Debug.LogError("MiniBattlePassDataProvider.Error: BuySuccess called but not VIP");
return;
}
buy.SetActive(false);
claim.SetActive(true);
done.SetActive(false);
RefreshPanel();
//for (int i = 0; i < miniBattlePassItems.Count; i++)
//{
// miniBattlePassItems[i].UnlockRefresh();
//}
}
protected virtual void ClickClaimAll()
{
miniBP.ReceiveAllReward();
RefreshPanel();
}
void SetItem()
{
miniBPItemDatas = miniBP.miniBPItemDatas;
allHeight = miniBPItemDatas.Count * itemHeight + addSizeDelta;
contentRect.sizeDelta = new Vector2(contentRect.sizeDelta.x, allHeight);
for (int i = 0; i < miniBPItemDatas.Count; i++)
{
GameObject go = Instantiate(item, content);
go.SetActive(true);
IMiniBattlePassItem miniBattlePassItem = go.GetComponent<IMiniBattlePassItem>();
miniBattlePassItem.Init(miniBPItemDatas[i], miniBP);
miniBattlePassItems.Add(miniBattlePassItem);
}
OnAfterMiniBattlePassItemsInstantiated();
JumpToIndex();
}
/// <summary>
/// 在 Content 下所有战令行 item 实例化完成后调用,可在此调整与列表同级的装饰节点顺序等。
/// </summary>
protected virtual void OnAfterMiniBattlePassItemsInstantiated()
{
}
protected virtual void JumpToIndex()
{
}
protected IEnumerator PlayVipUnlock()
{
for (int i = 0; i < miniBPItemDatas.Count; i++)
{
miniBPItemDatas[i].UILockVip = true;
}
float time = 0;
if (NormalizedPosition == 1)
{
time = 1f - scrollRect.verticalNormalizedPosition;
}
else
{
time = scrollRect.verticalNormalizedPosition;
}
scrollRect.DOVerticalNormalizedPos(NormalizedPosition, time).SetEase(Ease.OutCubic);
yield return new WaitForSeconds(time);
int index = -1;
int allitems = miniBattlePassItems.Count;
time = 0.2f;
float totalTime = allitems * time;
scrollRect.DOVerticalNormalizedPos(1 - NormalizedPosition, totalTime)
.SetEase(Ease.InOutCubic)
.OnUpdate(() =>
{
int curIndex = 0;
if (NormalizedPosition == 1)
{
curIndex = Mathf.FloorToInt((1 - scrollRect.verticalNormalizedPosition) * allitems);
}
else
{
curIndex = Mathf.FloorToInt(scrollRect.verticalNormalizedPosition * allitems);
}
if (curIndex > index && curIndex < allitems)
{
index = curIndex;
miniBattlePassItems[index % allitems].UnlockRefresh();
}
});
yield return new WaitForSeconds(totalTime);
scrollRect.DOVerticalNormalizedPos(NormalizedPosition, 1).SetEase(Ease.OutCubic);
//yield return new WaitForSeconds(1);
//btn_mask.SetActive(false);
}
protected virtual void RefreshPanel()
{
if (miniBP.IsVip)
{
bool isShowAllBtn = miniBP.Data.VRIndexs.Count <= miniBP.rewardIndex;
if (miniBP.FreeRewards.Count > 0)
{
isShowAllBtn |= miniBP.Data.NRIndexs.Count <= miniBP.rewardIndex;
}
btn_claim.gameObject.SetActive(isShowAllBtn);
btn_claim_gray.gameObject.SetActive(!isShowAllBtn);
}
for (int i = 0; i < miniBattlePassItems.Count; i++)
{
miniBattlePassItems[i].Refresh();
}
}
void ShowTimer()
{
//剩余时间
TimeSpan duration = miniBP.endTime - ZZTimeHelper.UtcNow();
text_time.text = string.Format(timerFormat, ConvertTools.ConvertTime2(duration));
var timer = Observable.Interval(TimeSpan.FromSeconds(1))
.TakeWhile(seconds => seconds <= duration.TotalSeconds)
.Subscribe(seconds => text_time.text =
string.Format(timerFormat, ConvertTools.ConvertTime2(duration.Subtract(TimeSpan.FromSeconds(seconds))))
, Refresh)
.AddTo(disposables);
}
protected void Refresh()
{
OnClickClose();
}
void OnClickClose()
{
UIManager.Instance.DestroyUI(gameObject.name);
}
private void OnDestroy()
{
disposables?.Dispose();
disposables = null;
}
}