class PinConfirmationLayout(QVBoxLayout, ErrorMessageMixin, InputFieldMixin): def __init__(self, parent, email, error_msg=''): super(). __init__() self.parent = parent self.resend_strategy = parent.resend_strategy self.cool_down_thread = parent.cool_down_thread label = QLabel(_('To confirm the request, please enter the code we sent to') + f"<br><b>{email}</b>") label.setWordWrap(True) hbox = QHBoxLayout() code_label = QLabel(_('Code:')) pin_edit = PinInputFiled() hbox.addWidget(code_label) hbox.addWidget(pin_edit) pin_edit.textChanged.connect(self.input_edited) self.input_edit = pin_edit self.addWidget(label) self.addSpacing(10) self.addLayout(hbox) self.error_label = QLabel() self.error_label.setWordWrap(True) self.error_label.setVisible(False) if error_msg: self.set_error(error_msg) self.send_request_thread = TaskThread(None) if self.cool_down_thread.is_running(): self.resend_button = QPushButton(self.cool_down_thread.get_formatted_left_time()) self.resend_button.setEnabled(False) else: self.resend_button = QPushButton(_('Resend')) hbox.addStretch(1) hbox.addWidget(self.resend_button) self.resend_button.clicked.connect(self.resend_request) self.addSpacing(5) self.addLayout(hbox) self.addSpacing(5) self.addWidget(self.error_label) def on_error(self, errors): self.resend_strategy.on_error(errors[1]) self.set_error(str(errors[1])) def resend_request(self): self.clear_error() self.cool_down_thread.run() self.send_request_thread.add( task=lambda: self.resend_strategy.resend(), on_success=lambda *args, **kwargs: None, on_error=self.on_error ) def pin(self): return self.input_edit.text() def terminate_thread(self): self.send_request_thread.terminate()
class CoolDownThread: RESEND_COOL_DOWN_TIME = 30 def __init__(self): self.elapsed_time = 0 self.pin_layout = None self.thread = None def register_layout(self, layout: PinConfirmationLayout): self.pin_layout = layout def unregister_layout(self): self.pin_layout = None def _set_resend_button_status(self, text: str, enabled: bool): if self.pin_layout: self.pin_layout.resend_button.setText(text) self.pin_layout.resend_button.setEnabled(enabled) def get_left_time(self) -> int: return int(self.RESEND_COOL_DOWN_TIME - self.elapsed_time) def get_formatted_left_time(self) -> str: return f'{self.get_left_time():>2}s' def cool_down_task(self): t0 = datetime.datetime.now() while True: self.elapsed_time = (datetime.datetime.now() - t0).total_seconds() if self.get_left_time() < 1: break self._set_resend_button_status(self.get_formatted_left_time(), False) time.sleep(1) def on_success(self, *args, **kwargs): self._set_resend_button_status(_('Resend'), True) def run(self): self.thread = TaskThread(None) self.thread.add( task=self.cool_down_task, on_success=self.on_success, on_error=lambda *args, **kwargs: None, ) def is_running(self) -> bool: return bool(self.thread and self.get_left_time() > 0) def terminate(self): self.elapsed_time = 0 if self.thread: self.thread.terminate()