IAPCtlShopUI.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. //
  2. // IAPCtlShopUI.cpp
  3. // TileManor
  4. //
  5. // Created by 徐炼新 on 2024/1/16.
  6. //
  7. #include "IAPCtlShop.hpp"
  8. #include "RUUtils.h"
  9. #include "RUPlatform.h"
  10. #include "IAPConf.hpp"
  11. #include "IAPCtlShopUI.hpp"
  12. #include "IAPCtlShopItem.hpp"
  13. #include <regex>
  14. IAPCtlShopUI* IAPCtlShopUI::_instance = nullptr;
  15. IAPCtlShopUI* IAPCtlShopUI::getInstance() {
  16. if (_instance == nullptr) {
  17. _instance = new IAPCtlShopUI();
  18. _instance->autorelease();
  19. _instance->retain();
  20. }
  21. return _instance;
  22. }
  23. IAPCtlShopUI::IAPCtlShopUI() {
  24. }
  25. IAPCtlShopUI::~IAPCtlShopUI() {
  26. }
  27. bool IAPCtlShopUI::isShowing() {
  28. return _bUIShowing;
  29. }
  30. void IAPCtlShopUI::clear() {
  31. _goodsInfo.clear();
  32. for (auto& gi : _goodsItems) {
  33. gi->release();
  34. }
  35. _goodsItems.clear();
  36. _allSizes.clear();
  37. _cb = nullptr;
  38. }
  39. bool IAPCtlShopUI::create(Node* pNode, IAPConf* cfg, iap::ShopRequirement& requirement,int placementId) {
  40. redutils::Platform::getInstance()->reportLog("open iap");
  41. _cfg = cfg;
  42. _bUIShowing = true;
  43. _placementId = placementId;
  44. clear();
  45. _layer = redutils::RUReboltLayer::createReboltLayer("shop_interface.redream");
  46. pNode->addChild(_layer, 3);
  47. _layer->registerOnNotify([this](const redutils::ReboltNotifyData& data){
  48. _onNotifyDevelopment(data);
  49. });
  50. _layer->runBehaviacWhitFunName("初始化");
  51. // _igCoin->doOwnInit();
  52. if (_goodsInfo.size() == 0) {
  53. IAPConf::getInstance()->getAllGoods(_goodsInfo);
  54. }
  55. // 过滤掉不符合的金币
  56. filterGoods(requirement);
  57. // 构建 list 区域
  58. constructShopItem(false);
  59. cocos2d::Size size = _ndScrollArea->getContentSize();
  60. _tableView = redutils::RUTableView::create(&_tableData, cocos2d::Size(size.width, size.height));
  61. _tableView->setCascadeOpacityEnabled(true);
  62. _tableView->setCascadeColorEnabled(true);
  63. _tableView->setDirection(ScrollViewSmooth::Direction::VERTICAL);
  64. _tableView->setVerticalFillOrder(TableViewSmooth::VerticalFillOrder::TOP_DOWN, false);
  65. _tableView->setDelegate(&_tableData);
  66. _tableView->setBounceable(true);
  67. // _tableView->setOutSightClean(false);
  68. _ndScrollArea->addChild(_tableView);
  69. return true;
  70. }
  71. void IAPCtlShopUI::_onNotifyDevelopment(const redutils::ReboltNotifyData& data) {
  72. if (data.notify == "绑定显示区域") {
  73. _ndScrollArea = data.outNode;
  74. } else if (data.notify == "绑定coin节点") {
  75. // _igCoin = new MapIGCoin(data.reboltRedManager);
  76. } else if (data.notify == "退出") {
  77. auto rm = RemoveSelf::create();
  78. auto cf = CallFunc::create([=]() {
  79. _layer->removeFromParent();
  80. _layer = nullptr;
  81. _bUIShowing = false;
  82. redutils::Platform::getInstance()->reportLog("iap closed");
  83. });
  84. _layer->runAction(Sequence::create(rm, cf, NULL));
  85. if (_cb) {
  86. _cb();
  87. }
  88. _cb = nullptr;
  89. }
  90. }
  91. void IAPCtlShopUI::constructShopItem(bool bShowAll) {
  92. int index = 0;
  93. _tableData.setCascadeOpacity(true);
  94. _tableData.clear();
  95. cocos2d::Size size = _ndScrollArea->getContentSize();
  96. auto delayIdx = 0;
  97. cocos2d::Vec2 offset(size.width, 0);
  98. float dur = 0.4;
  99. int height = 0;
  100. // 加入一个表头
  101. {
  102. Node* nd = Node::create();
  103. _tableData.insertCell(index++, nd);
  104. int h = size.height*0.08;
  105. _allSizes.push_back(cocos2d::Size(size.width, h));
  106. height += h;
  107. }
  108. // 重新获取
  109. if(bShowAll)IAPConf::getInstance()->getAllGoods(_goodsInfo);
  110. // 根据用户类型进行礼包排序
  111. switch (iap::IAPCtlShop::createWith()->getUserBuyType()) {
  112. case iap::UserBuyType::NoShopping:
  113. sortGoods(true);
  114. break;
  115. case iap::UserBuyType::LittleShopping:
  116. sortGoods(true);
  117. break;
  118. case iap::UserBuyType::NormalShopping:
  119. sortGoods(true);
  120. break;
  121. case iap::UserBuyType::LotShopping:
  122. sortGoods(false);
  123. break;
  124. default:
  125. break;
  126. }
  127. // 当前有效的区域
  128. int bigPackCount,smallPackCount; // 需要显示的礼包
  129. auto iapCtlShop = iap::IAPCtlShop::createWith();
  130. int leval = iapCtlShop->getDeviceLevel();
  131. size_t placementCount = iapCtlShop->getPlacementCount();
  132. switch(leval){
  133. case 1:
  134. // 低等级
  135. bigPackCount = 2;
  136. smallPackCount = 1;
  137. break;
  138. case 2:
  139. // 中等级
  140. break;
  141. case 3:
  142. if(placementCount >= 2){
  143. bigPackCount = 3;
  144. smallPackCount = 0;
  145. }else{
  146. bigPackCount = 2;
  147. smallPackCount = 2;
  148. }
  149. // 高等级
  150. break;
  151. default:
  152. break;
  153. }
  154. // 展示活动商品
  155. // 判断是否还有版位
  156. if(bigPackCount != 0 || smallPackCount != 0 || bShowAll){
  157. // 显示常规商品
  158. for (const auto& gi : _goodsInfo) {
  159. // 判断是否显示
  160. bool isShow = false;
  161. if (bShowAll) {
  162. isShow = true;
  163. }else{
  164. if(gi.type == "panel" && bigPackCount > 0){
  165. isShow = true;
  166. bigPackCount--;
  167. }
  168. if(gi.type == "bar" && smallPackCount > 0){
  169. isShow = true;
  170. smallPackCount--;
  171. }
  172. }
  173. // 商品显示
  174. if (isShow) {
  175. bool bNeedAnim = height <= size.height;
  176. Node* nd = Node::create();
  177. nd->setCascadeOpacityEnabled(true);
  178. nd->setCascadeColorEnabled(true);
  179. auto si = IAPCtlShopItem::create(gi, _placementId);
  180. auto sz = si->getSize();
  181. cocos2d::Vec2 pos(size.width/2.0, sz.height/2.0);
  182. nd->addChild(si);
  183. si->setPosition(bNeedAnim ? pos+offset : pos);
  184. _goodsItems.push_back(si);
  185. _tableData.insertCell(index++, nd);
  186. _allSizes.push_back(sz);
  187. height += sz.height;
  188. if (bNeedAnim) {
  189. // 加入动画
  190. auto d = DelayTime::create(delayIdx*dur/8.0);
  191. auto m = EaseBackOut::create(MoveBy::create(dur, cocos2d::Vec2(-offset.x, offset.y)));
  192. si->runAction(Sequence::create(d, m, NULL));
  193. delayIdx ++;
  194. }
  195. }
  196. }
  197. }
  198. // 添加展示所有按钮
  199. if (!bShowAll) {
  200. // 加入show All btn, 这个是一定会有动画的
  201. auto sz = cocos2d::Size(584, 130);
  202. Node* nd = Node::create();
  203. nd->setCascadeOpacityEnabled(true);
  204. nd->setCascadeColorEnabled(true);
  205. _btnShowAll = redutils::RUReboltLayer::createReboltLayer("shop_more_btn.redream");
  206. nd->addChild(_btnShowAll);
  207. _btnShowAll->setPosition(Vec2(size.width/2.0, sz.height/2.0) + offset);
  208. _tableData.insertCell(index++, nd);
  209. _btnShowAll->registerOnNotify([this](const redutils::ReboltNotifyData& data){
  210. if (data.notify == "点击") {
  211. auto rm = RemoveSelf::create();
  212. auto cf = CallFunc::create([=](){
  213. _btnShowAll = NULL;
  214. _tableData.clear();
  215. _goodsItems.clear();
  216. _allSizes.clear();
  217. constructShopItem(true);
  218. _tableView->reloadData(true);
  219. });
  220. _btnShowAll->runAction(Sequence::create(rm, cf, NULL));
  221. }
  222. });
  223. redutils::iterateNode(nd, [](Node* nd){
  224. nd->setCascadeOpacityEnabled(true);
  225. nd->setCascadeColorEnabled(true);
  226. });
  227. _btnShowAll->runBehaviacWhitFunName("初始化");
  228. _allSizes.push_back(sz);
  229. // 加入动画
  230. auto d = DelayTime::create(delayIdx*dur/8.0);
  231. auto m = EaseBackOut::create(MoveBy::create(dur, cocos2d::Vec2(-offset.x, offset.y)));
  232. _btnShowAll->runAction(Sequence::create(d, m, NULL));
  233. delayIdx ++;
  234. } else {
  235. // 底部添加一个额外节点(一个是底部的广告,还有就是美观一些)
  236. _tableData.insertCell(index++, Node::create());
  237. _allSizes.push_back(cocos2d::Size(584, 150));
  238. }
  239. _tableData._numberOfCellsInTableView = [=](cocos2d::extension::TableViewSmooth*)->ssize_t{
  240. return _allSizes.size();
  241. };
  242. _tableData._tableCellSizeForIndex = [=](cocos2d::extension::TableViewSmooth*, ssize_t idx)->Size{
  243. if (idx < _allSizes.size()) {
  244. return _allSizes[idx];
  245. } else {
  246. return Size(0,0);
  247. }
  248. };
  249. // 防止拉动的时候才创建
  250. _layer->scheduleOnce([=](float){
  251. for (int i=0; i<_allSizes.size(); i++) {
  252. _tableView->updateCellAtIndex(i);
  253. }
  254. }, 0.05, "SCH_Update_Cells");
  255. }
  256. void IAPCtlShopUI::filterGoods(iap::ShopRequirement &requirement){
  257. std::map<int, bool> m;
  258. int cnt = 0;
  259. for(const auto& goodsInfo : _goodsInfo){
  260. for(const auto area : goodsInfo.areas){
  261. bool flag = false;
  262. for(int i = 0;i < area.size(); i++){
  263. if(area[i].name != "coin")continue;
  264. if(std::stoi(area[i].count) >= requirement.coinsMin){
  265. m[cnt] = true;
  266. flag = true;
  267. break;
  268. }else{
  269. m[cnt] = false;
  270. flag = true;
  271. break;
  272. }
  273. }
  274. if(flag)break;
  275. }
  276. cnt++;
  277. }
  278. std::vector<GoodsInfo> newGoodsInfo;
  279. // 添加符合条件的礼包
  280. for(int i = 0;i < _goodsInfo.size(); i++){
  281. if(m[i]){
  282. newGoodsInfo.push_back(_goodsInfo[i]);
  283. }
  284. }
  285. // 添加不符合条件的礼包(不清楚是不是需要显示,暂放到列表末尾)
  286. // for(int i = 0;i < _goodsInfo.size(); i++){
  287. // if(!m[i]){
  288. // newGoodsInfo.push_back(_goodsInfo[i]);
  289. // }
  290. // }
  291. _goodsInfo = newGoodsInfo;
  292. }
  293. void IAPCtlShopUI::sortGoods(bool flag){
  294. sort(_goodsInfo.begin(), _goodsInfo.end(), [flag](GoodsInfo a, GoodsInfo b){
  295. if(a.type != b.type){
  296. if(a.type == "panel"){
  297. return true;
  298. }else if(b.type == "panel"){
  299. return false;
  300. }
  301. }
  302. float val_a,val_b;
  303. std::regex re(R"(\d+(\.\d{1,2})?)"); // 匹配整数或最多两位小数的数字
  304. std::smatch match;
  305. if (std::regex_search(a.cost, match, re)) {
  306. val_a = stof(match[0]); // 提取价格
  307. } else {
  308. log("IAPUserData::getUserBuyType : 转换失败");
  309. }
  310. if (std::regex_search(b.cost, match, re)) {
  311. val_b = stof(match[0]); // 提取价格
  312. } else {
  313. log("IAPUserData::getUserBuyType : 转换失败");
  314. }
  315. if(flag) return val_a < val_b;
  316. else return val_a > val_b;
  317. });
  318. }
  319. void IAPCtlShopUI::quit() {
  320. if (_layer) {
  321. _layer->runBehaviacWhitFunName("退出");
  322. }
  323. }