IAPCtlShopUI.cpp 11 KB

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