Fix toasts and modal dialogs
Toasts calculated the duration bar in python this is now a QPropertyAnimation Series/Issue Selection windows now use signals/slots to communicate
This commit is contained in:
parent
13ee9e9ad8
commit
ca8f36d105
@ -143,6 +143,7 @@ class IssueSelectionWindow(SelectionWindow):
|
||||
self.accept()
|
||||
|
||||
def update_row(self, row: int, issue: GenericMetadata) -> None: # type: ignore[override]
|
||||
self.twList.setStyleSheet(self.twList.styleSheet())
|
||||
item_text = issue.issue or ""
|
||||
item = self.twList.item(row, 0)
|
||||
item.setText(item_text)
|
||||
|
@ -23,7 +23,7 @@ from collections import deque
|
||||
|
||||
import natsort
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets, uic
|
||||
from PyQt5.QtCore import QUrl, pyqtSignal
|
||||
from PyQt5.QtCore import Qt, QUrl, pyqtSignal
|
||||
|
||||
from comicapi import utils
|
||||
from comicapi.comicarchive import ComicArchive
|
||||
@ -149,6 +149,7 @@ class SelectionWindow(QtWidgets.QDialog):
|
||||
literal: bool = False,
|
||||
) -> None:
|
||||
super().__init__(parent)
|
||||
self.setWindowModality(Qt.WindowModality.WindowModal)
|
||||
|
||||
with self.ui_file.open(encoding="utf-8") as uifile:
|
||||
uic.loadUi(uifile, self)
|
||||
@ -497,7 +498,6 @@ class SeriesSelectionWindow(SelectionWindow):
|
||||
selector = MatchSelectionWindow(
|
||||
self, issues, self.comic_archive, talker=self.talker, config=self.config
|
||||
)
|
||||
selector.setModal(True)
|
||||
selector.exec()
|
||||
if selector.result():
|
||||
# we should now have a list index
|
||||
@ -523,9 +523,8 @@ class SeriesSelectionWindow(SelectionWindow):
|
||||
break
|
||||
|
||||
self.selector.setWindowTitle(title + "Select Issue")
|
||||
self.selector.setModal(True)
|
||||
self.selector.finished.connect(self.issue_selected)
|
||||
self.selector.open()
|
||||
self.selector.show()
|
||||
|
||||
def issue_selected(self, result) -> None:
|
||||
if result and self.selector:
|
||||
|
@ -669,7 +669,6 @@ class SettingsWindow(QtWidgets.QDialog):
|
||||
|
||||
def show_template_help(self) -> None:
|
||||
template_help_win = TemplateHelpWindow(self)
|
||||
template_help_win.setModal(False)
|
||||
template_help_win.show()
|
||||
|
||||
|
||||
|
@ -1090,8 +1090,7 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
self.selector.setWindowTitle(f"Search: '{series_name}' - Select Series")
|
||||
self.selector.finished.connect(self.finish_query)
|
||||
|
||||
self.selector.setModal(True)
|
||||
self.selector.open()
|
||||
self.selector.show()
|
||||
|
||||
def finish_query(self, result) -> None:
|
||||
if result and self.selector:
|
||||
@ -1154,20 +1153,22 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
self.metadata_to_form()
|
||||
|
||||
def on_ratelimit(self, full_time: float, sleep_time: float) -> None:
|
||||
toast = Toast(self)
|
||||
# Convert to milliseconds, make it end half a second before the ratelimit triggers again, make sure we have a positive time
|
||||
toast.setDuration(abs(int(sleep_time * 1000) - 500))
|
||||
toast.setResetDurationOnHover(False)
|
||||
toast.setTitle("Rate Limit Hit!")
|
||||
toast.setText(
|
||||
self.toast = Toast(self)
|
||||
if qtutils.is_dark_mode():
|
||||
self.toast.applyPreset(ToastPreset.WARNING_DARK)
|
||||
else:
|
||||
self.toast.applyPreset(ToastPreset.WARNING)
|
||||
|
||||
# Convert to milliseconds, add 200ms because python is slow
|
||||
self.toast.setDuration(abs(int(sleep_time * 1000) + 200))
|
||||
self.toast.setResetDurationOnHover(False)
|
||||
self.toast.setFadeOutDuration(50)
|
||||
self.toast.setTitle("Rate Limit Hit!")
|
||||
self.toast.setText(
|
||||
f"Rate limit reached: {full_time:.0f}s until next request. Waiting {sleep_time:.0f}s for ratelimit"
|
||||
)
|
||||
if qtutils.is_dark_mode():
|
||||
toast.applyPreset(ToastPreset.WARNING_DARK)
|
||||
else:
|
||||
toast.applyPreset(ToastPreset.WARNING)
|
||||
toast.setPositionRelativeToWidget(self)
|
||||
toast.show()
|
||||
self.toast.setPositionRelativeToWidget(self)
|
||||
self.toast.show()
|
||||
|
||||
def write_tags(self) -> None:
|
||||
if self.metadata is not None and self.comic_archive is not None:
|
||||
@ -1395,7 +1396,6 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
|
||||
def show_settings(self) -> None:
|
||||
settingswin = SettingsWindow(self, self.config, self.talkers)
|
||||
settingswin.setModal(True)
|
||||
settingswin.exec()
|
||||
settingswin.result()
|
||||
self.adjust_source_combo()
|
||||
@ -1779,8 +1779,7 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
return
|
||||
|
||||
self.atprogdialog = AutoTagProgressWindow(self, self.current_talker())
|
||||
self.atprogdialog.setModal(True)
|
||||
self.atprogdialog.show()
|
||||
self.atprogdialog.open()
|
||||
self.atprogdialog.progressBar.setMaximum(len(ca_list))
|
||||
self.atprogdialog.setWindowTitle("Auto-Tagging")
|
||||
|
||||
@ -1862,7 +1861,6 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
self.config[0],
|
||||
self.current_talker(),
|
||||
)
|
||||
matchdlg.setModal(True)
|
||||
matchdlg.exec()
|
||||
self.fileSelectionList.update_selected_rows()
|
||||
new_ca = self.fileSelectionList.get_current_archive()
|
||||
@ -1980,7 +1978,6 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
"File Rename", "If you rename files now, unsaved data in the form will be lost. Are you sure?"
|
||||
):
|
||||
dlg = RenameWindow(self, ca_list, self.selected_read_tags, self.config, self.talkers)
|
||||
dlg.setModal(True)
|
||||
if dlg.exec() and self.comic_archive is not None:
|
||||
self.fileSelectionList.update_selected_rows()
|
||||
self.load_archive(self.comic_archive)
|
||||
|
@ -49,6 +49,15 @@
|
||||
<verstretch>7</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTableWidget[rowCount="0"] {
|
||||
background-image: url(":/graphics/about.png");
|
||||
background-attachment: fixed;
|
||||
background-position: top center;
|
||||
background-repeat: no-repeat;
|
||||
background-color: white;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
|
@ -3,7 +3,6 @@ from __future__ import annotations
|
||||
from PyQt5.QtGui import QColor
|
||||
|
||||
UPDATE_POSITION_DURATION = 200
|
||||
DURATION_BAR_UPDATE_INTERVAL = 1
|
||||
DROP_SHADOW_SIZE = 5
|
||||
SUCCESS_ACCENT_COLOR = QColor("#3E9141")
|
||||
WARNING_ACCENT_COLOR = QColor("#E8B849")
|
||||
@ -23,7 +22,6 @@ DEFAULT_CLOSE_BUTTON_ICON_COLOR_DARK = QColor("#C9C9C9")
|
||||
|
||||
__all__ = [
|
||||
"UPDATE_POSITION_DURATION",
|
||||
"DURATION_BAR_UPDATE_INTERVAL",
|
||||
"DROP_SHADOW_SIZE",
|
||||
"SUCCESS_ACCENT_COLOR",
|
||||
"WARNING_ACCENT_COLOR",
|
||||
|
@ -2,7 +2,18 @@ from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
from PyQt5.QtCore import QEvent, QMargins, QPoint, QPropertyAnimation, QRect, QSize, Qt, QTimer, pyqtSignal
|
||||
from PyQt5.QtCore import (
|
||||
QAbstractAnimation,
|
||||
QEvent,
|
||||
QMargins,
|
||||
QPoint,
|
||||
QPropertyAnimation,
|
||||
QRect,
|
||||
QSize,
|
||||
Qt,
|
||||
QTimer,
|
||||
pyqtSignal,
|
||||
)
|
||||
from PyQt5.QtGui import QColor, QFont, QFontMetrics, QGuiApplication, QIcon, QPixmap, QScreen
|
||||
from PyQt5.QtWidgets import QDialog, QGraphicsOpacityEffect, QLabel, QPushButton, QWidget
|
||||
|
||||
@ -19,7 +30,6 @@ from .constants import (
|
||||
DEFAULT_TITLE_COLOR,
|
||||
DEFAULT_TITLE_COLOR_DARK,
|
||||
DROP_SHADOW_SIZE,
|
||||
DURATION_BAR_UPDATE_INTERVAL,
|
||||
ERROR_ACCENT_COLOR,
|
||||
INFORMATION_ACCENT_COLOR,
|
||||
SUCCESS_ACCENT_COLOR,
|
||||
@ -95,7 +105,6 @@ class Toast(QDialog):
|
||||
self.__close_button_margins = QMargins(0, -8, 0, -8)
|
||||
self.__text_section_spacing = 8
|
||||
|
||||
self.__elapsed_time = 0
|
||||
self.__fading_out = False
|
||||
self.__used = False
|
||||
|
||||
@ -145,7 +154,6 @@ class Toast(QDialog):
|
||||
|
||||
# Duration bar chunk
|
||||
self.__duration_bar_chunk = QWidget(self.__duration_bar_container)
|
||||
self.__duration_bar_chunk.setFixedHeight(20)
|
||||
self.__duration_bar_chunk.move(0, -16)
|
||||
|
||||
# Set defaults
|
||||
@ -173,10 +181,6 @@ class Toast(QDialog):
|
||||
self.__duration_timer.setSingleShot(True)
|
||||
self.__duration_timer.timeout.connect(self.hide)
|
||||
|
||||
# Timer for updating the duration bar
|
||||
self.__duration_bar_timer = QTimer(self)
|
||||
self.__duration_bar_timer.timeout.connect(self.__update_duration_bar)
|
||||
|
||||
# Apply stylesheet
|
||||
self.setStyleSheet((css_path / "toast.css").read_text(encoding="utf-8"))
|
||||
|
||||
@ -205,14 +209,13 @@ class Toast(QDialog):
|
||||
"""
|
||||
|
||||
# Reset timer if hovered and resetting is enabled
|
||||
if self.__duration != 0 and self.__duration_timer.isActive() and self.__reset_duration_on_hover:
|
||||
if self.__reset_duration_on_hover and self.__duration != 0 and self.__duration_timer.isActive():
|
||||
self.__duration_timer.stop()
|
||||
|
||||
# Reset duration bar if enabled
|
||||
if self.__show_duration_bar:
|
||||
self.__duration_bar_timer.stop()
|
||||
self.__duration_bar_chunk.setFixedWidth(self.width())
|
||||
self.__elapsed_time = 0
|
||||
self.__bar_animation.stop()
|
||||
self.__duration_bar_chunk.setGeometry(QRect(0, 0, self.__duration_bar_container.width(), 4))
|
||||
|
||||
def leaveEvent(self, event: QEvent) -> None:
|
||||
"""Event that happens every time the mouse leaves this widget.
|
||||
@ -222,12 +225,21 @@ class Toast(QDialog):
|
||||
"""
|
||||
|
||||
# Start timer again when leaving notification and reset is enabled
|
||||
if self.__duration != 0 and not self.__duration_timer.isActive() and self.__reset_duration_on_hover:
|
||||
if self.__reset_duration_on_hover and self.__duration != 0 and not self.__duration_timer.isActive():
|
||||
self.__duration_timer.start(self.__duration)
|
||||
|
||||
# Restart duration bar animation if enabled
|
||||
if self.__show_duration_bar:
|
||||
self.__duration_bar_timer.start(DURATION_BAR_UPDATE_INTERVAL)
|
||||
self.__start_duration_bar_animation()
|
||||
|
||||
def __start_duration_bar_animation(self) -> None:
|
||||
self.__bar_animation = QPropertyAnimation(self.__duration_bar_chunk, b"geometry")
|
||||
self.__bar_animation.setDuration(self.__duration)
|
||||
self.__bar_animation.setStartValue(QRect(0, 0, self.__duration_bar.width(), 4))
|
||||
self.__bar_animation.setEndValue(QRect(0, 0, 0, 4))
|
||||
self.__bar_animation.setDirection(QAbstractAnimation.Direction.Forward)
|
||||
|
||||
self.__bar_animation.start()
|
||||
|
||||
def show(self) -> None:
|
||||
"""Show the toast notification"""
|
||||
@ -244,16 +256,12 @@ class Toast(QDialog):
|
||||
# Setup UI
|
||||
self.__setup_ui()
|
||||
|
||||
# Calculate position and show (animate position too if not first notification)
|
||||
x, y = self.__calculate_position()
|
||||
# Start duration timer
|
||||
if self.__duration != 0:
|
||||
self.__duration_timer.start(self.__duration)
|
||||
|
||||
# Start duration bar update timer
|
||||
if self.__duration != 0 and self.__show_duration_bar:
|
||||
self.__duration_bar_timer.start(DURATION_BAR_UPDATE_INTERVAL)
|
||||
|
||||
# Calculate position and show (animate position too if not first notification)
|
||||
x, y = self.__calculate_position()
|
||||
self.__start_duration_bar_animation()
|
||||
|
||||
# If not first toast on screen, also do a fade down/up animation
|
||||
if len(Toast.__currently_shown) > 1:
|
||||
@ -327,7 +335,6 @@ class Toast(QDialog):
|
||||
|
||||
if self in Toast.__currently_shown:
|
||||
Toast.__currently_shown.remove(self)
|
||||
self.__elapsed_time = 0
|
||||
self.__fading_out = False
|
||||
|
||||
# Emit signal
|
||||
@ -343,21 +350,6 @@ class Toast(QDialog):
|
||||
timer.timeout.connect(Toast.__show_next_in_queue)
|
||||
timer.start(self.__fade_in_duration)
|
||||
|
||||
def __update_duration_bar(self) -> None:
|
||||
"""Update the duration bar chunk with the elapsed time"""
|
||||
|
||||
self.__elapsed_time += DURATION_BAR_UPDATE_INTERVAL
|
||||
|
||||
if self.__elapsed_time >= self.__duration:
|
||||
self.__duration_bar_timer.stop()
|
||||
return
|
||||
|
||||
new_chunk_width = math.floor(
|
||||
self.__duration_bar_container.width()
|
||||
- self.__elapsed_time / self.__duration * self.__duration_bar_container.width()
|
||||
)
|
||||
self.__duration_bar_chunk.setFixedWidth(new_chunk_width)
|
||||
|
||||
def __update_position_xy(self, animate: bool = True) -> None:
|
||||
"""Update the x and y position of the toast with an optional animation
|
||||
|
||||
@ -893,14 +885,11 @@ class Toast(QDialog):
|
||||
self.__close_button.setVisible(False)
|
||||
|
||||
# Resize, move, and show duration bar if enabled
|
||||
if self.__show_duration_bar:
|
||||
self.__duration_bar_container.setFixedWidth(width)
|
||||
self.__duration_bar_container.move(0, height - duration_bar_height)
|
||||
self.__duration_bar.setFixedWidth(width)
|
||||
self.__duration_bar_chunk.setFixedWidth(width)
|
||||
self.__duration_bar_container.setVisible(True)
|
||||
else:
|
||||
self.__duration_bar_container.setVisible(False)
|
||||
self.__duration_bar_container.setFixedWidth(width)
|
||||
self.__duration_bar_container.move(0, height - duration_bar_height)
|
||||
self.__duration_bar.setFixedWidth(width)
|
||||
|
||||
self.__duration_bar_container.setVisible(self.__show_duration_bar)
|
||||
|
||||
def __install_widget_event_filter(self) -> None:
|
||||
"""Install an event filter on parent"""
|
||||
|
Loading…
Reference in New Issue
Block a user