tqt.py - electrum - Electrum Bitcoin wallet
HTML git clone https://git.parazyd.org/electrum
DIR Log
DIR Files
DIR Refs
DIR Submodules
---
tqt.py (4293B)
---
1 from functools import partial
2 import zlib
3 import json
4 from io import BytesIO
5 import sys
6 import platform
7 from typing import TYPE_CHECKING
8
9 from PyQt5.QtWidgets import (QComboBox, QGridLayout, QLabel, QPushButton)
10
11 from electrum.plugin import BasePlugin, hook
12 from electrum.gui.qt.util import WaitingDialog, EnterButton, WindowModalDialog, read_QIcon
13 from electrum.i18n import _
14 from electrum.logging import get_logger
15
16 if TYPE_CHECKING:
17 from electrum.gui.qt.transaction_dialog import TxDialog
18
19
20 _logger = get_logger(__name__)
21
22
23 try:
24 import amodem.audio
25 import amodem.main
26 import amodem.config
27 _logger.info('Audio MODEM is available.')
28 amodem.log.addHandler(amodem.logging.StreamHandler(sys.stderr))
29 amodem.log.setLevel(amodem.logging.INFO)
30 except ImportError:
31 amodem = None
32 _logger.info('Audio MODEM is not found.')
33
34
35 class Plugin(BasePlugin):
36
37 def __init__(self, parent, config, name):
38 BasePlugin.__init__(self, parent, config, name)
39 if self.is_available():
40 self.modem_config = amodem.config.slowest()
41 self.library_name = {
42 'Linux': 'libportaudio.so'
43 }[platform.system()]
44
45 def is_available(self):
46 return amodem is not None
47
48 def requires_settings(self):
49 return True
50
51 def settings_widget(self, window):
52 return EnterButton(_('Settings'), partial(self.settings_dialog, window))
53
54 def settings_dialog(self, window):
55 d = WindowModalDialog(window, _("Audio Modem Settings"))
56
57 layout = QGridLayout(d)
58 layout.addWidget(QLabel(_('Bit rate [kbps]: ')), 0, 0)
59
60 bitrates = list(sorted(amodem.config.bitrates.keys()))
61
62 def _index_changed(index):
63 bitrate = bitrates[index]
64 self.modem_config = amodem.config.bitrates[bitrate]
65
66 combo = QComboBox()
67 combo.addItems([str(x) for x in bitrates])
68 combo.currentIndexChanged.connect(_index_changed)
69 layout.addWidget(combo, 0, 1)
70
71 ok_button = QPushButton(_("OK"))
72 ok_button.clicked.connect(d.accept)
73 layout.addWidget(ok_button, 1, 1)
74
75 return bool(d.exec_())
76
77 @hook
78 def transaction_dialog(self, dialog: 'TxDialog'):
79 b = QPushButton()
80 b.setIcon(read_QIcon("speaker.png"))
81
82 def handler():
83 blob = dialog.tx.serialize()
84 self._send(parent=dialog, blob=blob)
85 b.clicked.connect(handler)
86 dialog.sharing_buttons.insert(-1, b)
87
88 @hook
89 def scan_text_edit(self, parent):
90 parent.addButton('microphone.png', partial(self._recv, parent),
91 _("Read from microphone"))
92
93 @hook
94 def show_text_edit(self, parent):
95 def handler():
96 blob = str(parent.toPlainText())
97 self._send(parent=parent, blob=blob)
98 parent.addButton('speaker.png', handler, _("Send to speaker"))
99
100 def _audio_interface(self):
101 interface = amodem.audio.Interface(config=self.modem_config)
102 return interface.load(self.library_name)
103
104 def _send(self, parent, blob):
105 def sender_thread():
106 with self._audio_interface() as interface:
107 src = BytesIO(blob)
108 dst = interface.player()
109 amodem.main.send(config=self.modem_config, src=src, dst=dst)
110
111 _logger.info(f'Sending: {repr(blob)}')
112 blob = zlib.compress(blob.encode('ascii'))
113
114 kbps = self.modem_config.modem_bps / 1e3
115 msg = 'Sending to Audio MODEM ({0:.1f} kbps)...'.format(kbps)
116 WaitingDialog(parent, msg, sender_thread)
117
118 def _recv(self, parent):
119 def receiver_thread():
120 with self._audio_interface() as interface:
121 src = interface.recorder()
122 dst = BytesIO()
123 amodem.main.recv(config=self.modem_config, src=src, dst=dst)
124 return dst.getvalue()
125
126 def on_finished(blob):
127 if blob:
128 blob = zlib.decompress(blob).decode('ascii')
129 _logger.info(f'Received: {repr(blob)}')
130 parent.setText(blob)
131
132 kbps = self.modem_config.modem_bps / 1e3
133 msg = 'Receiving from Audio MODEM ({0:.1f} kbps)...'.format(kbps)
134 WaitingDialog(parent, msg, receiver_thread, on_finished)