NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

buyComponentDialogue.py (13371B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\cosmetics\ship\pages\store\buyComponentDialogue.py
      2 import carbonui
      3 import carbonui.text.styles
      4 import eveformat
      5 import eveicon
      6 import uthread2
      7 from carbonui import Align, AxisAlignment, ButtonStyle, ButtonVariant, Density, TextColor, uiconst, TextAlign, PickState
      8 from carbonui.text.styles import TextHeader
      9 from carbonui.button.group import ButtonGroup, ButtonSizeMode
     10 from carbonui.control.button import Button
     11 from carbonui.control.checkbox import Checkbox
     12 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger
     13 from carbonui.control.window import Window
     14 from carbonui.decorative.divider_line import DividerLine
     15 from carbonui.primitives.container import Container
     16 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     17 from carbonui.primitives.sprite import Sprite
     18 from cosmetics.client.shipSkinComponentTradingSvc import get_ship_skin_component_trading_svc
     19 from cosmetics.client.ships.skins.errors import get_listing_error_text
     20 from cosmetics.common.ships.skins.util import Currency
     21 from eve.client.script.ui import eveColor
     22 from eve.client.script.ui.control.infoNotice import InfoNotice
     23 from player_messaging.client.ui_message import message_player
     24 from eve.client.script.ui.cosmetics.ship.controls.buyerFee import BuySKINBuyerFee
     25 from eve.client.script.ui.cosmetics.ship.pages.cards.componentListingCard import ComponentListingCard
     26 from eve.client.script.ui.cosmetics.ship.pages.store import storeSignals
     27 from eve.client.script.ui.shared.neocom.wallet.buyMissingPlexDialog import BuyMissingPlexDialog
     28 from localization import GetByLabel
     29 from plex.client.api.repository import get_repository
     30 from publicGateway.grpc.exceptions import GenericException
     31 from stackless_response_router.exceptions import TimeoutException
     32 
     33 class BuyComponentDialogue(Window):
     34     default_windowID = 'BuyComponentDialogue'
     35     default_iconNum = 'res:/UI/Texture/WindowIcons/paint_tool.png'
     36     default_caption = GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/BuyElement')
     37     default_fixedWidth = 515
     38     default_isMinimizable = False
     39     default_isStackable = False
     40     default_isCollapseable = False
     41 
     42     def __init__(self, listing, *args, **kwargs):
     43         super(BuyComponentDialogue, self).__init__(*args, **kwargs)
     44         self.listing = listing
     45         self.buy_thread = None
     46         self.construct_layout()
     47 
     48     def Close(self, setClosed = False, *args, **kwargs):
     49         try:
     50             self.kill_threads()
     51         finally:
     52             super(BuyComponentDialogue, self).Close(setClosed, *args, **kwargs)
     53 
     54     def kill_threads(self):
     55         if self.buy_thread is not None:
     56             self.buy_thread.kill()
     57             self.buy_thread = None
     58 
     59     def construct_content_cont(self):
     60         return ContainerAutoSize(parent=self.sr.maincontainer, name='main', align=uiconst.TOTOP, padding=self.content_padding)
     61 
     62     def construct_layout(self):
     63         self.content.on_size_changed.connect(self.on_content_size_changed)
     64         self.construct_card()
     65         name = self.listing.name_with_quantity if hasattr(self.listing, 'name_with_quantity') else ''
     66         carbonui.text.styles.TextHeader(parent=self.content, align=Align.TOTOP, text=name, textAlign=TextAlign.CENTER, padTop=-16)
     67         DividerLine(parent=self.content, align=Align.TOTOP, padTop=32)
     68         self.construct_buyer_fee()
     69         self.construct_price()
     70         self.construct_quantity()
     71         DividerLine(parent=self.content, align=Align.TOTOP, padTop=16)
     72         self.construct_activate_now_checkbox()
     73         self.construct_item_delivery_notice()
     74         self.construct_buttons()
     75         self.update()
     76 
     77     def construct_activate_now_checkbox(self):
     78         self.activate_now_checkbox = Checkbox(name='activate_now_checkbox', parent=self.content, align=Align.TOTOP, text=GetByLabel('UI/Personalization/ShipSkins/SKINR/Store/ActivateNow'), hint=GetByLabel('UI/Personalization/ShipSkins/SKINR/Store/ActivateNowHint'), padTop=16, checked=True, callback=self.on_activate_now_checkbox)
     79 
     80     def on_activate_now_checkbox(self, *args):
     81         self.update_item_delivery_notice()
     82 
     83     def on_content_size_changed(self, width, height):
     84         _, height = self.GetWindowSizeForContentSize(height=height)
     85         self.SetFixedHeight(height)
     86 
     87     def construct_card(self):
     88         card_container = ContainerAutoSize(name='card_container', parent=self.content, align=Align.TOTOP, padTop=16)
     89         card = BuyComponentListingCard(name='card', parent=card_container, align=Align.CENTERTOP, listing=self.listing)
     90         card._on_selected = lambda *args, **kwargs: None
     91         card.is_selected = True
     92 
     93     def construct_item_delivery_notice(self):
     94         self.item_delivery_notice = InfoNotice(name='item_delivery_notice', parent=self.content, align=uiconst.TOTOP, labelText=GetByLabel('UI/Personalization/ShipSkins/SKINR/ItemDeliveryNotice'), padTop=16)
     95         self.item_delivery_notice.noticeLabel.maxLines = None
     96 
     97     def construct_price(self):
     98         price_container = Container(name='price_container', parent=self.content, align=Align.TOTOP, height=32, padTop=16)
     99         TextHeader(name='price_label', parent=price_container, align=Align.TOLEFT, text=GetByLabel('UI/Market/Marketbase/Price'), bold=True, padTop=4)
    100         self.amount_label = TextHeader(name='amount_label', parent=price_container, align=Align.TORIGHT, state=uiconst.UI_NORMAL, bold=True, padTop=4)
    101         icon_container = Container(name='icon_container', parent=price_container, align=Align.TORIGHT, width=16, padRight=4)
    102         self.currency_icon = Sprite(name='currency_icon', parent=icon_container, align=Align.CENTER, pos=(0, 0, 16, 16))
    103 
    104     def construct_buyer_fee(self):
    105         self.buyer_fee = BuySKINBuyerFee(name='buyer_fee', parent=self.content, align=Align.TOTOP, padTop=16, display=False)
    106 
    107     def construct_quantity(self):
    108         quantity_container = Container(name='quantity_container', parent=self.content, align=Align.TOTOP, height=32, padTop=8)
    109         TextHeader(name='quantity_label', parent=quantity_container, align=Align.TOLEFT, text=GetByLabel('UI/Common/Quantity'), bold=True, padTop=4)
    110         quantity_edit_max_value = self.listing.quantity
    111         if quantity_edit_max_value < 0:
    112             quantity_edit_max_value = SingleLineEditInteger.default_maxValue
    113         self.quantity_edit = SingleLineEditInteger(name='quantity_edit', parent=quantity_container, align=Align.TORIGHT, density=Density.EXPANDED, minValue=1, maxValue=quantity_edit_max_value, setvalue=1, OnChange=self.on_input_change, width=125)
    114 
    115     def on_input_change(self, *args):
    116         self.update()
    117 
    118     def construct_buttons(self):
    119         button_group = ButtonGroup(name='button_group', parent=self.content, align=Align.TOTOP, button_alignment=AxisAlignment.CENTER, density=Density.EXPANDED, button_size_mode=ButtonSizeMode.STRETCH, padTop=16)
    120         self.buy_button = Button(name='buy_button', label=GetByLabel('UI/Personalization/ShipSkins/SKINR/Store/Buy'), variant=ButtonVariant.PRIMARY, func=self.on_buy_button)
    121         button_group.add_button(self.buy_button)
    122         self.cancel_button = Button(name='cancel_button', label=GetByLabel('UI/Common/Buttons/Cancel'), variant=ButtonVariant.GHOST, func=self.on_cancel_button)
    123         button_group.add_button(self.cancel_button)
    124 
    125     def update(self):
    126         self.update_buyer_fee()
    127         self.update_amount_label()
    128         self.update_currency_icon()
    129         self.update_buttons()
    130         self.update_item_delivery_notice()
    131 
    132     def update_amount_label(self):
    133         self.amount_label.text = eveformat.number(self.total_price)
    134         if self.listing.currency == Currency.PLEX and self.has_enough_plex:
    135             self.amount_label.color = TextColor.NORMAL
    136             self.amount_label.hint = None
    137         elif self.listing.currency == Currency.ISK and self.has_enough_isk:
    138             self.amount_label.color = TextColor.NORMAL
    139             self.amount_label.hint = None
    140         else:
    141             self.amount_label.color = TextColor.DANGER
    142             self.amount_label.hint = GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/ListingErrors/InsufficientFunds')
    143 
    144     def update_currency_icon(self):
    145         self.currency_icon.hint = self.get_currency_hint()
    146         self.currency_icon.texturePath = self.get_currency_icon()
    147         self.currency_icon.color = self.get_currency_color()
    148 
    149     def update_buttons(self):
    150         self.buy_button.LoadTooltipPanel = self.load_buy_button_tooltip_panel
    151         self.buy_button.style = self.get_buy_button_style()
    152 
    153     def update_item_delivery_notice(self):
    154         if hasattr(self, 'item_delivery_notice'):
    155             self.item_delivery_notice.display = not self.activate_now_checkbox.checked
    156 
    157     def update_buyer_fee(self):
    158         pass
    159 
    160     def has_sufficient_funds(self):
    161         if self.listing.currency == Currency.ISK:
    162             return self.has_enough_isk
    163         elif self.listing.currency == Currency.PLEX:
    164             return self.has_enough_plex
    165         else:
    166             return False
    167 
    168     @property
    169     def has_enough_isk(self):
    170         return sm.GetService('wallet').GetWealth() >= self.get_required_amount()
    171 
    172     @property
    173     def has_enough_plex(self):
    174         return get_repository().get_balance() >= self.get_required_amount()
    175 
    176     def get_required_amount(self):
    177         return self.listing.price * self.purchase_quantity
    178 
    179     def load_buy_button_tooltip_panel(self, tooltip_panel, *args):
    180         if self.has_sufficient_funds():
    181             return
    182         tooltip_panel.columns = 1
    183         tooltip_panel.LoadStandardSpacing()
    184         tooltip_panel.AddLabelMedium(text=self.insufficient_funds_hint, wrapWidth=300, color=eveColor.DANGER_RED)
    185         if self.listing.currency == Currency.PLEX and not self.has_enough_plex:
    186             tooltip_panel.pickState = PickState.ON
    187             button_group = ButtonGroup(parent=tooltip_panel, align=Align.TOTOP, button_size_mode=ButtonSizeMode.DYNAMIC, padTop=8)
    188             Button(parent=button_group, label=GetByLabel('UI/Wallet/BuyMore'), func=self.on_buy_more_plex_button, texturePath=eveicon.plex, style=ButtonStyle.MONETIZATION)
    189 
    190     @property
    191     def insufficient_funds_hint(self):
    192         currencies = []
    193         if self.listing.currency == Currency.ISK and not self.has_enough_isk:
    194             currencies.append(GetByLabel('UI/Common/ISK'))
    195         if self.listing.currency == Currency.PLEX and not self.has_enough_plex:
    196             currencies.append(GetByLabel('UI/Common/PLEX'))
    197         return u'{base} ({currencies})'.format(base=GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/ListingErrors/InsufficientFunds'), currencies=u'/'.join(currencies))
    198 
    199     def on_buy_more_plex_button(self, *args):
    200         buy_missing_plex_dialog = BuyMissingPlexDialog(required_amount=self.get_required_amount())
    201         buy_missing_plex_dialog.ShowModal()
    202         self.SetModalResult(uiconst.ID_CANCEL)
    203 
    204     def get_buy_button_style(self):
    205         if self.is_allowed_to_purchase:
    206             return ButtonStyle.NORMAL
    207         return ButtonStyle.DANGER
    208 
    209     @property
    210     def is_allowed_to_purchase(self):
    211         return self.has_sufficient_funds()
    212 
    213     @property
    214     def purchase_quantity(self):
    215         return self.quantity_edit.GetValue()
    216 
    217     def get_currency_hint(self):
    218         if self.listing.currency == Currency.ISK:
    219             return GetByLabel('UI/Common/ISK')
    220         elif self.listing.currency == Currency.PLEX:
    221             return GetByLabel('UI/Common/PLEX')
    222         else:
    223             return None
    224 
    225     def get_currency_icon(self):
    226         if self.listing.currency == Currency.ISK:
    227             return eveicon.isk
    228         elif self.listing.currency == Currency.PLEX:
    229             return eveicon.plex
    230         else:
    231             return None
    232 
    233     def get_currency_color(self):
    234         if self.listing.currency == Currency.PLEX:
    235             return eveColor.PLEX_YELLOW
    236         return eveColor.WHITE
    237 
    238     def on_buy_button(self, *args):
    239         if self.is_allowed_to_purchase:
    240             self.buy_thread = uthread2.StartTasklet(self._buy_async)
    241 
    242     def _buy_async(self):
    243         self.buy_button.busy = True
    244         self.buy_button.disabled = True
    245         try:
    246             error = self.purchase_listing()
    247             if error:
    248                 message_player(GetByLabel(get_listing_error_text(error)))
    249             else:
    250                 self.on_buy_success()
    251         except (GenericException, TimeoutException):
    252             message_player(GetByLabel('UI/Common/CannotConnectToServer'))
    253         finally:
    254             self.buy_thread = None
    255             self.buy_button.busy = False
    256             self.buy_button.disabled = False
    257 
    258     def on_buy_success(self):
    259         storeSignals.on_component_listing_selected(None)
    260         self.SetModalResult(uiconst.ID_OK)
    261 
    262     def purchase_listing(self):
    263         return get_ship_skin_component_trading_svc().purchase_listing(listing=self.listing, quantity=self.quantity, immediately_activate=self.activate_now_checkbox.checked)
    264 
    265     def on_cancel_button(self, *args):
    266         self.SetModalResult(uiconst.ID_CANCEL)
    267 
    268     @property
    269     def quantity(self):
    270         return self.quantity_edit.GetValue()
    271 
    272     @property
    273     def total_price(self):
    274         return self.listing.price * self.quantity
    275 
    276 
    277 class BuyComponentListingCard(ComponentListingCard):
    278 
    279     def get_component_name(self):
    280         return ''