a13rollcall/constants.py
2026-10-06 18:38:55 +08:00

691 行
17 KiB
Python

# -*- coding: utf-8 -*-
"""
A13课堂点名系统 - 常量集中管理模块
所有魔法数字、字符串、颜色、尺寸等常量统一在此定义
"""
import os
from PyQt5.QtGui import QColor
from PyQt5.QtCore import Qt
# ==================== 应用信息 ====================
class AppInfo:
NAME = "A13课堂点名系统"
VERSION = "6.8.0"
BUILD = "20260914"
AUTHOR = "A13"
ENGINE_NAME = "A13 Engine"
OFFICIAL_URL = "https://dkfile.istester.com/zhysppa13/a13callname.html"
URL_SCHEME = "a13rollcall://"
# ==================== 文件路径 ====================
class FilePaths:
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STUDENTS_FILE = os.path.join(BASE_DIR, "students.txt")
TEXTS_FILE = os.path.join(BASE_DIR, "texts.txt")
CONFIG_FILE = os.path.join(BASE_DIR, "config.json")
WIZARD_RECORD = os.path.join(BASE_DIR, "wizard_record.ini")
ECHO_HOLE_FILE = os.path.join(BASE_DIR, "echo_hole.txt")
ICONS_DIR = os.path.join(BASE_DIR, "icons")
PLUGINS_DIR = os.path.join(BASE_DIR, "plugins")
PLUGIN_DATA_DIR = os.path.join(PLUGINS_DIR, "data")
PLUGIN_LOGS_DIR = os.path.join(PLUGINS_DIR, "logs")
CRASH_REPORT_DIR = os.path.join(BASE_DIR, "crash_reports")
BACKUP_DIR = os.path.join(BASE_DIR, "backups")
TEMP_DIR = os.path.join(BASE_DIR, "temp")
# ==================== 颜色主题 ====================
class Colors:
# 主色调
PRIMARY = "#0067c0"
PRIMARY_LIGHT = "#0078d4"
PRIMARY_DARK = "#005a9e"
PRIMARY_HOVER = "#106ebe"
PRIMARY_PRESSED = "#005a9e"
# 成功/警告/错误
SUCCESS = "#107c10"
SUCCESS_LIGHT = "#0e6c0e"
WARNING = "#ca5010"
WARNING_LIGHT = "#ff8c00"
ERROR = "#c42b1c"
ERROR_LIGHT = "#e81123"
INFO = "#0067c0"
# 中性色
WHITE = "#ffffff"
BLACK = "#000000"
GRAY_50 = "#fafafa"
GRAY_100 = "#f5f5f5"
GRAY_200 = "#eeeeee"
GRAY_300 = "#e0e0e0"
GRAY_400 = "#bdbdbd"
GRAY_500 = "#9e9e9e"
GRAY_600 = "#757575"
GRAY_700 = "#616161"
GRAY_800 = "#424242"
GRAY_900 = "#212121"
# 文本颜色
TEXT_PRIMARY = "#1a1a1a"
TEXT_SECONDARY = "#666666"
TEXT_DISABLED = "#999999"
TEXT_INVERSE = "#ffffff"
# 背景色
BG_WINDOW = "#f3f3f3"
BG_CARD = "#ffffff"
BG_HOVER = "#f0f0f0"
BG_SELECTED = "#e5f1fb"
BG_DISABLED = "#f5f5f5"
# 边框色
BORDER_LIGHT = "#e0e0e0"
BORDER_NORMAL = "#d1d1d1"
BORDER_DARK = "#bdbdbd"
BORDER_FOCUS = "#0067c0"
# 深色模式
DARK_BG_WINDOW = "#202020"
DARK_BG_CARD = "#2d2d2d"
DARK_BG_HOVER = "#3a3a3a"
DARK_BG_SELECTED = "#0067c0"
DARK_TEXT_PRIMARY = "#ffffff"
DARK_TEXT_SECONDARY = "#cccccc"
DARK_BORDER = "#404040"
# 抽取状态颜色
DRAW_IDLE = "#666666"
DRAW_RUNNING = "#0067c0"
DRAW_SUCCESS = "#107c10"
DRAW_WARNING = "#ca5010"
# 背诵状态颜色
STATUS_RECITED = "#107c10"
STATUS_NOT_FAMILIAR = "#ca5010"
STATUS_NOT_RECITED = "#c42b1c"
STATUS_UNMARKED = "#666666"
# ==================== 尺寸常量 ====================
class Sizes:
# 窗口尺寸
WINDOW_MIN_WIDTH = 1000
WINDOW_MIN_HEIGHT = 700
WINDOW_DEFAULT_WIDTH = 1400
WINDOW_DEFAULT_HEIGHT = 880
WINDOW_LARGE_WIDTH = 1600
WINDOW_LARGE_HEIGHT = 1000
# 标题栏
TITLE_BAR_HEIGHT = 48
TITLE_BAR_ICON_SIZE = 24
WINDOW_CONTROL_BTN_WIDTH = 46
WINDOW_CONTROL_BTN_HEIGHT = 32
# 按钮尺寸
BTN_SMALL_HEIGHT = 28
BTN_NORMAL_HEIGHT = 36
BTN_LARGE_HEIGHT = 44
BTN_XLARGE_HEIGHT = 52
BTN_SMALL_WIDTH = 72
BTN_NORMAL_WIDTH = 100
BTN_LARGE_WIDTH = 140
BTN_XLARGE_WIDTH = 180
# 圆角
RADIUS_SMALL = 4
RADIUS_NORMAL = 6
RADIUS_LARGE = 8
RADIUS_XLARGE = 12
RADIUS_2XLARGE = 16
RADIUS_FULL = 9999
# 间距
SPACING_XS = 4
SPACING_SMALL = 8
SPACING_NORMAL = 12
SPACING_LARGE = 16
SPACING_XLARGE = 24
SPACING_2XLARGE = 32
# 内边距
PADDING_XS = 4
PADDING_SMALL = 8
PADDING_NORMAL = 12
PADDING_LARGE = 16
PADDING_XLARGE = 20
PADDING_2XLARGE = 24
# 字体大小
FONT_XS = 10
FONT_SMALL = 11
FONT_NORMAL = 12
FONT_LARGE = 13
FONT_XLARGE = 14
FONT_2XLARGE = 16
FONT_3XLARGE = 18
FONT_4XLARGE = 20
FONT_5XLARGE = 24
FONT_TITLE = 28
FONT_BIG_TITLE = 32
FONT_HUGE = 48
# 字体粗细
FONT_WEIGHT_LIGHT = 300
FONT_WEIGHT_NORMAL = 400
FONT_WEIGHT_MEDIUM = 500
FONT_WEIGHT_SEMIBOLD = 600
FONT_WEIGHT_BOLD = 700
FONT_WEIGHT_EXTRABOLD = 800
# 图标尺寸
ICON_XS = 12
ICON_SMALL = 16
ICON_NORMAL = 20
ICON_LARGE = 24
ICON_XLARGE = 32
ICON_2XLARGE = 48
ICON_3XLARGE = 64
# 抽取名字显示
DRAW_NAME_FONT_MIN = 36
DRAW_NAME_FONT_MAX = 72
DRAW_NAME_FONT_DEFAULT = 56
# 阴影
SHADOW_SMALL = 4
SHADOW_NORMAL = 8
SHADOW_LARGE = 16
SHADOW_XLARGE = 24
# ==================== 时间常量 ====================
class Times:
# 动画时长(毫秒)
ANIMATION_FAST = 150
ANIMATION_NORMAL = 300
ANIMATION_SLOW = 500
ANIMATION_VERY_SLOW = 800
# 抽取动画
DRAW_ROLL_INTERVAL_MIN = 30
DRAW_ROLL_INTERVAL_MAX = 100
DRAW_ROLL_DURATION_MIN = 1500
DRAW_ROLL_DURATION_MAX = 3000
DRAW_RESULT_DISPLAY = 3000
# 提示显示时长
TOAST_SHORT = 1500
TOAST_NORMAL = 2500
TOAST_LONG = 4000
TOAST_VERY_LONG = 6000
# 自动保存间隔
AUTOSAVE_INTERVAL = 30000
# 启动延迟
STARTUP_DELAY_FAST = 100
STARTUP_DELAY_NORMAL = 300
STARTUP_DELAY_SLOW = 500
STARTUP_DELAY_VERY_SLOW = 1000
# 超时时间(秒)
TIMEOUT_SHORT = 5
TIMEOUT_NORMAL = 10
TIMEOUT_LONG = 30
TIMEOUT_VERY_LONG = 60
# 网络请求重试
NETWORK_RETRY_COUNT = 3
NETWORK_RETRY_DELAY = 1000
# ==================== UI样式 ====================
class Styles:
# 按钮基础样式
BTN_BASE = """
QPushButton {
border: none;
border-radius: %dpx;
font-weight: 600;
font-size: %dpx;
padding: 8px 16px;
}
"""
# 主按钮
BTN_PRIMARY = """
QPushButton {
background: %s;
color: white;
}
QPushButton:hover {
background: %s;
}
QPushButton:pressed {
background: %s;
}
QPushButton:disabled {
background: #cccccc;
color: #999999;
}
""" % (Colors.PRIMARY, Colors.PRIMARY_HOVER, Colors.PRIMARY_PRESSED)
# 成功按钮
BTN_SUCCESS = """
QPushButton {
background: %s;
color: white;
}
QPushButton:hover {
background: #0e6c0e;
}
QPushButton:pressed {
background: #0b5a0b;
}
QPushButton:disabled {
background: #cccccc;
color: #999999;
}
""" % Colors.SUCCESS
# 警告按钮
BTN_WARNING = """
QPushButton {
background: %s;
color: white;
}
QPushButton:hover {
background: #b04810;
}
QPushButton:pressed {
background: #963d0e;
}
QPushButton:disabled {
background: #cccccc;
color: #999999;
}
""" % Colors.WARNING
# 危险按钮
BTN_DANGER = """
QPushButton {
background: %s;
color: white;
}
QPushButton:hover {
background: #a52517;
}
QPushButton:pressed {
background: #8a1f13;
}
QPushButton:disabled {
background: #cccccc;
color: #999999;
}
""" % Colors.ERROR
# 幽灵按钮(边框按钮)
BTN_GHOST = """
QPushButton {
background: transparent;
color: %s;
border: 1px solid %s;
}
QPushButton:hover {
background: %s;
}
QPushButton:pressed {
background: #d0e4f7;
}
QPushButton:disabled {
color: #999999;
border-color: #dddddd;
}
""" % (Colors.PRIMARY, Colors.PRIMARY, Colors.BG_SELECTED)
# 输入框
INPUT_NORMAL = """
QLineEdit, QTextEdit, QPlainTextEdit {
background: white;
border: 1px solid %s;
border-radius: %dpx;
padding: 8px 12px;
font-size: %dpx;
selection-background-color: %s;
}
QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus {
border: 2px solid %s;
padding: 7px 11px;
}
QLineEdit:disabled, QTextEdit:disabled {
background: #f5f5f5;
color: #999999;
}
""" % (Colors.BORDER_NORMAL, Sizes.RADIUS_NORMAL, Sizes.FONT_NORMAL, Colors.PRIMARY, Colors.BORDER_FOCUS)
# 卡片
CARD = """
QWidget#card {
background: white;
border: 1px solid %s;
border-radius: %dpx;
}
""" % (Colors.BORDER_LIGHT, Sizes.RADIUS_LARGE)
# 分组框
GROUP_BOX = """
QGroupBox {
font-weight: 700;
font-size: %dpx;
border: 1px solid %s;
border-radius: %dpx;
margin-top: 12px;
padding-top: 16px;
background: white;
}
QGroupBox::title {
subcontrol-origin: margin;
left: 16px;
padding: 0 8px;
color: %s;
}
""" % (Sizes.FONT_LARGE, Colors.BORDER_LIGHT, Sizes.RADIUS_LARGE, Colors.PRIMARY)
# 标签页
TAB_WIDGET = """
QTabWidget::pane {
border: 1px solid %s;
border-radius: %dpx;
top: -1px;
}
QTabBar::tab {
padding: 10px 20px;
margin-right: 4px;
border-radius: %dpx %dpx 0 0;
font-size: %dpx;
font-weight: 600;
}
QTabBar::tab:selected {
background: %s;
color: white;
}
QTabBar::tab:!selected {
background: #f0f0f0;
color: #333;
}
QTabBar::tab:!selected:hover {
background: #e0e0e0;
}
""" % (Colors.BORDER_LIGHT, Sizes.RADIUS_NORMAL, Sizes.RADIUS_NORMAL, Sizes.RADIUS_NORMAL, Sizes.FONT_NORMAL, Colors.PRIMARY)
# 列表控件
LIST_WIDGET = """
QListWidget {
background: white;
border: 1px solid %s;
border-radius: %dpx;
padding: 8px;
font-size: %dpx;
outline: none;
}
QListWidget::item {
padding: 8px;
border-radius: 4px;
margin: 2px 0;
}
QListWidget::item:selected {
background: %s;
color: white;
}
QListWidget::item:hover:!selected {
background: %s;
}
""" % (Colors.BORDER_LIGHT, Sizes.RADIUS_NORMAL, Sizes.FONT_NORMAL, Colors.PRIMARY, Colors.BG_HOVER)
# 滚动条
SCROLLBAR = """
QScrollBar:vertical {
background: transparent;
width: 8px;
margin: 0;
}
QScrollBar::handle:vertical {
background: #c1c1c1;
border-radius: 4px;
min-height: 30px;
}
QScrollBar::handle:vertical:hover {
background: #a1a1a1;
}
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
height: 0;
}
QScrollBar:horizontal {
background: transparent;
height: 8px;
margin: 0;
}
QScrollBar::handle:horizontal {
background: #c1c1c1;
border-radius: 4px;
min-width: 30px;
}
QScrollBar::handle:horizontal:hover {
background: #a1a1a1;
}
QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
width: 0;
}
"""
# ==================== 快捷键 ====================
class Shortcuts:
# 抽取操作
DRAW_START_STOP = "Space"
RESET_ROUND = "Esc"
TOGGLE_NO_REPEAT = "N"
TOGGLE_WEIGHT = "W"
VIEW_ROUND_RECORD = "R"
# 状态标记
MARK_RECITED = "1"
MARK_NOT_FAMILIAR = "2"
MARK_NOT_RECITED = "3"
UNDO_LAST_MARK = "Z"
SKIP_CURRENT = "Tab"
# 课文与界面
TOGGLE_DRAW_MODE = "T"
PREV_TEXT = "Left"
NEXT_TEXT = "Right"
TOGGLE_THEME = "M"
OPEN_SETTINGS = ","
# 显示与效果
TOGGLE_PARTICLES = "P"
FULLSCREEN = "F11"
LEADERBOARD = "L"
SAVE_DATA = "Ctrl+S"
SHORTCUT_HELP = "?"
# ==================== 状态常量 ====================
class States:
# 抽取状态
DRAW_IDLE = "idle"
DRAW_RUNNING = "running"
DRAW_PAUSED = "paused"
DRAW_FINISHED = "finished"
# 背诵状态
STATUS_UNMARKED = "未标记"
STATUS_RECITED = "已背过"
STATUS_NOT_FAMILIAR = "未背熟"
STATUS_NOT_RECITED = "未背过"
STATUS_SKIPPED = "已跳过"
# 抽取模式
MODE_RANDOM = "random"
MODE_NO_REPEAT = "no_repeat"
MODE_WEIGHTED = "weighted"
# 窗口状态
WINDOW_NORMAL = "normal"
WINDOW_MINIMIZED = "minimized"
WINDOW_MAXIMIZED = "maximized"
WINDOW_FULLSCREEN = "fullscreen"
# 插件状态
PLUGIN_LOADED = "loaded"
PLUGIN_ENABLED = "enabled"
PLUGIN_DISABLED = "disabled"
PLUGIN_ERROR = "error"
# ==================== 配置键名 ====================
class ConfigKeys:
# 应用设置
APP_CLASS_NAME = "app.class_name"
APP_THEME = "app.theme"
APP_LANGUAGE = "app.language"
APP_AUTOSAVE = "app.autosave"
APP_STARTUP_MODE = "app.startup_mode"
APP_REMEMBER_WINDOW = "app.remember_window"
# 抽取设置
DRAW_MODE = "draw.mode"
DRAW_DURATION = "draw.duration"
DRAW_SHOW_TEXT = "draw.show_text"
DRAW_RANDOM_TEXT = "draw.random_text"
DRAW_AUTO_START = "draw.auto_start"
DRAW_SOUND_ENABLED = "draw.sound_enabled"
DRAW_PARTICLES_ENABLED = "draw.particles_enabled"
# 界面设置
UI_FONT_SIZE = "ui.font_size"
UI_DARK_MODE = "ui.dark_mode"
UI_WINDOW_OPACITY = "ui.window_opacity"
UI_ANIMATION_SPEED = "ui.animation_speed"
UI_SHOW_STATISTICS = "ui.show_statistics"
UI_SHOW_LEADERBOARD = "ui.show_leaderboard"
# 快捷抽取设置
QUICK_ENABLED = "quick.enabled"
QUICK_AUTO_HIDE = "quick.auto_hide"
QUICK_ON_TOP = "quick.on_top"
QUICK_POSITION = "quick.position"
# 插件设置
PLUGIN_AUTO_LOAD = "plugin.auto_load"
PLUGIN_SANDBOX = "plugin.sandbox"
PLUGIN_UPDATE_CHECK = "plugin.update_check"
# ==================== 错误码 ====================
class ErrorCodes:
# 通用错误
SUCCESS = 0
UNKNOWN_ERROR = -1
INVALID_PARAMETER = -2
OPERATION_FAILED = -3
PERMISSION_DENIED = -4
NOT_FOUND = -5
ALREADY_EXISTS = -6
# 文件错误
FILE_NOT_FOUND = -100
FILE_READ_ERROR = -101
FILE_WRITE_ERROR = -102
FILE_CORRUPTED = -103
FILE_LOCKED = -104
# 配置错误
CONFIG_INVALID = -200
CONFIG_PARSE_ERROR = -201
CONFIG_SCHEMA_ERROR = -202
# 插件错误
PLUGIN_NOT_FOUND = -300
PLUGIN_LOAD_ERROR = -301
PLUGIN_EXECUTE_ERROR = -302
PLUGIN_DEPENDENCY_MISSING = -303
PLUGIN_VERSION_INCOMPATIBLE = -304
PLUGIN_PERMISSION_DENIED = -305
PLUGIN_CRASHED = -306
# 网络错误
NETWORK_TIMEOUT = -400
NETWORK_CONNECTION_ERROR = -401
NETWORK_HTTP_ERROR = -402
NETWORK_SSL_ERROR = -403
# 数据错误
DATA_EMPTY = -500
DATA_INVALID = -501
DATA_DUPLICATE = -502
DATA_NOT_FOUND = -503
# ==================== 字体 ====================
class Fonts:
FAMILY_DEFAULT = "微软雅黑"
FAMILY_MONOSPACE = "Consolas"
FAMILY_UI = "Segoe UI"
@staticmethod
def get_font(size=Sizes.FONT_NORMAL, weight=Sizes.FONT_WEIGHT_NORMAL):
from PyQt5.QtGui import QFont
font = QFont(Fonts.FAMILY_DEFAULT, size)
font.setWeight(weight)
return font
@staticmethod
def get_monospace_font(size=Sizes.FONT_NORMAL):
from PyQt5.QtGui import QFont
font = QFont(Fonts.FAMILY_MONOSPACE, size)
return font
# ==================== 动画曲线 ====================
class AnimationCurves:
LINEAR = 0
EASE_IN = 1
EASE_OUT = 2
EASE_IN_OUT = 3
EASE_OUT_BACK = 4
EASE_OUT_ELASTIC = 5
EASE_OUT_BOUNCE = 6
SPRING = 7
# ==================== 工具函数 ====================
def get_color(color_str):
"""将颜色字符串转换为QColor"""
return QColor(color_str)
def get_opacity_color(color_str, opacity=0.5):
"""获取带透明度的颜色"""
color = QColor(color_str)
color.setAlphaF(opacity)
return color
def get_shadow_color(color_str, depth=Sizes.SHADOW_NORMAL):
"""获取阴影颜色"""
color = QColor(color_str)
color.setAlpha(40 + depth * 2)
return color
# ==================== 版本信息 ====================
__version__ = AppInfo.VERSION
__build__ = AppInfo.BUILD
__author__ = AppInfo.AUTHOR