Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/develop/one_dragon/modules/application.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ config/

使用 `ApplicationGroupManager` 获取具体的应用组配置。

默认应用组(one_dragon)会在初始化的注册应用后,添加到应用组管理器中。
默认应用组(one_dragon)会在初始化的注册应用后,添加到应用组管理器中。配置中从未出现过的新应用会按当前默认顺序显示在列表头部,初始为禁用状态,但不会立即写入用户保存的应用顺序;用户第一次启用、拖拽排序或点击运行后才会保存,拖拽排序会保存当前显示的完整顺序,点击运行会保存被运行应用的当前位置。已有应用的顺序和启用状态保持不变。

### 应用组运行

Expand Down
11 changes: 11 additions & 0 deletions docs/develop/one_dragon/modules/application_plugin_system.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
**类常量**:
- `REQUIRED_CONST_FIELDS`: app_const 模块必须定义的字段(`APP_ID`, `APP_NAME`, `DEFAULT_GROUP`, `NEED_NOTIFY`)
- `OPTIONAL_PLUGIN_FIELDS`: 可选的插件元数据字段(`PLUGIN_AUTHOR`, `PLUGIN_HOMEPAGE`, `PLUGIN_VERSION`, `PLUGIN_DESCRIPTION`)
- 可选 app 常量字段:`PRIORITY`(整数,默认组 app 的排序优先级)

## 目录结构

Expand Down Expand Up @@ -99,6 +100,16 @@ project_root/
- 会出现在"一条龙"运行列表中
- 可以被用户排序和启用/禁用
- 适用于:体力刷本、咖啡店、邮件等日常任务
- 可选定义 `PRIORITY` 整数;数值越小越靠前。显式 priority 相同的 app 按 `app_id` 排序,未定义 priority 的 app 排在全部显式 priority app 之后。
- priority 只决定初始默认/候选顺序,不会覆盖用户保存的应用组顺序。

可运行以下开发入口查看内置应用与 `plugins/` 中第三方应用的实际 priority:

```shell
uv run python src/zzz_od/application/devtools/application_priority_scanner.py
```

入口只解析应用目录中的 factory/const 文件,不会初始化游戏上下文或启动 GUI。输出按 priority 排序,并包含默认组、来源、app ID、名称和 const 文件位置。

### 非默认组应用 (default_group=False)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def __init__(self, app_const: ModuleType):
- APP_NAME: 显示用的应用名称
- DEFAULT_GROUP: 是否属于默认应用组
- NEED_NOTIFY: 应用是否需要通知
- PRIORITY: 默认组排序优先级(可选)

Args:
app_const: 应用常量模块
Expand All @@ -51,6 +52,12 @@ def __init__(self, app_const: ModuleType):
self.app_name: str = app_const.APP_NAME
self.default_group: bool = app_const.DEFAULT_GROUP
self.need_notify: bool = app_const.NEED_NOTIFY
priority = getattr(app_const, 'PRIORITY', None)
if priority is not None and (
not isinstance(priority, int) or isinstance(priority, bool)
):
raise ValueError(f'应用 {self.app_id} 的 PRIORITY 必须为整数')
self.priority: int | None = priority
self._config_cache: dict[str, ApplicationConfig] = {}
self._run_record_cache: dict[str, AppRunRecord] = {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ def discover_factories(
non_default_factories.extend(non_default)
default_factories.extend(default)

default_factories.sort(
key=lambda factory: (
factory.priority is None,
factory.priority if factory.priority is not None else 0,
factory.app_id,
)
)

log.info(
f"发现 {len(non_default_factories)} 个非默认组应用, "
f"{len(default_factories)} 个默认组应用, "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@

class ApplicationGroupConfigItem:

def __init__(self, app_id: str, enabled: bool):
def __init__(self, app_id: str, enabled: bool, is_persisted: bool = True):
"""
应用组配置项

Args:
app_id: 应用ID
enabled: 是否启用
is_persisted: 是否已进入用户保存的应用顺序
"""
self.app_id: str = app_id
self.enabled: bool = enabled
self.is_persisted: bool = is_persisted
self.app_name: str = '' # 不需要保存 每次注入


Expand Down Expand Up @@ -54,11 +56,13 @@ def _init_app_list(self) -> None:
)

def save_app_list(self) -> None:
"""保存应用列表,同步 app_list 排序到 _all_apps 后写入文件"""
# 将 app_list 的排序同步回 _all_apps,未注册的应用保持原位
active_set = {item.app_id for item in self.app_list}
"""保存已持久化的应用列表,并同步其显示顺序。"""
persisted_apps = [item for item in self.app_list if item.is_persisted]

# 将已持久化应用的排序同步回 _all_apps,未注册的应用保持原位
active_set = {item.app_id for item in persisted_apps}
active_indices = [i for i, item in enumerate(self._all_apps) if item.app_id in active_set]
for idx, item in zip(active_indices, self.app_list, strict=True):
for idx, item in zip(active_indices, persisted_apps, strict=True):
self._all_apps[idx] = item

self.update("app_list", [
Expand All @@ -74,28 +78,58 @@ def update_full_app_list(self, app_id_list: list[str]) -> None:
更新完整的应用ID列表
只应该被默认组使用 用于填充一条龙默认应用

在 _all_apps 中保留所有配置项(含未注册的),保持原有顺序。
新注册的应用追加到末尾。app_list 只包含已注册的应用。
在 _all_apps 中保留所有已保存配置项(含未注册的),保持原有顺序。
新注册的应用按默认顺序显示在头部,初始为禁用状态,但不立即保存。
app_list 包含已注册的已保存项和未保存新项。

Args:
app_id_list: 当前已注册的应用ID列表
"""
registered_set = set(app_id_list)
seen: set[str] = {item.app_id for item in self._all_apps}

# 追加新注册但不在配置中的应用
changed = False
persisted_ids = {item.app_id for item in self._all_apps}
transient_map = {
item.app_id: item
for item in self.app_list
if not item.is_persisted
}

transient_items: list[ApplicationGroupConfigItem] = []
for app_id in app_id_list:
if app_id not in seen:
seen.add(app_id)
self._all_apps.append(ApplicationGroupConfigItem(app_id=app_id, enabled=False))
changed = True
if app_id not in persisted_ids:
transient_items.append(
transient_map.get(app_id)
or ApplicationGroupConfigItem(
app_id=app_id,
enabled=False,
is_persisted=False,
)
)

# 从 _all_apps 中过滤出已注册的应用
self.app_list = [item for item in self._all_apps if item.app_id in registered_set]
persisted_items = [
item for item in self._all_apps if item.app_id in registered_set
]
self.app_list = transient_items + persisted_items

if changed:
self.save_app_list()
def _persist_app_item(self, item: ApplicationGroupConfigItem) -> bool:
"""将运行时临时应用加入用户保存顺序。"""
if item.is_persisted:
return False

item.is_persisted = True
self._all_apps.append(item)
return True

def persist_app(self, app_id: str) -> None:
"""
持久化指定应用当前的显示位置。

Args:
app_id: 应用ID
"""
for item in self.app_list:
if item.app_id == app_id and self._persist_app_item(item):
self.save_app_list()
return

def set_app_enable(self, app_id: str, enabled: bool) -> None:
"""
Expand All @@ -109,6 +143,8 @@ def set_app_enable(self, app_id: str, enabled: bool) -> None:
app_list = self.app_list
for item in app_list:
if item.app_id == app_id:
if enabled:
changed = self._persist_app_item(item) or changed
if item.enabled != enabled:
changed = True
item.enabled = enabled
Expand All @@ -128,7 +164,7 @@ def remove_app(self, app_id: str) -> None:

def set_app_order(self, app_id_list: list[str]) -> None:
"""
设置应用运行顺序
设置应用运行顺序,并将当前列表中的临时应用纳入保存顺序。

Args:
app_id_list: 应用ID列表
Expand All @@ -148,6 +184,8 @@ def set_app_order(self, app_id_list: list[str]) -> None:
new_list.append(item)

self.app_list = new_list
for item in self.app_list:
self._persist_app_item(item)
self.save_app_list()

def move_up_app(self, app_id: str) -> None:
Expand Down
7 changes: 4 additions & 3 deletions src/one_dragon_qt/view/one_dragon/one_dragon_run_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,8 @@ def _on_app_list_changed(self, new_app_list: list[ApplicationGroupConfigItem]) -
Args:
new_app_list: 新顺序的应用列表
"""
# 更新配置中的 app_list 顺序
self.config.app_list = new_app_list
self.config.save_app_list()
# 更新配置中的 app_list 顺序;用户主动调整顺序时一并保存临时应用
self.config.set_app_order([item.app_id for item in new_app_list])

def _on_app_card_run(self, app_id: str) -> None:
"""
Expand All @@ -231,7 +230,9 @@ def _on_app_card_run(self, app_id: str) -> None:
"""
for app in self.config.app_list:
if app.app_id == app_id:
self.config.persist_app(app_id)
self.run_app_by_item(app)
break

def on_app_switch_run(self, app_id: str, value: bool) -> None:
"""
Expand Down
1 change: 1 addition & 0 deletions src/zzz_od/application/charge_plan/charge_plan_const.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
APP_ID = "charge_plan"
APP_NAME = "体力刷本"
DEFAULT_GROUP = True
PRIORITY = 600
NEED_NOTIFY = True
1 change: 1 addition & 0 deletions src/zzz_od/application/city_fund/city_fund_const.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
APP_ID = 'city_fund'
APP_NAME = '丽都城募'
DEFAULT_GROUP = True
PRIORITY = 800
NEED_NOTIFY = True
1 change: 1 addition & 0 deletions src/zzz_od/application/coffee/coffee_app_const.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
APP_ID = "coffee"
APP_NAME = "咖啡店"
DEFAULT_GROUP = True
PRIORITY = 500
NEED_NOTIFY = True
1 change: 1 addition & 0 deletions src/zzz_od/application/daily_signin/daily_signin_const.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
APP_ID = "daily_signin"
APP_NAME = "每日签到"
DEFAULT_GROUP = True
PRIORITY = 300
NEED_NOTIFY = True
Loading
Loading