123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559 |
- //
- // IAPCtlShopUI.cpp
- // TileManor
- //
- // Created by 徐炼新 on 2024/1/16.
- //
- #include "IAPCtlShop.hpp"
- #include "ui/UIPageView.h"
- #include "RUUtils.h"
- #include "RUPlatform.h"
- #include "IAPConf.hpp"
- #include "IAPCtlShopUI.hpp"
- #include "IAPCtlShopItem.hpp"
- #include "IAPDefine.hpp"
- #include "IAPTestCard.hpp"
- #include <regex>
- IAPCtlShopUI* IAPCtlShopUI::_instance = nullptr;
- IAPCtlShopUI* IAPCtlShopUI::getInstance() {
- if (_instance == nullptr) {
- _instance = new IAPCtlShopUI();
- _instance->autorelease();
- _instance->retain();
- }
- return _instance;
- }
- IAPCtlShopUI::IAPCtlShopUI() {
- }
- IAPCtlShopUI::~IAPCtlShopUI() {
-
- }
- bool IAPCtlShopUI::isShowing() {
- return _bUIShowing;
- }
- void IAPCtlShopUI::clear() {
- _goodsInfo.clear();
- for (auto& gi : _goodsItems) {
- gi->release();
- }
- _goodsItems.clear();
- _placementItems.clear();
- for(const auto& placement : _placements){
- _indicators[placement.first].clear();
- }
- _allSizes.clear();
- _cb = nullptr;
- }
- bool IAPCtlShopUI::create(Node* pNode, IAPConf* cfg, iap::ShopRequirement& requirement,int placementId) {
- redutils::Platform::getInstance()->reportLog("open iap");
- _cfg = cfg;
- _bUIShowing = true;
- _placementId = placementId;
- clear();
-
- _layer = redutils::RUReboltLayer::createReboltLayer("shop_interface.redream");
- pNode->addChild(_layer, 3);
- _layer->registerOnNotify([this](const redutils::ReboltNotifyData& data){
- _onNotifyDevelopment(data);
- });
- _layer->runBehaviacWhitFunName("初始化");
-
- // _igCoin->doOwnInit();
-
- if (_goodsInfo.size() == 0) {
- IAPConf::getInstance()->getAllGoods(_goodsInfo);
- }
- // 过滤掉不符合的金币
- filterGoods(requirement);
-
- // 构建 list 区域
- constructShopItem(false);
- cocos2d::Size size = _ndScrollArea->getContentSize();
- _tableView = redutils::RUTableView::create(&_tableData, cocos2d::Size(size.width, size.height));
- _tableView->setCascadeOpacityEnabled(true);
- _tableView->setCascadeColorEnabled(true);
- _tableView->setDirection(ScrollViewSmooth::Direction::VERTICAL);
- _tableView->setVerticalFillOrder(TableViewSmooth::VerticalFillOrder::TOP_DOWN, false);
- _tableView->setDelegate(&_tableData);
- _tableView->setBounceable(true);
- // _tableView->setOutSightClean(false);
- _ndScrollArea->addChild(_tableView);
-
- return true;
- }
- // (暂未完成)
- void IAPCtlShopUI::showPlacementsInNode(cocos2d::Node *pNode, const vector<std::string> &plIds){
- clear();
- redutils::Platform::getInstance()->reportLog("open iap");
-
- int index = 0;
- _tableData.setCascadeOpacity(true);
- _tableData.clear();
- cocos2d::Size size = _ndScrollArea->getContentSize();
- auto delayIdx = 0;
- cocos2d::Vec2 offset(size.width, 0);
- float dur = 0.4;
- int height = 0;
-
- for(int i = 0; i < plIds.size(); i++){
- if(_placements.count(plIds[i]) == 0)continue;
- // 展示活动版位
- bool bNeedAnim = height <= size.height;
- Node* nd = Node::create();
- nd->setAnchorPoint(Vec2(0.5,0.5));
- nd->setContentSize(cocos2d::Size(584,250));
- nd->setCascadeOpacityEnabled(true);
- nd->setCascadeColorEnabled(true);
-
- auto si = createPlacementUI(_placements[plIds[i]]);
- auto sz = cocos2d::Size(584,280);
- cocos2d::Vec2 pos(size.width/2.0, sz.height/2.0);
- nd->addChild(si);
- si->setPosition(bNeedAnim ? pos+offset : pos);
- _placementItems.push_back(nd);
- _tableData.insertCell(index++, nd);
- _allSizes.push_back(sz);
- height += sz.height;
-
- if (bNeedAnim) {
- // 加入动画
- auto d = DelayTime::create(delayIdx*dur/8.0);
- auto m = EaseBackOut::create(MoveBy::create(dur, cocos2d::Vec2(-offset.x, offset.y)));
- si->runAction(Sequence::create(d, m, NULL));
- delayIdx ++;
- }
- }
-
- _tableData._numberOfCellsInTableView = [=](cocos2d::extension::TableViewSmooth*)->ssize_t{
- return _allSizes.size();
- };
- _tableData._tableCellSizeForIndex = [=](cocos2d::extension::TableViewSmooth*, ssize_t idx)->Size{
- if (idx < _allSizes.size()) {
- return _allSizes[idx];
- } else {
- return Size(0,0);
- }
- };
-
- // 防止拉动的时候才创建
- _layer->scheduleOnce([=](float){
- for (int i=0; i<_allSizes.size(); i++) {
- _tableView->updateCellAtIndex(i);
- }
- }, 0.05, "SCH_Update_Cells");
-
-
- _tableView = redutils::RUTableView::create(&_tableData, cocos2d::Size(size.width, size.height));
- _tableView->setCascadeOpacityEnabled(true);
- _tableView->setCascadeColorEnabled(true);
- _tableView->setDirection(ScrollViewSmooth::Direction::VERTICAL);
- _tableView->setVerticalFillOrder(TableViewSmooth::VerticalFillOrder::TOP_DOWN, false);
- _tableView->setDelegate(&_tableData);
- _tableView->setBounceable(true);
- // _tableView->setOutSightClean(false);
- _ndScrollArea->addChild(_tableView);
- }
- bool IAPCtlShopUI::addAPlacement(const iap::IAPPlacement &plInfo){
- // 如果该活动ID存在,则添加失败
- if(_placements.count(plInfo.id) != 0)return false;
-
- _placements[plInfo.id] = plInfo;
-
- std::vector<DrawNode*> drawNode;
- _indicators[plInfo.id] = drawNode;
-
- return true;
- }
- void IAPCtlShopUI::removePlacement(const std::string &id){
- _placements.erase(id);
-
- _indicators.erase(id);
-
- }
- bool IAPCtlShopUI::addCardToPlacement(const std::string &id, iap::IAPCard *card){
- if(_placements.count(id) == 0)return false;
- _placements[id].cards.push_back(card);
- return true;
- }
- void IAPCtlShopUI::clearPlacement(){
- _placements.clear();
- _indicators.clear();
- }
- size_t IAPCtlShopUI::getPlacementCount(){
- return _placements.size();
- }
- void IAPCtlShopUI::_onNotifyDevelopment(const redutils::ReboltNotifyData& data) {
- if (data.notify == "绑定显示区域") {
- _ndScrollArea = data.outNode;
- } else if (data.notify == "绑定coin节点") {
- // _igCoin = new MapIGCoin(data.reboltRedManager);
- } else if (data.notify == "退出") {
- auto rm = RemoveSelf::create();
- auto cf = CallFunc::create([=]() {
- _layer->removeFromParent();
- _layer = nullptr;
- _bUIShowing = false;
- redutils::Platform::getInstance()->reportLog("iap closed");
- });
- _layer->runAction(Sequence::create(rm, cf, NULL));
- if (_cb) {
- _cb();
- }
- _cb = nullptr;
- }
- }
- void IAPCtlShopUI::constructShopItem(bool bShowAll) {
- int index = 0;
- _tableData.setCascadeOpacity(true);
- _tableData.clear();
- cocos2d::Size size = _ndScrollArea->getContentSize();
- auto delayIdx = 0;
- cocos2d::Vec2 offset(size.width, 0);
- float dur = 0.4;
- int height = 0;
-
- // 加入一个表头
- {
- Node* nd = Node::create();
- _tableData.insertCell(index++, nd);
- int h = size.height*0.08;
- _allSizes.push_back(cocos2d::Size(size.width, h));
- height += h;
- }
-
- // 重新获取
- if(bShowAll)IAPConf::getInstance()->getAllGoods(_goodsInfo);
- // 根据用户类型进行礼包排序
- switch (iap::IAPCtlShop::createWith()->getUserBuyType()) {
- case iap::UserBuyType::NoShopping:
- sortGoods(true);
- break;
- case iap::UserBuyType::LittleShopping:
- sortGoods(true);
- break;
- case iap::UserBuyType::NormalShopping:
- sortGoods(true);
- break;
- case iap::UserBuyType::LotShopping:
- sortGoods(false);
- break;
- default:
- break;
- }
- // 当前有效的区域
- int bigPackCount,smallPackCount; // 需要显示的礼包
- auto iapCtlShop = iap::IAPCtlShop::createWith();
- int leval = iapCtlShop->getDeviceLevel();
- size_t placementCount = iapCtlShop->getPlacementCount();
- switch(leval){
- case 1:
- // 低等级
- bigPackCount = 2;
- smallPackCount = 1;
- break;
- case 2:
- // 中等级
- break;
- case 3:
- if(placementCount >= 2){
- bigPackCount = 3;
- smallPackCount = 0;
- }else{
- bigPackCount = 2;
- smallPackCount = 2;
- }
- // 高等级
- break;
- default:
- break;
- }
-
- // 展示活动版位
- if(_placements.size() != 0){
- // 展示活动版位中的活动
- for(const auto& placement : _placements){
- bool isShow = false;
- if(bShowAll){
- isShow = true;
- }else{
- if(bigPackCount > 0){
- isShow = true;
- bigPackCount--;
- }
- }
- if(isShow){
- // 展示活动版位
- bool bNeedAnim = height <= size.height;
- Node* nd = Node::create();
- nd->setAnchorPoint(Vec2(0.5,0.5));
- nd->setContentSize(cocos2d::Size(584,250));
- nd->setCascadeOpacityEnabled(true);
- nd->setCascadeColorEnabled(true);
-
- auto si = createPlacementUI(placement.second);
- auto sz = cocos2d::Size(584,280);
- cocos2d::Vec2 pos(size.width/2.0, sz.height/2.0);
- nd->addChild(si);
- si->setPosition(bNeedAnim ? pos+offset : pos);
- _placementItems.push_back(nd);
- _tableData.insertCell(index++, nd);
- _allSizes.push_back(sz);
- height += sz.height;
-
- if (bNeedAnim) {
- // 加入动画
- auto d = DelayTime::create(delayIdx*dur/8.0);
- auto m = EaseBackOut::create(MoveBy::create(dur, cocos2d::Vec2(-offset.x, offset.y)));
- si->runAction(Sequence::create(d, m, NULL));
- delayIdx ++;
- }
-
- }
-
- }
- }
- // 判断是否还有版位
- if(bigPackCount != 0 || smallPackCount != 0 || bShowAll){
- // 显示常规商品
- for (const auto& gi : _goodsInfo) {
- // 判断是否显示
- bool isShow = false;
- if (bShowAll) {
- isShow = true;
- }else{
- if(gi.type == "panel" && bigPackCount > 0){
- isShow = true;
- bigPackCount--;
- }
- if(gi.type == "bar" && smallPackCount > 0){
- isShow = true;
- smallPackCount--;
- }
- }
- // 商品显示
- if (isShow) {
- bool bNeedAnim = height <= size.height;
- Node* nd = Node::create();
- nd->setCascadeOpacityEnabled(true);
- nd->setCascadeColorEnabled(true);
- auto si = IAPCtlShopItem::create(gi, _placementId);
- auto sz = si->getSize();
- cocos2d::Vec2 pos(size.width/2.0, sz.height/2.0);
- nd->addChild(si);
- si->setPosition(bNeedAnim ? pos+offset : pos);
- _goodsItems.push_back(si);
- _tableData.insertCell(index++, nd);
- _allSizes.push_back(sz);
- height += sz.height;
-
- if (bNeedAnim) {
- // 加入动画
- auto d = DelayTime::create(delayIdx*dur/8.0);
- auto m = EaseBackOut::create(MoveBy::create(dur, cocos2d::Vec2(-offset.x, offset.y)));
- si->runAction(Sequence::create(d, m, NULL));
- delayIdx ++;
- }
- }
- }
- }
-
- // 添加展示所有按钮
- if (!bShowAll) {
- // 加入show All btn, 这个是一定会有动画的
- auto sz = cocos2d::Size(584, 130);
- Node* nd = Node::create();
- nd->setCascadeOpacityEnabled(true);
- nd->setCascadeColorEnabled(true);
- _btnShowAll = redutils::RUReboltLayer::createReboltLayer("shop_more_btn.redream");
- nd->addChild(_btnShowAll);
- _btnShowAll->setPosition(Vec2(size.width/2.0, sz.height/2.0) + offset);
- _tableData.insertCell(index++, nd);
- _btnShowAll->registerOnNotify([this](const redutils::ReboltNotifyData& data){
- if (data.notify == "点击") {
- auto rm = RemoveSelf::create();
- auto cf = CallFunc::create([=](){
- _btnShowAll = NULL;
- _tableData.clear();
- _goodsItems.clear();
- _placementItems.clear();
- for(const auto& placement : _placements){
- _indicators[placement.first].clear();
- }
- _allSizes.clear();
- constructShopItem(true);
- _tableView->reloadData(true);
- });
- _btnShowAll->runAction(Sequence::create(rm, cf, NULL));
- }
- });
- redutils::iterateNode(nd, [](Node* nd){
- nd->setCascadeOpacityEnabled(true);
- nd->setCascadeColorEnabled(true);
- });
- _btnShowAll->runBehaviacWhitFunName("初始化");
- _allSizes.push_back(sz);
-
- // 加入动画
- auto d = DelayTime::create(delayIdx*dur/8.0);
- auto m = EaseBackOut::create(MoveBy::create(dur, cocos2d::Vec2(-offset.x, offset.y)));
- _btnShowAll->runAction(Sequence::create(d, m, NULL));
- delayIdx ++;
- } else {
- // 底部添加一个额外节点(一个是底部的广告,还有就是美观一些)
- _tableData.insertCell(index++, Node::create());
- _allSizes.push_back(cocos2d::Size(584, 150));
- }
-
- _tableData._numberOfCellsInTableView = [=](cocos2d::extension::TableViewSmooth*)->ssize_t{
- return _allSizes.size();
- };
- _tableData._tableCellSizeForIndex = [=](cocos2d::extension::TableViewSmooth*, ssize_t idx)->Size{
- if (idx < _allSizes.size()) {
- return _allSizes[idx];
- } else {
- return Size(0,0);
- }
- };
-
- // 防止拉动的时候才创建
- _layer->scheduleOnce([=](float){
- for (int i=0; i<_allSizes.size(); i++) {
- _tableView->updateCellAtIndex(i);
- }
- }, 0.05, "SCH_Update_Cells");
- }
- Node* IAPCtlShopUI::createPlacementUI(const iap::IAPPlacement& placement){
- Node* node = Node::create();
-
- // 创建 PageView 用于分页滑动卡片
- auto pageView = ui::PageView::create();
- pageView->setContentSize(cocos2d::Size(584, 250));
-
- // 创建指示点的父节点
- auto indicatorNode = Node::create();
- float spacing = 20.0f; // 每个指示点之间的间距
-
- // 遍历 placement 中的卡片,依次创建并添加到 PageView 中
- for (int i = 0; i < placement.cards.size(); i++) {
- // 创建每张卡片的布局容器(PageView 只能添加 Layout 类型的子节点)
- auto layout = ui::Layout::create();
- layout->setContentSize(cocos2d::Size(584, 250));
-
- auto card = placement.cards[i]->create(); // 假设 card 有 create 方法
-
- // 设置卡片的居中位置
- card->setPosition(Vec2(layout->getContentSize().width / 2, layout->getContentSize().height / 2));
- layout->addChild(card);
-
- // 将布局容器添加到 PageView 中
- pageView->addPage(layout);
-
- // 创建指示点
- auto indicator = DrawNode::create();
- Vec2 center(i * spacing, 0); // 水平排列指示点
- _indicators[placement.id].push_back(indicator);
-
- // 画白色圆点
- indicator->drawDot(center, 5, Color4F(1, 1, 1, 1)); // 白色指示点
- indicatorNode->addChild(indicator);
- }
-
- // 设置 PageView 的分页切换效果(滑动自动切换)
- pageView->setUsingCustomScrollThreshold(true); // 启用自定义滑动阈值
- pageView->setCustomScrollThreshold(50); // 设置触发翻页的滑动距离阈值
- pageView->setAutoScrollStopEpsilon(0.05f); // 提高自动滚动停止的精度
-
- // 设置指示点的位置,居中显示在卡片下方
- float indicatorNodeWidth = (placement.cards.size() - 1) * spacing;
- indicatorNode->setPosition(Vec2(pageView->getContentSize().width / 2 - indicatorNodeWidth / 2, 0)); // 调整y轴位置
- node->addChild(indicatorNode); // 将指示点容器添加到主节点中
- // 添加回调函数监听页面变化
- pageView->addEventListener([=](Ref* sender, ui::PageView::EventType type) {
- if (type == ui::PageView::EventType::TURNING) {
- log("滑动");
- auto pageView = dynamic_cast<ui::PageView*>(sender);
- int currentPageIndex = pageView->getCurrentPageIndex();
-
- // 更新指示点颜色,当前页的指示点变为红色,其他保持白色
- for (int i = 0; i < _indicators[placement.id].size(); i++) {
- _indicators[placement.id][i]->clear(); // 清除之前的绘制
- Color4F color = (i == currentPageIndex) ? Color4F(1, 0, 0, 1) : Color4F(1, 1, 1, 1); // 红色或白色
- _indicators[placement.id][i]->drawDot(Vec2(i * 20, 0), 5, color); // 更新指示点颜色
- }
- }
- });
-
- // 默认将第一页的指示点设为红色
- _indicators[placement.id][0]->drawDot(Vec2(0, 0), 5, Color4F(1, 0, 0, 1)); // 当前页红点
- // 将 PageView 添加到父节点 node 中
- node->addChild(pageView);
-
- return node;
- }
- void IAPCtlShopUI::filterGoods(iap::ShopRequirement &requirement){
- std::map<int, bool> m;
- int cnt = 0;
- for(const auto& goodInfo : _goodsInfo){
- if(goodInfo.getCoinNumber() >= requirement.coinsMin){
- m[cnt] = true;
- }
- cnt++;
- }
-
- std::vector<GoodsInfo> newGoodsInfo;
-
- // 添加符合条件的礼包
- for(int i = 0;i < _goodsInfo.size(); i++){
- if(m[i]){
- newGoodsInfo.push_back(_goodsInfo[i]);
- }
- }
- // 添加不符合条件的礼包(不清楚是不是需要显示,暂放到列表末尾)
- // for(int i = 0;i < _goodsInfo.size(); i++){
- // if(!m[i]){
- // newGoodsInfo.push_back(_goodsInfo[i]);
- // }
- // }
-
- _goodsInfo = newGoodsInfo;
- }
- void IAPCtlShopUI::sortGoods(bool flag){
-
- sort(_goodsInfo.begin(), _goodsInfo.end(), [flag](GoodsInfo a, GoodsInfo b){
- if(a.getTypeValue() != b.getTypeValue())return a.getTypeValue() > b.getTypeValue();
- if(flag) return a.getCostNumber() < b.getCostNumber();
- else return a.getCostNumber() > b.getCostNumber();
- });
-
- }
- void IAPCtlShopUI::quit() {
- if (_layer) {
- _layer->runBehaviacWhitFunName("退出");
- }
- }
|