Skip to content

Commit 29af5d2

Browse files
committed
feat(Search): 桌面端与移动端统一搜索框架
- 删除 _searchTarget 手动簿记,改用固定连接 + currentWidget 路由 - searchEdit 实例化移到 __init__ 遵循四段式骨架 - 移动端共享搜索框放在页面上方,页面切换自动重接 - filterToolBar 去掉 searchLineEdit,改为 filterSegment 居左 - 添加 android/preview.py 在桌面预览移动端 UI
1 parent f7c3c73 commit 29af5d2

6 files changed

Lines changed: 87 additions & 21 deletions

File tree

android/preview.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""在桌面上预览移动端 UI,用于开发调试。
2+
3+
用法: uv run python android/preview.py
4+
"""
5+
import sys
6+
from pathlib import Path
7+
8+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
9+
10+
import app.platform.android as _android
11+
_android.nativeLibraryDir = lambda: ""
12+
_android.isStorageGranted = lambda: True
13+
_android.requestStoragePermission = lambda: None
14+
_android.sharedText = lambda: None
15+
_android.clearShare = lambda: None
16+
_android.isSystemDark = lambda: False
17+
18+
import app.platform.android_notification as _notif
19+
_notif.isNotificationEnabled = lambda: True
20+
_notif.requestNotificationPermission = lambda: None
21+
22+
23+
if __name__ == "__main__":
24+
from main import setupEnvironment
25+
from app.platform.application import SingletonApplication
26+
from app.startup import loadEngine, loadPacks, startEngine, stopEngine
27+
28+
setupEnvironment()
29+
app = SingletonApplication(sys.argv, "gd3-mobile-preview")
30+
31+
from app.view.mobile import setupAndroid
32+
setupAndroid()
33+
34+
loadEngine(app)
35+
loadPacks()
36+
37+
from app.view.mobile.window import MobileMainWindow
38+
from app.view.mobile.device import setupTouchScrolling
39+
window = MobileMainWindow()
40+
window.resize(400, 800)
41+
window.show()
42+
setupTouchScrolling(window)
43+
44+
startEngine()
45+
app.aboutToQuit.connect(stopEngine)
46+
sys.exit(app.exec())

app/view/mobile/setting_page.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from PySide6.QtCore import Qt
22
from PySide6.QtGui import QColor, QPalette
33
from PySide6.QtWidgets import QHBoxLayout, QSizePolicy, QVBoxLayout, QWidget
4-
from qfluentwidgets import SearchLineEdit, SettingCard, SwitchButton, isDarkTheme, qconfig
4+
from qfluentwidgets import SettingCard, SwitchButton, isDarkTheme, qconfig
55

66
from app.view.components.setting_card_group import CollapsibleSettingCardGroup
77
from app.view.pages.setting_page import SettingPage
@@ -12,12 +12,6 @@
1212
class MobileSettingPage(SettingPage):
1313
def __init__(self, parent=None):
1414
super().__init__(parent)
15-
16-
self.searchEdit = SearchLineEdit(self.container)
17-
self.searchEdit.setPlaceholderText(self.tr("搜索设置"))
18-
self.vBoxLayout.insertWidget(0, self.searchEdit)
19-
self.searchEdit.textChanged.connect(self.setSearchText)
20-
2115
self._setScrollContentOpaque()
2216

2317
def showEvent(self, event):

app/view/mobile/task_page.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ def _initLayout(self) -> None:
5151
filterToolBarLayout = QHBoxLayout(self.filterToolBar)
5252
filterToolBarLayout.setContentsMargins(10, 0, 10, 4)
5353
filterToolBarLayout.setSpacing(6)
54-
filterToolBarLayout.addWidget(self.sortButton)
5554
filterToolBarLayout.addWidget(self.filterSegment)
55+
filterToolBarLayout.addStretch(1)
56+
filterToolBarLayout.addWidget(self.sortButton)
5657
filterToolBarLayout.addWidget(self.categoryFilterButton)
57-
filterToolBarLayout.addWidget(self.searchLineEdit, 1)
5858

5959
layout = QVBoxLayout(self)
6060
layout.setContentsMargins(0, 0, 0, 0)

app/view/mobile/window.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
from PySide6.QtCore import QEvent, QSize, Qt
44
from PySide6.QtGui import QColor, QIcon, QPainter
5-
from PySide6.QtWidgets import QApplication, QStackedWidget, QVBoxLayout, QWidget
5+
from PySide6.QtWidgets import QApplication, QHBoxLayout, QStackedWidget, QVBoxLayout, QWidget
66
from qfluentwidgets import (
7-
FluentIcon, InfoBar, InfoBarPosition, PrimaryToolButton,
7+
FluentIcon, InfoBar, InfoBarPosition, PrimaryToolButton, SearchLineEdit,
88
Theme, isDarkTheme, qconfig,
99
)
1010

@@ -38,6 +38,7 @@ def __init__(self):
3838
)
3939
self.taskPage = MobileTaskPage(self)
4040
self.settingPage = MobileSettingPage(self)
41+
self.searchEdit = SearchLineEdit(self)
4142
self.addButton = PrimaryToolButton(FluentIcon.ADD, self)
4243
self.vBoxLayout = QVBoxLayout(self)
4344

@@ -50,13 +51,16 @@ def __init__(self):
5051
self._bind()
5152
self._updatePermissionBanner()
5253
self._updateAddButtonVisibility()
54+
self._updateSearchTarget(self.taskPage)
5355

5456
def _initWidget(self):
5557
self.setObjectName("MobileMainWindow")
5658
self.setWindowIcon(QIcon(":/image/logo.png"))
5759
self.setWindowTitle("Ghost Downloader")
5860
self.taskPage.setObjectName("taskInterface")
5961
self.settingPage.setObjectName("settingInterface")
62+
self.searchEdit.setClearButtonEnabled(True)
63+
self.taskPage.searchLineEdit.hide()
6064
self.addButton.setFixedSize(56, 56)
6165
self.addButton.setIconSize(QSize(22, 22))
6266
self.addButton.raise_()
@@ -68,12 +72,21 @@ def _initLayout(self):
6872
self.vBoxLayout.setSpacing(0)
6973
self.vBoxLayout.addWidget(self.permissionBanner, 0)
7074
self.vBoxLayout.addWidget(self.notificationBanner, 0)
75+
searchBar = QWidget(self)
76+
searchBarLayout = QHBoxLayout(searchBar)
77+
searchBarLayout.setContentsMargins(10, 6, 10, 6)
78+
searchBarLayout.addWidget(self.searchEdit)
79+
self.vBoxLayout.addWidget(searchBar, 0)
7180
self.vBoxLayout.addWidget(self.stackedWidget, 1)
7281
self.vBoxLayout.addWidget(self.navigationBar, 0)
7382

7483
def _bind(self):
7584
self.navigationBar.currentChanged.connect(self.stackedWidget.setCurrentIndex)
7685
self.navigationBar.currentChanged.connect(lambda *_: self._updateAddButtonVisibility())
86+
self.navigationBar.currentChanged.connect(
87+
lambda index: self._updateSearchTarget(self.stackedWidget.widget(index))
88+
)
89+
self.searchEdit.textChanged.connect(self._onSearchTextChanged)
7790
self.taskPage.selectionModeChanged.connect(lambda *_: self._updateAddButtonVisibility())
7891
self.addButton.clicked.connect(self._showAddTaskDialog)
7992
self._draft.taskConfirmed.connect(taskService.add)
@@ -87,6 +100,19 @@ def _addPage(self, page: QWidget, icon: FluentIcon, text: str):
87100
self.stackedWidget.addWidget(page)
88101
self.navigationBar.addItem(icon, text)
89102

103+
def _onSearchTextChanged(self, text: str) -> None:
104+
page = self.stackedWidget.currentWidget()
105+
if hasattr(page, 'setSearchText'):
106+
page.setSearchText(text)
107+
108+
def _updateSearchTarget(self, page: QWidget) -> None:
109+
self.searchEdit.clear()
110+
if hasattr(page, 'setSearchText'):
111+
self.searchEdit.setPlaceholderText(page.searchPlaceholder)
112+
self.searchEdit.show()
113+
else:
114+
self.searchEdit.hide()
115+
90116
def _onSystemColorSchemeChanged(self, colorScheme):
91117
if cfg.themeMode.value != Theme.AUTO:
92118
return

app/view/pages/setting_page.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ def _initCards(self) -> None:
319319
self.feedbackCard = PrimaryPushSettingCard(
320320
self.tr("提供反馈"), FluentIcon.FEEDBACK,
321321
self.tr("提供反馈"),
322-
self.tr("通过提供反馈来帮助我们改进 Ghost Downloader(日志)"),
322+
self.tr("通过提供反馈来帮助我们改进 Ghost Downloader,也可查看日志排查问题"),
323323
)
324324
self.openLogButton = PushButton(self.tr("查看日志"), self.feedbackCard)
325325
self.feedbackCard.hBoxLayout.insertSpacing(6, 8)

app/view/windows/main_window.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ class MainWindow(MSFluentWindow):
3131
def __init__(self, parent=None):
3232
self._isGeometryRestored = False
3333
self._isBackgroundEffectDirty = False
34-
self._searchTarget = None
34+
self.searchEdit = None
3535
super().__init__(parent)
3636
self.setMicaEffectEnabled(False)
3737
self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
3838

3939
self._pages: dict[str, QWidget] = {}
40-
4140
self._draft = TaskDraft(parent=self)
41+
self.searchEdit = SearchLineEdit(self.titleBar)
4242

4343
self._initWidget()
4444
self._initLayout()
@@ -52,7 +52,6 @@ def _initWidget(self) -> None:
5252
if sys.platform == "darwin":
5353
self.titleBar.hBoxLayout.insertSpacing(0, 60)
5454

55-
self.searchEdit = SearchLineEdit(self.titleBar)
5655
self.searchEdit.setClearButtonEnabled(True)
5756
self.searchEdit.hide()
5857
self.searchEdit.raise_()
@@ -112,14 +111,14 @@ def _showPage(self, pageClass: type[QWidget]) -> None:
112111
self.navigationInterface.setCurrentItem(routeKey)
113112
self._updateSearchTarget(page)
114113

114+
def _onSearchTextChanged(self, text: str) -> None:
115+
page = self.stackedWidget.currentWidget()
116+
if hasattr(page, 'setSearchText'):
117+
page.setSearchText(text)
118+
115119
def _updateSearchTarget(self, page: QWidget) -> None:
116120
self.searchEdit.clear()
117-
if self._searchTarget is not None:
118-
self.searchEdit.textChanged.disconnect(self._searchTarget)
119-
self._searchTarget = None
120121
if hasattr(page, 'setSearchText'):
121-
self._searchTarget = page.setSearchText
122-
self.searchEdit.textChanged.connect(self._searchTarget)
123122
self.searchEdit.setPlaceholderText(page.searchPlaceholder)
124123
self.searchEdit.show()
125124
else:
@@ -146,6 +145,7 @@ def _bind(self) -> None:
146145
QApplication.instance().styleHints().colorSchemeChanged.connect(self._onSystemColorSchemeChanged)
147146
self.titleBar.closeBtn.clicked.disconnect(self.close)
148147
self.titleBar.closeBtn.clicked.connect(self._onCloseClicked)
148+
self.searchEdit.textChanged.connect(self._onSearchTextChanged)
149149

150150
from PySide6.QtGui import QKeySequence, QShortcut
151151
QShortcut(QKeySequence.StandardKey.Find, self).activated.connect(self._onSearchShortcut)
@@ -294,7 +294,7 @@ def _onCloseClicked(self) -> None:
294294

295295
def resizeEvent(self, event) -> None:
296296
super().resizeEvent(event)
297-
if self._searchTarget is not None:
297+
if self.searchEdit is not None and self.searchEdit.isVisible():
298298
self._refreshSearchEditGeometry()
299299

300300
def closeEvent(self, event) -> None:

0 commit comments

Comments
 (0)