vgsDetailContainer.py (20492B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\view\aurumstore\vgsDetailContainer.py 2 import blue 3 import logging 4 import math 5 import time 6 import uthread 7 from carbonui import const as uiconst 8 from carbonui.primitives.container import Container 9 from carbonui.primitives.containerAutoSize import ContainerAutoSize 10 from carbonui.primitives.fill import Fill 11 from carbonui.primitives.gradientSprite import GradientSprite 12 from carbonui.uianimations import animations 13 from carbonui.uicore import uicore 14 from carbonui.util.color import Color 15 from eve.client.script.ui.control.eveLabel import EveLabelMedium 16 from eve.client.script.ui.control.eveLoadingWheel import LoadingWheel 17 from eve.client.script.ui.shared.redeem.redeemPanel import GetOldRedeemPanel 18 from eve.client.script.ui.shared.redeem.oldRedeemPanel import StaticRedeemContainer 19 from eve.client.script.ui.shared.vgs.headerButton import HeaderButton 20 from eve.client.script.ui.shared.vgs.kiringPaymentProvider import get_element_for_payment_provider 21 from eve.client.script.ui.shared.vgs.priceTag import PriceTagLarge 22 from eve.client.script.ui.view.aurumstore.purchasepanels.purchaseDetailsPanel import PurchaseDetailsPanel 23 from eve.client.script.ui.view.aurumstore.purchasepanels.purchaseProgressPanel import PurchaseProgressPanel 24 from eve.client.script.ui.view.aurumstore.purchasepanels.purchaseResultPanel import PurchaseResultPanel 25 from eve.client.script.ui.view.aurumstore.shared.const import TEXT_PADDING, PROGRESS_TRANSITION_TIME, CONTAINER_WIDTH, CONTAINER_WIDTH_LARGE, CONTAINER_WIDTH_SMALL, TOP_PANEL_HEIGHT, TOP_PANEL_HEIGHT_LARGE, TOP_PANEL_HEIGHT_SMALL, MIN_SCREEN_HEIGHT_FOR_LARGE, MIN_SCREEN_HEIGHT_FOR_SMALL, BOTTOM_PANEL_HEIGHT, FRAME_COLOR, EXIT_BUTTON_PADDING, FRAME_WIDTH, STORE_PREVIEW_OVERLAY_HEIGHT 26 from eve.common.script.sys.eveCfg import IsPreviewable, IsBlueprint 27 from eve.client.script.ui.view.aurumstore.shared.offerpricing import get_number_of_available_currencies 28 from eve.client.script.ui.view.aurumstore.shared.util import GetSortedTokens 29 from eve.client.script.ui.view.aurumstore.vgsOffer import Ribbon, VgsOfferPreview 30 from eve.client.script.ui.view.aurumstore.vgsUiConst import BACKGROUND_COLOR, BUY_BUTTON_COLOR, HEADER_BG_COLOR, REDEEM_BUTTON_BACKGROUND_COLOR, REDEEM_BUTTON_FILL_COLOR 31 from eve.client.script.ui.view.aurumstore.vgsUiPrimitives import VgsLabelSmall, DetailButton, ExitButton, LazyUrlSprite, VgsLabelMedium 32 from fastcheckout.const import WINDOW_COLOR, FROM_NES_PRODUCT 33 from kiring.client.apigateway import KiringPaymentActionID, get_kiring_api_gateway, KiringOrder 34 from localization import GetByLabel 35 logger = logging.getLogger(__name__) 36 37 class VgsDetailContainer(Container): 38 __notifyevents__ = ['OnGiftingPanelActivated', 'OnGiftingPurchasePressed'] 39 default_name = 'VgsDetailContainer' 40 default_state = uiconst.UI_PICKCHILDREN 41 frameColor = Color.GRAY9 42 default_align = uiconst.TOALL 43 44 def ApplyAttributes(self, attributes): 45 super(VgsDetailContainer, self).ApplyAttributes(attributes) 46 sm.RegisterNotify(self) 47 self.vgsUiController = attributes.vgsUiController 48 self.offer = attributes.offer 49 self.qrCodeCont = None 50 fullWidth, fullHeight = self.GetAbsoluteSize() 51 self.backgroundBottomContainer = ContainerAutoSize(parent=self, name='backgroundBottomContainer', align=uiconst.TOBOTTOM_NOPUSH, state=uiconst.UI_PICKCHILDREN, width=fullWidth) 52 self.backgroundTopContainer = Container(parent=self, name='backgroundTopContainer', align=uiconst.TOBOTTOM, state=uiconst.UI_PICKCHILDREN, height=fullHeight, width=fullWidth) 53 if self._doMakeCardLarge(fullHeight): 54 self.contWidth = CONTAINER_WIDTH_LARGE 55 self.contTopWidth = TOP_PANEL_HEIGHT_LARGE 56 elif self._doMakeCardSmall(fullHeight): 57 self.contWidth = CONTAINER_WIDTH_SMALL 58 self.contTopWidth = TOP_PANEL_HEIGHT_SMALL 59 else: 60 self.contWidth = CONTAINER_WIDTH 61 self.contTopWidth = TOP_PANEL_HEIGHT 62 self.offerContainer = Container(parent=self.backgroundTopContainer, name='offerContainer', state=uiconst.UI_NORMAL, align=uiconst.CENTER, width=self.contWidth, height=self.contTopWidth + BOTTOM_PANEL_HEIGHT, bgColor=BACKGROUND_COLOR) 63 self.preview_fill = Fill(parent=self.offerContainer, align=uiconst.TOALL, opacity=0, color=WINDOW_COLOR) 64 self.loading_wheel = LoadingWheel(parent=self.offerContainer, align=uiconst.CENTER, state=uiconst.UI_DISABLED, opacity=0) 65 self.main_container = Container(name='MainContainer', parent=self.offerContainer, align=uiconst.TOALL) 66 Fill(bgParent=self.main_container, color=FRAME_COLOR, padding=-FRAME_WIDTH) 67 previewOverlay = Container(name='previewOverlay', parent=self.main_container, align=uiconst.TOTOP_NOPUSH, height=STORE_PREVIEW_OVERLAY_HEIGHT) 68 if self.offer.label is not None: 69 Ribbon(parent=previewOverlay, align=uiconst.TOPLEFT, text=self.offer.label.description, texture_path=self.offer.label.url, state=uiconst.UI_DISABLED, idx=0, isBig=True, padding=(-20, -10, 0, 0)) 70 exitButton = ExitButton(parent=previewOverlay, align=uiconst.TOPRIGHT, onClick=self.CloseOffer, top=EXIT_BUTTON_PADDING, left=EXIT_BUTTON_PADDING) 71 GradientSprite(bgParent=previewOverlay, rgbData=[(0.0, (0.0, 0.0, 0.0)), (1.0, (0.0, 0.0, 0.0))], alphaData=[(0.0, 0.5), (1.0, 0.0)], rotation=-math.pi / 2.0) 72 self.backButton = HeaderButton(parent=self.main_container, align=uiconst.TOPRIGHT, left=EXIT_BUTTON_PADDING, top=EXIT_BUTTON_PADDING + exitButton.height + 2, texturePath='res:/UI/Texture/Vgs/back.png', hint=GetByLabel('UI/Commands/Back'), onClick=self.OnBackButtonClicked, state=uiconst.UI_HIDDEN) 73 self.preview = VgsOfferPreview(parent=self.main_container, align=uiconst.TOTOP, height=self.contTopWidth, offer=self.offer) 74 self.CreateBottomLayout(self.offer, attributes.plexBalance) 75 self.CreateFakeRedeemPanel() 76 self.kiringApiGateway = get_kiring_api_gateway() 77 78 def _isPreviewableOffer(self): 79 for product in self.offer.productQuantities.itervalues(): 80 typeID = product.typeId 81 if IsBlueprint(typeID) or IsPreviewable(typeID): 82 return True 83 return False 84 85 def _doMakeCardLarge(self, windowHeight): 86 return self._isPreviewableOffer() and MIN_SCREEN_HEIGHT_FOR_LARGE <= windowHeight 87 88 def _doMakeCardSmall(self, windowHeight): 89 return MIN_SCREEN_HEIGHT_FOR_SMALL >= windowHeight 90 91 def CreateBottomLayout(self, offer, plexBalance): 92 self.bottomContainer = Container(name='bottomContainer', parent=self.main_container, align=uiconst.TOTOP, clipChildren=True, height=BOTTOM_PANEL_HEIGHT) 93 Fill(align=uiconst.TOALL, bgParent=self.bottomContainer, color=HEADER_BG_COLOR) 94 GradientSprite(align=uiconst.TOALL, bgParent=self.bottomContainer, rgbData=((0.0, (0.0, 0.0, 0.0)), (1.0, (0.0, 0.0, 0.0))), alphaData=((0.0, 0.8), (0.2, 0.6), (0.6, 0.0)), rotation=math.pi * 0.4) 95 self.continueButton = DetailButton(name='ContinueShoppingButton', parent=self.bottomContainer, align=uiconst.CENTERBOTTOM, label=GetByLabel('UI/VirtualGoodsStore/ContinueShopping'), color=BUY_BUTTON_COLOR, state=uiconst.UI_HIDDEN, opacity=0, top=10, onClick=self.CloseOffer) 96 currency, price = (None, None) 97 if get_number_of_available_currencies(offer) == 1: 98 offerPricing = offer.offerPricings[0] 99 currency = offerPricing.currency 100 price = offerPricing.price 101 self.purchaseDetailsPanel = PurchaseDetailsPanel(parent=self.bottomContainer, offer=offer, plexBalance=plexBalance, buyOfferCallback=self.vgsUiController.BuyOffer, previewCallback=self.OnPreviewType, kiringPaymentInitiationCallback=self.OnKiringPaymentInitiated, state=uiconst.UI_PICKCHILDREN, width=self.contWidth, buyAurumFunc=lambda : uicore.cmd.CmdBuyPlex(logContext=FROM_NES_PRODUCT), backButton=self.backButton, currency=currency, price=price) 102 self.activeBottomPanel = self.purchaseDetailsPanel 103 self.purchaseProgressPanel = PurchaseProgressPanel(parent=self.bottomContainer, width=self.contWidth) 104 self.purchaseSuccessPanel = PurchaseResultPanel(parent=self.bottomContainer, closeOfferCallback=self.CloseOffer, iconForegroundTexturePath='res:/UI/Texture/vgs/purchase_success_fg.png', iconBackgroundTexturePath='res:/UI/Texture/vgs/purchase_success_bg.png', textTitle=GetByLabel('UI/VirtualGoodsStore/Purchase/Completed'), audioEventName='store_purchase_success', width=self.contWidth) 105 self.purchaseFailurePanel = PurchaseResultPanel(parent=self.bottomContainer, closeOfferCallback=self.CloseOffer, iconForegroundTexturePath='res:/UI/Texture/vgs/purchase_fail_fg.png', iconBackgroundTexturePath='res:/UI/Texture/vgs/purchase_fail_bg.png', textTitle=GetByLabel('UI/VirtualGoodsStore/Purchase/Failed'), audioEventName='store_purchase_failure', width=self.contWidth) 106 self.purchaseFailureReasonLabel = VgsLabelSmall(parent=self.purchaseFailurePanel, align=uiconst.TOTOP, padding=(TEXT_PADDING, 107 TEXT_PADDING, 108 TEXT_PADDING, 109 0)) 110 111 def OnBackButtonClicked(self, *args): 112 self.purchaseDetailsPanel.ReconstructPanel(animate=True) 113 114 def fade_in_fill(self, opacity = 1.0): 115 animations.FadeIn(self.preview_fill, endVal=opacity, duration=0.5) 116 self.preview_fill.Enable() 117 animations.FadeIn(self.loading_wheel, duration=0.5) 118 119 def fade_out_fill(self): 120 self.open_offer_view() 121 animations.FadeOut(self.preview_fill, duration=0.5) 122 self.preview_fill.Disable() 123 animations.FadeOut(self.loading_wheel, duration=0.3) 124 125 def open_offer_view(self): 126 self.bottomContainer.SetState(uiconst.UI_NORMAL) 127 self.preview.SetState(uiconst.UI_NORMAL) 128 129 def CreateRedeemPanel(self, offer, offerQuantity): 130 self.redeemContainer = StaticRedeemContainer(parent=self.purchaseSuccessPanel, name='offerRedeemQueueContent', align=uiconst.TOTOP, padTop=TEXT_PADDING, redeemTokens=GetSortedTokens(offer.productQuantities), offerQuantity=offerQuantity, clipChildren=False, containerWidth=self.contWidth, dragEnabled=False, minimizeTokens=True) 131 self.successDescriptionText = VgsLabelSmall(parent=self.purchaseSuccessPanel, align=uiconst.TOTOP, text='', padding=(TEXT_PADDING, 132 TEXT_PADDING, 133 TEXT_PADDING, 134 0)) 135 self.successDescriptionText.opacity = 0.0 136 137 def CreateFakeRedeemPanel(self): 138 instructionText = '<url=localsvc:method=ShowRedeemUI>%s</url>' % (GetByLabel('UI/RedeemWindow/ClickToInitiateRedeeming'),) 139 redeemPanelClass = GetOldRedeemPanel() 140 self.fakeRedeemingPanel = redeemPanelClass(parent=self.backgroundBottomContainer, name='fakeRedeemPanel', align=uiconst.TOBOTTOM, dragEnabled=False, redeemButtonBackgroundColor=REDEEM_BUTTON_BACKGROUND_COLOR, redeemButtonFillColor=REDEEM_BUTTON_FILL_COLOR, buttonClick=None, instructionText=instructionText) 141 self.fakeRedeemingPanel.UpdateDisplay(animate=False) 142 self.fakeRedeemingPanel.HidePanel(animate=False) 143 self.vgsUiController.view.storeContainer.redeemingPanel.HidePanel() 144 self.vgsUiController.view.storeContainer.redeemingPanel.SetListenToRedeemQueueUpdatedEvents(False) 145 146 def OnPreviewType(self, typeID): 147 self.preview.typeID = typeID 148 149 def ConstructPaymentElement(self, paymentMethod, currency, price): 150 if self.qrCodeCont: 151 self.qrCodeCont.CloseByUser(sleep=True) 152 self.qrCodeCont = QRCodeContainer(parent=self, align=uiconst.CENTER, width=350, height=450, idx=0, opacity=0.0, paymentMethod=paymentMethod, currency=currency, price=price, offerName=self.offer.name, account=self.kiringApiGateway.name, onClose=self.OnQRCodeContClose) 153 self.fade_in_fill(0.7) 154 155 def OnQRCodeContClose(self): 156 self.fade_out_fill() 157 158 def OnKiringPaymentInitiated(self, paymentMethod, currency, price, goodsID, quantity, offerID): 159 self.ConstructPaymentElement(paymentMethod, currency, price * quantity) 160 unixTimestamp = time.time() 161 order = KiringOrder(session.charid, goodsID, quantity, unixTimestamp, on_success=lambda : self.OnKiringPaymentSuccessful(offerID), on_failure=self.OnKiringPaymentFailed) 162 try: 163 paymentAction = self.kiringApiGateway.place_order(order, paymentMethod) 164 except Exception as ex: 165 self.OnKiringPaymentFailed(GetByLabel('UI/VirtualGoodsStore/Kiring/CannotConnectToPaymentProvider')) 166 raise ex 167 168 if paymentAction is None: 169 self.OnKiringPaymentFailed(GetByLabel('UI/VirtualGoodsStore/Kiring/CannotConnectToPaymentProvider')) 170 logger.error('No payment action returned from server') 171 elif paymentAction.actionID == KiringPaymentActionID.OPEN_WEBSITE: 172 self.qrCodeCont.OpenPaymentUrl(paymentAction.url) 173 elif paymentAction.actionID == KiringPaymentActionID.SCAN_QR_CODE: 174 self.qrCodeCont.ShowQrCode(paymentAction.url, self.kiringApiGateway.name) 175 176 def OnKiringPaymentSuccessful(self, offerID): 177 self.qrCodeCont.CloseByUser() 178 sm.GetService('vgsService').GetStore().ClearCache() 179 self.SwitchToSuccessPanel(self.purchaseDetailsPanel.GetQuantity(), session.charid) 180 self.vgsUiController.view.storeContainer.OnOfferPurchase(offerID) 181 182 def OnKiringPaymentFailed(self, reason = None): 183 self.qrCodeCont.CloseByUser() 184 self.SwitchToFailurePanel(reason) 185 186 def OpenFakeRedeemPanel(self): 187 self.fakeRedeemingPanel.ExpandPanel(animate=True, showNewItems=False) 188 189 def SwitchToProgressPanel(self): 190 self.SwitchToPanel(self.purchaseProgressPanel) 191 192 def SwitchToSuccessPanel(self, offerQuantity, toCharacterID): 193 self.CreateRedeemPanel(self.offer, offerQuantity) 194 self.backButton.Hide() 195 self.SwitchToPanel(self.purchaseSuccessPanel) 196 store = sm.GetService('vgsService').GetStore() 197 isGametimeOffer = store.IsGametimeOffer(self.offer) 198 isItemOffer = store.IsItemOffer(self.offer) 199 isPlexOffer = store.IsPlexOffer(self.offer) 200 isGemOffer = store.IsGemOffer(self.offer) 201 if toCharacterID: 202 if isGametimeOffer: 203 self.successDescriptionText.SetText('<center>%s</center>' % GetByLabel('UI/VirtualGoodsStore/Purchase/GiftingGametimeSuccess') + '<br/>') 204 if isItemOffer: 205 self.successDescriptionText.SetText(self.successDescriptionText.GetText() + '<center>%s</center>' % GetByLabel('UI/VirtualGoodsStore/Purchase/GiftingSuccessSubtext')) 206 tokens = self.redeemContainer.GetTokens() 207 for tokenInfo, token in tokens.iteritems(): 208 srcToken = self.redeemContainer.PopToken(token) 209 srcToken.AnimateOut(timeOffset=0.6) 210 211 else: 212 if isGametimeOffer: 213 self.successDescriptionText.SetText(self.successDescriptionText.GetText() + '<center>%s</center>' % GetByLabel('UI/VirtualGoodsStore/Purchase/GameTimePurchaseSuccess') + '<br/>') 214 if isPlexOffer: 215 self.successDescriptionText.SetText(self.successDescriptionText.GetText() + '<center>%s</center>' % GetByLabel('UI/FastCheckout/PLEXPurchaseSuccessSubText') + '<br/>') 216 if isGemOffer: 217 self.successDescriptionText.SetText(self.successDescriptionText.GetText() + '<center>%s</center>' % GetByLabel('UI/VirtualGoodsStore/Purchase/GemPurchaseSuccess') + '<br/>') 218 if isItemOffer: 219 self.successDescriptionText.SetText(self.successDescriptionText.GetText() + '<center>%s</center>' % GetByLabel('UI/VirtualGoodsStore/Purchase/NewPurchaseInstruction') + '<br/>') 220 self.OpenFakeRedeemPanel() 221 self.fakeRedeemingPanel.AddRedeemContainerContent(self.redeemContainer) 222 uicore.animations.MoveOutTop(self.redeemContainer, amount=self.redeemContainer.height, timeOffset=1.0, sleep=True, callback=self.redeemContainer.Close) 223 uicore.animations.FadeIn(self.successDescriptionText, duration=1.0, sleep=True) 224 self.fakeRedeemingPanel.HidePanel(animate=True) 225 self.continueButton.SetState(uiconst.UI_NORMAL) 226 animations.FadeIn(self.continueButton) 227 228 def SwitchToFailurePanel(self, reason = None): 229 text = reason or GetByLabel('UI/VirtualGoodsStore/Purchase/FailureReasonUnknown') 230 self._SetPurchaseFailureReasonText(text) 231 self.backButton.Hide() 232 self.SwitchToPanel(self.purchaseFailurePanel) 233 234 def _SetPurchaseFailureReasonText(self, text): 235 self.purchaseFailureReasonLabel.text = '<center>%s</center>' % text 236 237 def HasSuccessfullyBoughtItem(self): 238 return self.activeBottomPanel == self.purchaseSuccessPanel 239 240 def SwitchToPanel(self, newPanel): 241 newPanel.OnPanelActivated() 242 uicore.animations.MoveOutLeft(self.activeBottomPanel, self.contWidth, duration=PROGRESS_TRANSITION_TIME) 243 self.activeBottomPanel = newPanel 244 self.activeBottomPanel.state = uiconst.UI_PICKCHILDREN 245 uicore.animations.MoveInFromRight(self.activeBottomPanel, self.contWidth, duration=PROGRESS_TRANSITION_TIME, sleep=True) 246 247 def CloseOffer(self, *args): 248 uthread.new(sm.GetService('vgsService').GetUiController().CloseOffer) 249 250 def PrepareClose(self): 251 self.preview.PrepareClose() 252 253 def _OnResize(self, *args): 254 if not hasattr(self, 'backgroundTopContainer'): 255 return 256 self.backgroundTopContainer.height = self.parent.GetAbsoluteSize()[1] 257 258 259 class QRCodeContainer(Container): 260 default_name = 'QRCodeContainer' 261 default_bgColor = HEADER_BG_COLOR 262 263 def ApplyAttributes(self, attributes): 264 super(QRCodeContainer, self).ApplyAttributes(attributes) 265 currency = attributes.currency 266 price = attributes.price 267 paymentMethod = attributes.paymentMethod 268 self.offerName = attributes.offerName 269 self.onClose = attributes.onClose 270 Fill(bgParent=self, color=FRAME_COLOR, padding=-FRAME_WIDTH) 271 self.topCont = Container(name='topCont', parent=self, align=uiconst.TOTOP, height=40, bgColor=Color.GRAY2, opacity=0.7) 272 self.bottomCont = Container(name='bottomCont', parent=self, align=uiconst.TOBOTTOM, height=60, bgColor=Color.GRAY2, opacity=0.7) 273 self.mainCont = Container(name='mainCont', parent=self, align=uiconst.TOALL) 274 self.ConstructTopCont() 275 self.ConstructMainCont(paymentMethod, price, currency) 276 self.ConstructBottomCont() 277 self.AnimEntry() 278 279 def ConstructTopCont(self): 280 VgsLabelMedium(parent=self.topCont, text=u'\u652f\u4ed8', align=uiconst.CENTER) 281 ExitButton(parent=self.topCont, align=uiconst.TOPRIGHT, onClick=self.CloseByUser, left=3, top=3) 282 283 def ConstructMainCont(self, paymentMethod, price, currency): 284 PriceTagLarge(name='price_tag', parent=self.mainCont, align=uiconst.CENTERTOP, price=price, currency=currency, top=18) 285 self.loadingWheel = LoadingWheel(parent=self.mainCont, align=uiconst.CENTER, state=uiconst.UI_DISABLED) 286 ProviderElementClass = get_element_for_payment_provider(paymentMethod) 287 ProviderElementClass(parent=self.mainCont, align=uiconst.CENTERBOTTOM, top=10) 288 289 def ConstructBottomCont(self): 290 VgsLabelSmall(parent=self.bottomCont, align=uiconst.TOPLEFT, text=self.offerName, left=5, top=8) 291 self.accountNameLabel = VgsLabelSmall(parent=self.bottomCont, align=uiconst.BOTTOMLEFT, left=5, top=8, bold=True, fontsize=14) 292 293 def CloseByUser(self, sleep = False): 294 self.Disable() 295 duration = 0.2 296 animations.FadeOut(self, duration=duration, callback=self.Close) 297 self.onClose() 298 299 def AnimEntry(self): 300 duration = 0.4 301 animations.FadeIn(self, duration=duration) 302 animations.MorphScalar(self, 'top', self.top + 80, self.top, duration=duration) 303 304 def ShowQrCode(self, url, accountName): 305 self.loadingWheel.Hide() 306 LazyUrlSprite(parent=self.mainCont, align=uiconst.CENTER, pos=(0, 0, 200, 200), imageUrl=url, spriteBgFill=(1.0, 1.0, 1.0, 1.0)) 307 self.accountNameLabel.text = accountName 308 309 def OpenPaymentUrl(self, url): 310 self.loadingWheel.Hide() 311 EveLabelMedium(parent=self.mainCont, align=uiconst.CENTER, text=u'\u8bf7\u5728\u6253\u5f00\u7684\u6d4f\u89c8\u5668\u9875\u9762\u4e2d\u5b8c\u6210\u652f\u4ed8') 312 blue.os.ShellExecute(url)