Skip to content

Commit b70c2a9

Browse files
committed
[0.8.0] add background image
1 parent f5ecc99 commit b70c2a9

File tree

8 files changed

+565
-24
lines changed

8 files changed

+565
-24
lines changed

app_state/__init__.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,21 @@
1717
separators=(",", ":"))
1818

1919

20-
@dataclass
20+
@dataclass(slots=True)
2121
class AppSettings(StateBase):
2222
proxy_mode: ProxyMode = ProxyMode.NONE
2323
custom_proxy_url: str = ""
2424
custom_tray_icon: str = ""
2525
custom_tray_hint: str = ""
2626
custom_font: str = ""
2727
prefer_proto: PreferProto = PreferProto.RTMP
28+
custom_bg: str = ""
29+
custom_bg_blur_radius: float = 10.0
30+
custom_bg_opacity: float = 50.0
31+
custom_bg_mode: BackgroundMode = BackgroundMode.COVER
2832

2933

30-
@dataclass
34+
@dataclass(slots=True)
3135
class ObsSettings(StateBase):
3236
ip_addr: str = "localhost"
3337
port: str = "4455"
@@ -36,7 +40,7 @@ class ObsSettings(StateBase):
3640
auto_connect: bool = False
3741

3842

39-
@dataclass
43+
@dataclass(slots=True)
4044
class ScanStatus(StateBase):
4145
scanned: bool = False
4246
qr_key: Optional[str] = None
@@ -52,7 +56,7 @@ class ScanStatus(StateBase):
5256
announce_updated: bool = False
5357

5458

55-
@dataclass
59+
@dataclass(slots=True)
5660
class StreamStatus(StateBase):
5761
live_status: bool = False
5862
required_face: bool = False
@@ -62,7 +66,7 @@ class StreamStatus(StateBase):
6266
stream_key: Optional[str] = None
6367

6468

65-
@dataclass
69+
@dataclass(slots=True)
6670
class RoomInfo(StateBase):
6771
cover_audit_reason: str = ""
6872
cover_url: str = ""
@@ -147,6 +151,13 @@ def app_settings_default() -> None:
147151
app_settings.reset()
148152

149153

154+
def bg_settings_default() -> None:
155+
app_settings["custom_bg"] = ""
156+
app_settings["custom_bg_blur_radius"] = 10.0
157+
app_settings["custom_bg_opacity"] = 10.0
158+
app_settings["custom_bg_mode"] = BackgroundMode.COVER
159+
160+
150161
def scan_settings_default() -> None:
151162
scan_status.reset()
152163
scan_status["const_updated"] = True

app_state/app_state_base.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
from PySide6.QtCore import QMutex, QMutexLocker
66

77

8-
@dataclass
8+
@dataclass(slots=True)
99
class StateBase:
1010
_lock: QMutex = field(default_factory=QMutex, init=False, repr=False)
11+
_default: bool = False
1112

1213
# obj["field"]
1314
def __getitem__(self, key: str) -> Any:
@@ -18,6 +19,7 @@ def __getitem__(self, key: str) -> Any:
1819

1920
# obj["field"] = value
2021
def __setitem__(self, key: str, value: Any) -> None:
22+
self._default = False
2123
with QMutexLocker(self._lock):
2224
if not hasattr(self, key):
2325
raise KeyError(key)
@@ -33,6 +35,7 @@ def get(self, key: str, default: Any = None) -> Any:
3335
# obj.update({...})
3436
def update(self, mapping: Mapping[str, Any] | None = None,
3537
**kwargs: Any) -> None:
38+
self._default = False
3639
with QMutexLocker(self._lock):
3740
if mapping:
3841
for k, v in mapping.items():
@@ -70,6 +73,7 @@ def default_dict(cls) -> dict[str, Any]:
7073
return result
7174

7275
def reset(self) -> None:
76+
self._default = True
7377
defaults = type(self).default_dict()
7478
with QMutexLocker(self._lock):
7579
for name, value in defaults.items():
@@ -100,4 +104,4 @@ def __len__(self) -> int:
100104
return len([f for f in fields(self) if not f.name.startswith("_")])
101105

102106
def __bool__(self) -> bool:
103-
return bool(len(self))
107+
return self._default

constant/__init__.py

Lines changed: 218 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
"KEYRING_SERVICE_NAME", "KEYRING_COOKIES", "KEYRING_COOKIES_INDEX",
55
"KEYRING_SETTINGS", "KEYRING_ROOM_INFO", "KEYRING_APP_SETTINGS",
66
"LOCAL_SERVER_NAME", "LOGGER_NAME", "USERNAME_DISPLAY_TEMPLATE",
7-
"MAX_RECENT_TITLE", "VERSION", "DARK_CSS", "LIGHT_CSS",
7+
"MAX_RECENT_TITLE", "VERSION", "DARK_COVER_CSS", "DARK_CSS", "LIGHT_COVER_CSS",
8+
"LIGHT_CSS",
89
"ProxyMode", "PreferProto", "CoverStatus",
9-
"WidgetIndex", "CacheType"
10+
"WidgetIndex", "CacheType", "BackgroundMode"
1011
]
1112

1213

@@ -45,6 +46,14 @@ class CacheType(StrEnum):
4546
CONFIG = "config"
4647

4748

49+
@unique
50+
class BackgroundMode(IntEnum):
51+
NO_SCALE = 0 # 无拉伸
52+
STRETCH = 1 # 等比拉伸
53+
FIT = 2 # 等比填充
54+
COVER = 3 # 等比适应
55+
56+
4857
KEYRING_SERVICE_NAME = "StartLive|userCredentials"
4958
KEYRING_COOKIES = "cookies"
5059
KEYRING_COOKIES_INDEX = "cookiesIndex"
@@ -84,6 +93,109 @@ class CacheType(StrEnum):
8493
START_LIVE_AUTH_CSRF = True
8594
STOP_LIVE_AUTH_CSRF = False
8695

96+
DARK_COVER_CSS = """QWidget {
97+
background: transparent;
98+
}
99+
100+
QComboBox {
101+
background-color: #3C404D;
102+
border: none;
103+
border-radius: 4px;
104+
padding: 2px 1px 2px 2px;
105+
padding-left: 8px;
106+
height: 22 + 8 - 4px * 2;
107+
}
108+
109+
QLineEdit, QTextEdit, QPlainTextEdit {
110+
background-color: #3C404D;
111+
border: none;
112+
border-radius: 4px;
113+
padding: 4px 1px 4px 4px;
114+
padding-left: 10px;
115+
border: 1px solid #3C404D;
116+
height: 22 + 8 - 4px * 2;
117+
}
118+
119+
QLineEdit:hover, QTextEdit:hover, QPlainTextEdit:hover {
120+
background-color: #3C404D;
121+
border-color: #5B6273;
122+
}
123+
124+
QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus {
125+
background-color: #3C404D;
126+
border-color: #284CB8;
127+
}
128+
129+
QDialog, QMainWindow, QStatusBar, QMenuBar {
130+
background-color: #1D1F26;
131+
background: transparent;
132+
}
133+
134+
QMenu {
135+
background-color: #1D1F26;
136+
}
137+
138+
QMenu::icon {
139+
left: 4px;
140+
}
141+
142+
QMenu::separator {
143+
background: #3C404D;
144+
height: 1px;
145+
margin: 2px 4px;
146+
}
147+
148+
QMenu::item:disabled {
149+
color: rgb(153, 153, 153);
150+
background: transparent;
151+
}
152+
153+
QMenuBar::item {
154+
background-color: transparent;
155+
}
156+
157+
QMenuBar::item:selected {
158+
background: #284CB8;
159+
}
160+
161+
QMenu::item {
162+
padding: 4px 4px + 8;
163+
}
164+
165+
QMenu::item {
166+
padding-right: 20px;
167+
}
168+
169+
QListWidget, QMenu, SceneTree, SourceTree {
170+
padding: 2px;
171+
}
172+
173+
QMenu::item {
174+
padding: 4px 4px + 8;
175+
}
176+
177+
QMenu::item {
178+
padding-right: 20px;
179+
}
180+
181+
QListWidget::item, SourceTreeItem, QMenu::item, SceneTree::item {
182+
border-radius: 5px;
183+
color: #FFFFFF;
184+
border: 1px solid transparent;
185+
}
186+
187+
QMenu::item:selected {
188+
background-color: #284CB8;
189+
}
190+
191+
QMenu::item:hover, QMenu::item:selected:hover {
192+
background-color: #476BD7;
193+
color: #FFFFFF;
194+
}
195+
196+
QMenu::item:focus, QMenu::item:selected:focus {
197+
border: 1px solid "transparent";
198+
}"""
87199
DARK_CSS = """QComboBox {
88200
background-color: #3C404D;
89201
border: none;
@@ -178,7 +290,11 @@ class CacheType(StrEnum):
178290
QMenu::item:focus, QMenu::item:selected:focus {
179291
border: 1px solid "transparent";
180292
}"""
181-
LIGHT_CSS = """QComboBox {
293+
LIGHT_COVER_CSS = """QWidget {
294+
background: transparent;
295+
}
296+
297+
QComboBox {
182298
margin-top: 1px;
183299
margin-bottom: 1px;
184300
background-color: #FFFFFF;
@@ -217,6 +333,7 @@ class CacheType(StrEnum):
217333
218334
QMenuBar {
219335
background-color: #e5e5e5;
336+
background: transparent;
220337
}
221338
222339
QMenu {
@@ -276,3 +393,101 @@ class CacheType(StrEnum):
276393
QMenuBar::item {
277394
background-color: transparent;
278395
}"""
396+
LIGHT_CSS = """QComboBox {
397+
margin-top: 1px;
398+
margin-bottom: 1px;
399+
background-color: #FFFFFF;
400+
border-color: #5B6273;
401+
border-radius: 4px;
402+
padding: 2px 1px 2px 2px;
403+
padding-left: 8px;
404+
border: 1px solid #d3d3d3;
405+
height: 22 + 8 - 4px * 2;
406+
}
407+
408+
QCheckBox {
409+
margin-top: 1px;
410+
margin-bottom: 1px;
411+
}
412+
413+
QLineEdit {
414+
background-color: #FFFFFF;
415+
border-color: #5B6273;
416+
border-radius: 4px;
417+
padding: 4px 1px 4px 4px;
418+
padding-left: 10px;
419+
border: 1px solid #d3d3d3;
420+
height: 22 + 8 - 4px * 2;
421+
}
422+
423+
QLineEdit:hover {
424+
background-color: #FFFFFF;
425+
border-color: #5B6273;
426+
}
427+
428+
QLineEdit:focus {
429+
background-color: #FFFFFF;
430+
border-color: #284CB8;
431+
}
432+
433+
QMenuBar {
434+
background-color: #e5e5e5;
435+
}
436+
437+
QMenu {
438+
background-color: #e5e5e5;
439+
padding: 2px;
440+
}
441+
442+
QMenu::icon {
443+
left: 4px;
444+
}
445+
446+
QMenu::separator {
447+
background: #FFFFFF;
448+
height: 1px;
449+
margin: 2px 4px;
450+
}
451+
452+
QMenu::item:hover {
453+
background-color: #476BD7;
454+
color: #000000;
455+
}
456+
457+
QMenu::item:selected:hover {
458+
background-color: #476BD7;
459+
color: #000000;
460+
}
461+
462+
QMenu::item:disabled {
463+
color: rgb(153, 153, 153);
464+
background: transparent;
465+
}
466+
467+
QMenu::item:focus {
468+
border: 1px solid "transparent";
469+
}
470+
471+
QMenu::item:selected:focus {
472+
border: 1px solid "transparent";
473+
}
474+
475+
QMenu::item:selected {
476+
background-color: #8cb5ff;
477+
}
478+
479+
QMenu::item {
480+
padding: 4px 4px + 8;
481+
padding-right: 20px;
482+
border-radius: 5px;
483+
color: #000000;
484+
border: 1px solid transparent;
485+
}
486+
487+
QMenuBar::item:selected {
488+
background: #8cb5ff;
489+
}
490+
491+
QMenuBar::item {
492+
background-color: transparent;
493+
}"""

models/widgets/sl_menu_bar.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class StartLiveMenuBar(QMenuBar):
2020
cookieDeleted = Signal(int, bool, bool)
2121
obsSettingsDeleted = Signal()
2222
appSettingsDeleted = Signal()
23+
bgDeleted = Signal()
2324
credDeleted = Signal(bool)
2425
accountSwitch = Signal(int)
2526
accountAdded = Signal()
@@ -52,6 +53,10 @@ def __init__(self, parent=None, /):
5253
delete_app_settings.triggered.connect(self._delete_app_settings)
5354
self._setting_menu.addAction(delete_app_settings)
5455

56+
delete_bg = QAction("清除背景设置", self)
57+
delete_bg.triggered.connect(self._on_delete_bg)
58+
self._setting_menu.addAction(delete_bg)
59+
5560
delete_cred = QAction("清空所有凭据", self)
5661
delete_cred.triggered.connect(self._delete_cred)
5762
self._setting_menu.addAction(delete_cred)
@@ -140,6 +145,10 @@ def _delete_cred(self):
140145
rmtree(cache_base_dir(CacheType.CONFIG))
141146
self.credDeleted.emit(True)
142147

148+
@Slot()
149+
def _on_delete_bg(self):
150+
self.bgDeleted.emit()
151+
143152
@Slot()
144153
def _switch_account(self, action: QAction):
145154
idx = action.data()

0 commit comments

Comments
 (0)