diff --git a/src/sakia/gui/main_window/toolbar/about_money.ui b/src/sakia/gui/main_window/toolbar/about_money.ui index 21432be2ced327e84f19684a3b58e11f0be6606e..d4e6cc90d7c056b5da8e6027d065960baeade415 100644 --- a/src/sakia/gui/main_window/toolbar/about_money.ui +++ b/src/sakia/gui/main_window/toolbar/about_money.ui @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> - <class>Form</class> - <widget class="QWidget" name="Form"> + <class>AboutMoney</class> + <widget class="QWidget" name="AboutMoney"> <property name="geometry"> <rect> <x>0</x> @@ -61,22 +61,6 @@ </layout> </widget> </item> - <item> - <widget class="QGroupBox" name="group_referentials"> - <property name="title"> - <string>Referentials</string> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <widget class="QLabel" name="label_referentials"> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </widget> - </item> <item> <widget class="QGroupBox" name="group_money"> <property name="title"> @@ -96,25 +80,6 @@ </layout> </widget> </item> - <item> - <widget class="QGroupBox" name="group_wot"> - <property name="title"> - <string>WoT</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <item> - <widget class="QLabel" name="label_wot"> - <property name="text"> - <string/> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> - </property> - </widget> - </item> - </layout> - </widget> - </item> </layout> </widget> <resources/> diff --git a/src/sakia/gui/main_window/toolbar/about_wot.ui b/src/sakia/gui/main_window/toolbar/about_wot.ui new file mode 100644 index 0000000000000000000000000000000000000000..24e061aee9f17e0dd7b0ba039e3382b103cc58ae --- /dev/null +++ b/src/sakia/gui/main_window/toolbar/about_wot.ui @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AboutWot</class> + <widget class="QWidget" name="AboutWot"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>509</width> + <height>406</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="group_wot"> + <property name="title"> + <string>WoT</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QLabel" name="label_wot"> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/sakia/gui/main_window/toolbar/controller.py b/src/sakia/gui/main_window/toolbar/controller.py index 45aee53c2c7f915f905f84d4ca2e4a172d098278..0a4c12ae6a6ee878a36ac02dbdb2668dd345d054 100644 --- a/src/sakia/gui/main_window/toolbar/controller.py +++ b/src/sakia/gui/main_window/toolbar/controller.py @@ -7,6 +7,7 @@ from sakia.gui.dialogs.plugins_manager.controller import PluginsManagerControlle from sakia.gui.preferences import PreferencesDialog from .model import ToolbarModel from .view import ToolbarView +from sakia.data.processors import BlockchainProcessor import sys @@ -28,6 +29,9 @@ class ToolbarController(QObject): self.view.action_parameters.triggered.connect(self.open_settings_dialog) self.view.action_plugins.triggered.connect(self.open_plugins_manager_dialog) self.view.action_about.triggered.connect(self.open_about_dialog) + self.view.action_about_wot.triggered.connect(self.open_about_wot_dialog) + self.view.action_about_money.triggered.connect(self.open_about_money_dialog) + self.view.action_about_referentials.triggered.connect(self.open_about_referentials_dialog) self.view.action_revoke_uid.triggered.connect(self.open_revocation_dialog) self.view.button_contacts.clicked.connect(self.open_contacts_dialog) @@ -41,7 +45,7 @@ class ToolbarController(QObject): :rtype: NavigationController """ view = ToolbarView(None) - model = ToolbarModel(app, navigation.model) + model = ToolbarModel(app, navigation.model, app.blockchain_service, BlockchainProcessor.instanciate(app)) toolbar = cls(view, model) return toolbar @@ -69,6 +73,21 @@ class ToolbarController(QObject): text = self.model.about_text() self.view.show_about(text) + def open_about_wot_dialog(self): + params = self.model.parameters() + self.view.show_about_wot(params) + + def open_about_money_dialog(self): + params = self.model.parameters() + currency = self.model.app.currency + localized_data = self.model.get_localized_data() + referentials = self.model.referentials() + self.view.show_about_money(params, currency, localized_data) + + def open_about_referentials_dialog(self): + referentials = self.model.referentials() + self.view.show_about_referentials(referentials) + def retranslateUi(self, widget): """ Method to complete translations missing from generated code diff --git a/src/sakia/gui/main_window/toolbar/model.py b/src/sakia/gui/main_window/toolbar/model.py index 5e312cdb4227b8142e8fd639ffa0f28fd8e7852f..ffa438ef972444024dd172ee147f648747ce63b7 100644 --- a/src/sakia/gui/main_window/toolbar/model.py +++ b/src/sakia/gui/main_window/toolbar/model.py @@ -1,7 +1,11 @@ -from PyQt5.QtCore import QObject +from PyQt5.QtCore import QObject, QLocale, QDateTime from sakia.data.processors import ConnectionsProcessor import attr +import math from sakia import __version__ +from sakia.constants import ROOT_SERVERS +from duniterpy.api import errors +from sakia.money import Referentials @attr.s() @@ -15,13 +19,12 @@ class ToolbarModel(QObject): app = attr.ib() navigation_model = attr.ib() + blockchain_service = attr.ib() + blockchain_processor = attr.ib() def __attrs_post_init__(self): super().__init__() - async def send_join(self, connection, secret_key, password): - return await self.app.documents_service.send_membership(connection, secret_key, password, "IN") - def notifications(self): return self.app.parameters.notifications @@ -62,4 +65,110 @@ class ToolbarModel(QObject): <p>canercandan</p> <p>Moul</p> """.format(__version__, - new_version_text=new_version_text) \ No newline at end of file + new_version_text=new_version_text) + + def get_localized_data(self): + localized_data = {} + # try to request money parameters + params = self.blockchain_service.parameters() + + localized_data['currency'] = ROOT_SERVERS[self.app.currency]["display"] + localized_data['growth'] = params.c + localized_data['days_per_dividend'] = QLocale().toString(params.dt / 86400, 'f', 2) + + last_ud, last_ud_base = self.blockchain_service.last_ud() + members_count = self.blockchain_service.last_members_count() + previous_ud, previous_ud_base = self.blockchain_service.previous_ud() + previous_ud_time = self.blockchain_service.previous_ud_time() + previous_monetary_mass = self.blockchain_service.previous_monetary_mass() + previous_members_count = self.blockchain_service.previous_members_count() + + localized_data['units'] = self.app.current_ref.instance(0, + self.app.currency, + self.app, None).units + localized_data['diff_units'] = self.app.current_ref.instance(0, + self.app.currency, + self.app, None).diff_units + + if last_ud: + # display float values + localized_data['ud'] = self.app.current_ref.instance(last_ud * math.pow(10, last_ud_base), + self.app.currency, + self.app).diff_localized(False, True) + + localized_data['members_count'] = self.blockchain_service.current_members_count() + + computed_dividend = self.blockchain_service.computed_dividend() + # display float values + localized_data['ud_plus_1'] = self.app.current_ref.instance(computed_dividend, + self.app.currency, self.app).diff_localized(False, True) + + localized_data['mass'] = self.app.current_ref.instance(self.blockchain_service.current_mass(), + self.app.currency, self.app).localized(False, True) + + ud_median_time = self.blockchain_service.last_ud_time() + ud_median_time = self.blockchain_processor.adjusted_ts(self.app.currency, ud_median_time) + + localized_data['ud_median_time'] = QLocale.toString( + QLocale(), + QDateTime.fromTime_t(ud_median_time), + QLocale.dateTimeFormat(QLocale(), QLocale.ShortFormat) + ) + + next_ud_median_time = self.blockchain_service.last_ud_time() + params.dt + next_ud_median_time = self.blockchain_processor.adjusted_ts(self.app.currency, next_ud_median_time) + + localized_data['next_ud_median_time'] = QLocale.toString( + QLocale(), + QDateTime.fromTime_t(next_ud_median_time), + QLocale.dateTimeFormat(QLocale(), QLocale.ShortFormat) + ) + + next_ud_reeval = self.blockchain_service.next_ud_reeval() + next_ud_reeval = self.blockchain_processor.adjusted_ts(self.app.currency, next_ud_reeval) + localized_data['next_ud_reeval'] = QLocale.toString( + QLocale(), + QDateTime.fromTime_t(next_ud_reeval), + QLocale.dateTimeFormat(QLocale(), QLocale.ShortFormat) + ) + + if previous_ud: + mass_minus_1_per_member = (float(0) if previous_ud == 0 or previous_members_count == 0 else + previous_monetary_mass / previous_members_count) + localized_data['mass_minus_1_per_member'] = self.app.current_ref.instance(mass_minus_1_per_member, + self.app.currency, self.app) \ + .localized(False, True) + localized_data['mass_minus_1'] = self.app.current_ref.instance(previous_monetary_mass, + self.app.currency, self.app) \ + .localized(False, True) + # avoid divide by zero ! + if members_count == 0 or previous_members_count == 0: + localized_data['actual_growth'] = float(0) + else: + localized_data['actual_growth'] = (last_ud * math.pow(10, last_ud_base)) / ( + previous_monetary_mass / members_count) + + previous_ud_time = self.blockchain_processor.adjusted_ts(self.app.currency, previous_ud_time) + localized_data['ud_median_time_minus_1'] = QLocale.toString( + QLocale(), + QDateTime.fromTime_t(previous_ud_time), + QLocale.dateTimeFormat(QLocale(), QLocale.ShortFormat) + ) + return localized_data + + def parameters(self): + """ + Get community parameters + """ + return self.blockchain_service.parameters() + + def referentials(self): + """ + Get referentials + :return: The list of instances of all referentials + :rtype: list + """ + refs_instances = [] + for ref_class in Referentials: + refs_instances.append(ref_class(0, self.app.currency, self.app, None)) + return refs_instances \ No newline at end of file diff --git a/src/sakia/gui/main_window/toolbar/view.py b/src/sakia/gui/main_window/toolbar/view.py index aa16a91084cd1d2b146f3ef6e139569ed4fa6351..ae7c8cd780115f74952a4ff81b3663d3c0d03f89 100644 --- a/src/sakia/gui/main_window/toolbar/view.py +++ b/src/sakia/gui/main_window/toolbar/view.py @@ -1,8 +1,12 @@ -from PyQt5.QtWidgets import QFrame, QAction, QMenu, QSizePolicy, QInputDialog, QDialog +from PyQt5.QtWidgets import QFrame, QAction, QMenu, QSizePolicy, QInputDialog, QDialog, \ + QVBoxLayout, QTabWidget, QWidget, QLabel from sakia.gui.widgets.dialogs import dialog_async_exec -from PyQt5.QtCore import QObject, QT_TRANSLATE_NOOP, Qt +from PyQt5.QtCore import QObject, QT_TRANSLATE_NOOP, Qt, QLocale from .toolbar_uic import Ui_SakiaToolbar from .about_uic import Ui_AboutPopup +from .about_money_uic import Ui_AboutMoney +from .about_wot_uic import Ui_AboutWot +from sakia.helpers import timestamp_to_dhms class ToolbarView(QFrame, Ui_SakiaToolbar): @@ -30,11 +34,14 @@ class ToolbarView(QFrame, Ui_SakiaToolbar): self.action_plugins = QAction(self.tr("Plugins manager"), tool_menu) tool_menu.addAction(self.action_plugins) - self.action_about = QAction(self.tr("About Money"), tool_menu) - tool_menu.addAction(self.action_about) + self.action_about_money = QAction(self.tr("About Money"), tool_menu) + tool_menu.addAction(self.action_about_money) - self.action_about = QAction(self.tr("About Web of Trust"), tool_menu) - tool_menu.addAction(self.action_about) + self.action_about_referentials = QAction(self.tr("About Referentials"), tool_menu) + tool_menu.addAction(self.action_about_referentials) + + self.action_about_wot = QAction(self.tr("About Web of Trust"), tool_menu) + tool_menu.addAction(self.action_about_wot) self.action_about = QAction(self.tr("About Sakia"), tool_menu) tool_menu.addAction(self.action_about) @@ -56,6 +63,216 @@ class ToolbarView(QFrame, Ui_SakiaToolbar): if c.title() == result: return c + def show_about_wot(self, params): + """ + Set wot text from currency parameters + :param sakia.data.entities.BlockchainParameters params: Parameters of the currency + :return: + """ + dialog = QDialog(self) + about_dialog = Ui_AboutWot() + about_dialog.setupUi(dialog) + + # set infos in label + about_dialog.label_wot.setText( + self.tr(""" + <table cellpadding="5"> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +</table> +""").format( + QLocale().toString(params.sig_period / 86400, 'f', 2), + self.tr('Minimum delay between 2 certifications (in days)'), + QLocale().toString(params.sig_validity / 86400, 'f', 2), + self.tr('Maximum age of a valid signature (in days)'), + params.sig_qty, + self.tr('Minimum quantity of signatures to be part of the WoT'), + params.sig_stock, + self.tr('Maximum quantity of active certifications made by member.'), + params.sig_window, + self.tr('Maximum delay a certification can wait before being expired for non-writing.'), + params.xpercent, + self.tr('Minimum percent of sentries to reach to match the distance rule'), + params.ms_validity / 86400, + self.tr('Maximum age of a valid membership (in days)'), + params.step_max, + self.tr('Maximum distance between each WoT member and a newcomer'), + ) + ) + dialog.setWindowTitle(self.tr("Web of Trust rules")) + dialog.exec() + + def show_about_money(self, params, currency, localized_data): + dialog = QDialog(self) + about_dialog = Ui_AboutMoney() + about_dialog.setupUi(dialog) + about_dialog.label_general.setText(self.general_text(localized_data)) + about_dialog.label_rules.setText(self.rules_text(localized_data)) + about_dialog.label_money.setText(self.money_text(params, currency)) + dialog.setWindowTitle(self.tr("Money rules")) + dialog.exec() + + def show_about_referentials(self, referentials): + dialog = QDialog(self) + layout = QVBoxLayout(dialog) + tabwidget = QTabWidget(dialog) + layout.addWidget(tabwidget) + for ref in referentials: + widget = QWidget() + layout = QVBoxLayout(widget) + label = QLabel() + label.setText(self.text_referential(ref)) + layout.addWidget(label) + tabwidget.addTab(widget, ref.translated_name()) + dialog.setWindowTitle(self.tr("Referentials")) + dialog.exec() + + def general_text(self, localized_data): + """ + Fill the general text with given informations + :return: + """ + # set infos in label + return self.tr(""" + <table cellpadding="5"> + <tr><td align="right"><b>{:}</b></div></td><td>{:} {:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:} {:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:} {:}</td></tr> + <tr><td align="right"><b>{:2.2%} / {:} days</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + </table> + """).format( + localized_data.get('ud', '####'), + self.tr('Universal Dividend UD(t) in'), + localized_data['diff_units'], + localized_data.get('mass_minus_1', "###"), + self.tr('Monetary Mass M(t-1) in'), + localized_data['units'], + localized_data.get('members_count', '####'), + self.tr('Members N(t)'), + localized_data.get('mass_minus_1_per_member', '####'), + self.tr('Monetary Mass per member M(t-1)/N(t) in'), + localized_data['diff_units'], + localized_data.get('actual_growth', 0), + localized_data.get('days_per_dividend', '####'), + self.tr('Actual growth c = UD(t)/[M(t-1)/N(t)]'), + localized_data.get('ud_median_time_minus_1', '####'), + self.tr('Penultimate UD date and time (t-1)'), + localized_data.get('ud_median_time', '####'), + self.tr('Last UD date and time (t)'), + localized_data.get('next_ud_median_time', '####'), + self.tr('Next UD date and time (t+1)'), + localized_data.get('next_ud_reeaval', '####'), + self.tr('Next UD reevaluation (t+1)') + ) + + def rules_text(self, localized_data): + """ + Set text in rules + :param dict localized_data: + :return: + """ + # set infos in label + return self.tr(""" + <table cellpadding="5"> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + </table> + """).format( + self.tr('{:2.0%} / {:} days').format(localized_data['growth'], localized_data['days_per_dividend']), + self.tr('Fundamental growth (c) / Delta time (dt)'), + self.tr('UDĞ(t) = UDĞ(t-1) + c²*M(t-1)/N(t-1)'), + self.tr('Universal Dividend (formula)'), + self.tr('{:} = {:} + {:2.0%}²* {:} / {:}').format( + localized_data.get('ud_plus_1', '####'), + localized_data.get('ud', '####'), + localized_data.get('growth', '####'), + localized_data.get('mass', '####'), + localized_data.get('members_count', '####') + ), + self.tr('Universal Dividend (computed)') + ) + + def text_referential(self, ref): + """ + Set text from referentials + """ + # set infos in label + ref_template = """ + <table cellpadding="5"> + <tr><th>{:}</th><td>{:}</td></tr> + <tr><th>{:}</th><td>{:}</td></tr> + <tr><th>{:}</th><td>{:}</td></tr> + <tr><th>{:}</th><td>{:}</td></tr> + </table> + """ + return ref_template.format(self.tr('Name'), ref.translated_name(), + self.tr('Units'), ref.units, + self.tr('Formula'), ref.formula, + self.tr('Description'), ref.description + ) + + def money_text(self, params, currency): + """ + Set text from money parameters + :param sakia.data.entities.BlockchainParameters params: Parameters of the currency + :param str currency: The currency + """ + + dt_dhms = timestamp_to_dhms(params.dt) + if dt_dhms[0] > 0: + dt_as_str = self.tr("{:} day(s) {:} hour(s)").format(*dt_dhms) + else: + dt_as_str = self.tr("{:} hour(s)").format(dt_dhms[1]) + if dt_dhms[2] > 0 or dt_dhms[3] > 0: + dt_dhms += ", {:} minute(s) and {:} second(s)".format(*dt_dhms[1:]) + dt_reeval_dhms = timestamp_to_dhms(params.dt_reeval) + dt_reeval_as_str = self.tr("{:} day(s) {:} hour(s)").format(*dt_reeval_dhms) + + # set infos in label + return self.tr(""" + <table cellpadding="5"> + <tr><td align="right"><b>{:2.0%} / {:} days</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:} {:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:2.0%}</b></td><td>{:}</td></tr> + </table> + """).format( + params.c, + QLocale().toString(params.dt / 86400, 'f', 2), + self.tr('Fundamental growth (c)'), + params.ud0, + self.tr('Initial Universal Dividend UD(0) in'), + currency, + dt_as_str, + self.tr('Time period between two UD'), + dt_reeval_as_str, + self.tr('Time period between two UD reevaluation'), + params.median_time_blocks, + self.tr('Number of blocks used for calculating median time'), + params.avg_gen_time, + self.tr('The average time in seconds for writing 1 block (wished time)'), + params.dt_diff_eval, + self.tr('The number of blocks required to evaluate again PoWMin value'), + params.percent_rot, + self.tr('The percent of previous issuers to reach for personalized difficulty') + ) + def show_about(self, text): dialog = QDialog(self) about_dialog = Ui_AboutPopup()