// // 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 "IAPCardView.hpp" #include "IAPTestCardViewDelegate.hpp" #include "IAPRunTimeData.hpp" #include 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(); _failItems.clear(); for(const auto& placement : _placements){ _indicators[placement.first].clear(); } _allSizes.clear(); _cb = nullptr; } bool IAPCtlShopUI::create(Node* pNode, IAPConf* cfg, iapshop::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); } // 构建 list 区域 constructShopItem(false, requirement); 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; } bool IAPCtlShopUI::addAPlacement(const iapshop::IAPPlacement &plInfo){ // 如果该活动ID存在,则添加失败 if(_placements.count(plInfo.id) != 0)return false; _placements[plInfo.id] = plInfo; std::vector nodeVec; _indicators[plInfo.id] = nodeVec; return true; } void IAPCtlShopUI::removePlacement(const std::string &id){ _placements.erase(id); _indicators.erase(id); } bool IAPCtlShopUI::addCardToPlacement(const std::string &id, iapshop::IAPCard *card){ if(_placements.count(id) == 0)return false; _placements[id].cards.push_back(card); return true; } bool IAPCtlShopUI::removeCardToPlacement(const std::string id, int cardIndex){ if(_placements.count(id) == 0)return false; if(cardIndex < 0 || cardIndex >= _placements[id].cards.size()){ return false; } _placements[id].cards.erase(_placements[id].cards.begin() + cardIndex); 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, iapshop::ShopRequirement& requirement) { 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; } // 开始构建 // 获取礼包信息 IAPConf::getInstance()->getAllGoods(_goodsInfo); // 获取版位信息 int bigPackCount,smallPackCount; // 需要显示的礼包 auto iapCtlShop = iapshop::IAPCtlShop::createWith(); auto userBuyType = iapshop::IAPRunTimeData::getInstance()->getUserBuyType(); int leval = iapshop::IAPRunTimeData::getInstance()->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 ++; } } } } // 根据用户类型进行礼包排序 switch (userBuyType) { case iapshop::UserBuyType::NoShopping: sortGoods(true); break; case iapshop::UserBuyType::LittleShopping: sortGoods(true); break; case iapshop::UserBuyType::NormalShopping: sortGoods(true); break; case iapshop::UserBuyType::LotShopping: sortGoods(false); break; default: break; } // 判断是否展示全部 if(!bShowAll){ // 不展示全部,过滤掉不合格的礼包 filterGoods(requirement); } // 判断是否为正常消费 if(userBuyType == iapshop::UserBuyType::NormalShopping && !bShowAll){ // (当前已按 大礼包 > 小礼包,金额小 > 金额大 的优先级排序) // 获取购买过的最大金额 float maxn = iapshop::IAPRunTimeData::getInstance()->getUserBuyMaxAmount(); // 构建大礼包 if(bigPackCount == 2){ // 查找购买过的最高金额更高一级对应的常规礼包 int nowAmount = INT_MAX; int nowIndex = -1; for(int i = 0; i < _goodsInfo.size(); i++){ if(_goodsInfo[i].type != "panel")continue; if(_goodsInfo[i].getCostNumber() <= maxn)continue; if(nowAmount > _goodsInfo[i].getCostNumber()){ nowAmount = _goodsInfo[i].getCostNumber(); nowIndex = i; } } if(nowIndex != -1){ bool bNeedAnim = height <= size.height; Node* nd = Node::create(); nd->setCascadeOpacityEnabled(true); nd->setCascadeColorEnabled(true); auto si = IAPCtlShopItem::create(_goodsInfo[nowIndex], _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 ++; } } bigPackCount--; } if(bigPackCount == 1){ // 查找购买过最高金额所对应的常规礼包 int nowAmount = INT_MIN; int nowIndex = -1; for(int i = 0; i < _goodsInfo.size(); i++){ if(_goodsInfo[i].type != "panel")continue; if(_goodsInfo[i].getCostNumber() > maxn)continue; if(nowAmount <= _goodsInfo[i].getCostNumber()){ nowAmount = _goodsInfo[i].getCostNumber(); nowIndex = i; } } if(nowIndex != -1){ bool bNeedAnim = height <= size.height; Node* nd = Node::create(); nd->setCascadeOpacityEnabled(true); nd->setCascadeColorEnabled(true); auto si = IAPCtlShopItem::create(_goodsInfo[nowIndex], _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 ++; } } bigPackCount--; } // 构建小礼包 if(smallPackCount == 2){ // 查找购买过的最高金额更高一级对应的金币礼包 int nowAmount = INT_MAX; int nowIndex = -1; for(int i = 0; i < _goodsInfo.size(); i++){ if(_goodsInfo[i].type != "bar")continue; if(_goodsInfo[i].getCostNumber() <= maxn)continue; if(nowAmount > _goodsInfo[i].getCostNumber()){ nowAmount = _goodsInfo[i].getCostNumber(); nowIndex = i; } } if(nowIndex != -1){ bool bNeedAnim = height <= size.height; Node* nd = Node::create(); nd->setCascadeOpacityEnabled(true); nd->setCascadeColorEnabled(true); auto si = IAPCtlShopItem::create(_goodsInfo[nowIndex], _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 ++; } } smallPackCount--; } if(smallPackCount == 1){ // 查找购买过最高金额所对应的金币礼包 int nowAmount = INT_MIN; int nowIndex = -1; for(int i = 0; i < _goodsInfo.size(); i++){ if(_goodsInfo[i].type != "bar")continue; if(_goodsInfo[i].getCostNumber() > maxn)continue; if(nowAmount <= _goodsInfo[i].getCostNumber()){ nowAmount = _goodsInfo[i].getCostNumber(); nowIndex = i; } } if(nowIndex != -1){ bool bNeedAnim = height <= size.height; Node* nd = Node::create(); nd->setCascadeOpacityEnabled(true); nd->setCascadeColorEnabled(true); auto si = IAPCtlShopItem::create(_goodsInfo[nowIndex], _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 ++; } } smallPackCount--; } }else{ // 判断是否还有版位 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(); iapshop::ShopRequirement req; req.coinsMin = 0; constructShopItem(true, req); _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 iapshop::IAPPlacement& placement){ Node* node = Node::create(); IAPCardView::sDotCfg cfg; cfg.hightSp = "内购版位_通用_图标_滑动点_已选中.png"; cfg.normalSp = "内购版位_通用_图标_滑动点_未选中.png"; cfg.sepWidth = 30.0f; cfg.yStart = 0; cocos2d::Size sz = cocos2d::Size(584, 250); IAPCardView* cardView = IAPCardView::create(sz, cfg); IAPTestCardViewDelegate* cardViewDelegate = new IAPTestCardViewDelegate(); cardView->setDelegate(cardViewDelegate); // 遍历 placement 中的卡片,依次创建并添加到 PageView 中 for (int i = 0; i < placement.cards.size(); i++) { cardView->addCard(placement.cards[i]->create()); } // 将 PageView 添加到父节点 node 中 node->addChild(cardView); return node; } void IAPCtlShopUI::filterGoods(iapshop::ShopRequirement &requirement){ std::map m; int cnt = 0; for(const auto& goodInfo : _goodsInfo){ if(goodInfo.getCoinNumber() >= requirement.coinsMin){ m[cnt] = true; } cnt++; } std::vector 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("退出"); } }