Skip to content
Snippets Groups Projects

Prepare withdraw routes part of the HP managament

Merged Jakub Ziebinski requested to merge jziebinski/withdraw-routes-prepare into develop
Compare and
7 files
+ 545
8
Compare changes
  • Side-by-side
  • Inline
Files
7
@@ -2,23 +2,188 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from textual.widgets import TabPane
from textual import on
from textual.containers import Horizontal, ScrollableContainer
from textual.widgets import Input, Pretty, Static, TabPane
from clive.__private.ui.widgets.clive_widget import CliveWidget
from clive.__private.core.formatters.humanize import humanize_datetime
from clive.__private.core.hive_to_vests import hive_to_vests
from clive.__private.ui.data_providers.hive_power_data_provider import HivePowerDataProvider
from clive.__private.ui.get_css import get_css_from_relative_path
from clive.__private.ui.operations.bindings.operation_action_bindings import OperationActionBindings
from clive.__private.ui.operations.hive_power_management.common_hive_power.hp_vests_factor import HpVestsFactor
from clive.__private.ui.operations.operation_summary.cancel_power_down import CancelPowerDown
from clive.__private.ui.widgets.clive_button import CliveButton
from clive.__private.ui.widgets.clive_checkerboard_table import (
EVEN_STYLE,
ODD_STYLE,
CliveCheckerboardTable,
CliveCheckerBoardTableCell,
CliveCheckerboardTableRow,
)
from clive.__private.ui.widgets.currency_selector.currency_selector_hp_vests import CurrencySelectorHpVests
from clive.__private.ui.widgets.generous_button import GenerousButton
from clive.__private.ui.widgets.inputs.hp_vests_amount_input import HPVestsAmountInput
from clive.models import Asset
from schemas.operations import WithdrawVestingOperation
if TYPE_CHECKING:
from datetime import datetime
from rich.text import TextType
from textual.app import ComposeResult
from textual.widget import Widget
from clive.__private.core.commands.data_retrieval.hive_power_data import HivePowerData
class PlaceTaker(Static):
pass
class ScrollablePart(ScrollableContainer):
pass
class WithdrawRoutesDisplay(Pretty):
"""Widget used just to inform user to which account has withdrawal route and how much % it is."""
class PendingPowerDownHeader(Horizontal):
def compose(self) -> ComposeResult:
yield Static("Next power down", classes=EVEN_STYLE)
yield Static("Power down(HP)", classes=ODD_STYLE)
yield Static("Power down(VESTS)", classes=EVEN_STYLE)
yield PlaceTaker()
class PendingPowerDown(CliveCheckerboardTable):
def __init__(self) -> None:
super().__init__(
Static("Pending Power down", id="pending-power-down-title"), PendingPowerDownHeader(), dynamic=True
)
def create_dynamic_rows(self, content: HivePowerData) -> list[Widget]:
if humanize_datetime(content.next_vesting_withdrawal) == "never":
return [Static("No pending power down", id="no-pending-power-down-info")]
return [
CliveCheckerboardTableRow(
CliveCheckerBoardTableCell(humanize_datetime(content.next_vesting_withdrawal), evenness="odd"),
CliveCheckerBoardTableCell(Asset.pretty_amount(content.next_power_down.hp_balance), evenness="even"),
CliveCheckerBoardTableCell(Asset.pretty_amount(content.next_power_down.vests_balance), evenness="odd"),
CliveButton("Cancel", variant="error"),
)
]
@on(CliveButton.Pressed)
def push_operation_summary_screen(self) -> None:
self.app.push_screen(
CancelPowerDown(self.provider.content.next_vesting_withdrawal, self.provider.content.next_power_down)
)
@property
def provider(self) -> HivePowerDataProvider:
return self.app.query_one(HivePowerDataProvider)
@property
def creature_to_reconstruction_check(self) -> datetime:
return self.provider.content.next_vesting_withdrawal
class PowerDown(TabPane, CliveWidget):
class PowerDown(TabPane, OperationActionBindings):
"""TabPane with all content about power down."""
def __init__(self, title: TextType):
DEFAULT_CSS = get_css_from_relative_path(__file__)
def __init__(self, title: TextType) -> None:
"""
Initialize a TabPane.
Initialize the PowerDown tab-pane.
Args:
----
title: Title of the TabPane (will be displayed in a tab label).
"""
super().__init__(title=title)
self._shares_input = HPVestsAmountInput()
self._instalment_display = Static("", id="instalment-display")
self._instalment_display.display = False
def compose(self) -> ComposeResult:
with ScrollablePart():
yield Static("Power down corresponds to a `withdraw vesting` operation", id="operation-name-info")
yield HpVestsFactor(self.provider)
with Horizontal(id="input-with-button"):
yield self._shares_input
yield GenerousButton(self._shares_input, self._get_shares_balance) # type: ignore[arg-type]
yield self._instalment_display
yield Static("Your withdraw routes", id="withdraw-routes-title")
yield WithdrawRoutesDisplay({})
yield PendingPowerDown()
def on_mount(self) -> None:
self.watch(self.provider, "_content", self._update_withdraw_routes, init=False)
def _get_shares_balance(self) -> Asset.Hive | Asset.Vests:
if self._shares_input.selected_asset_type is Asset.Hive:
return self.provider.content.owned_balance.hp_balance
return self.provider.content.owned_balance.vests_balance
@on(Input.Changed)
def calculate_one_withdrawal(self) -> None:
"""The withdrawal is divided into 13 parts - calculate and inform the user of the amount of one of them."""
shares_input = self._shares_input.value_or_none()
if shares_input is None:
self._instalment_display.display = False
self._instalment_display.update("")
return
one_withdrawal = shares_input / 13
self._instalment_display.update(
f"The withdrawal will be divided into 13 parts, one of which is: {Asset.pretty_amount(one_withdrawal)}"
)
self._instalment_display.display = True
@on(CurrencySelectorHpVests.Changed)
def shares_type_changed(self) -> None:
"""Clear input when shares type was changed and hide factor display when vests selected."""
self._shares_input.input.value = ""
hp_vests_factor = self.query_one(HpVestsFactor)
if self._shares_input.selected_asset_type is Asset.Vests:
hp_vests_factor.display = False
return
hp_vests_factor.display = True
def _create_operation(self) -> WithdrawVestingOperation | None:
asset = self._shares_input.value_or_none()
if asset is None:
return None
if isinstance(asset, Asset.Vests):
return WithdrawVestingOperation(account=self.working_account, vesting_shares=asset)
hp_to_vests = hive_to_vests(asset, self.provider.content.gdpo)
# If the user has passed an amount in `HP` - convert it to `VESTS`. The operation is performed using VESTS.
return WithdrawVestingOperation(account=self.working_account, vesting_shares=hp_to_vests)
def _update_withdraw_routes(self, content: HivePowerData) -> None:
"""Update withdraw routes pretty widget."""
if not content.withdraw_routes:
self.query_one(WithdrawRoutesDisplay).update("You have no withdraw routes")
return
withdraw_routes = {}
for withdraw_route in content.withdraw_routes:
withdraw_routes[withdraw_route.to_account] = f"{withdraw_route.percent / 100}%"
self.query_one(WithdrawRoutesDisplay).update(withdraw_routes)
@property
def provider(self) -> HivePowerDataProvider:
return self.app.query_one(HivePowerDataProvider)
@property
def working_account(self) -> str:
return self.app.world.profile_data.working_account.name
Loading