[fix] disable already added devices in DeskHub recent picker

This commit is contained in:
dijunkun
2026-10-14 10:20:20 +08:00
parent 3ee0d42494
commit 5721222724
5 changed files with 43 additions and 17 deletions
@@ -4628,7 +4628,9 @@ bool GuiApplication::ImportGalleryRecent(const std::string& input_group) {
std::vector<std::string> ids;
for (size_t i = 0; i < ui_->gallery_recent_model->row_count(); ++i) {
const auto device = ui_->gallery_recent_model->row_data(i);
if (device && device->selected) ids.emplace_back(device->id);
if (device && device->selected && !device->added &&
!ui_->gallery.Contains(std::string(device->id)))
ids.emplace_back(device->id);
}
if (ids.empty()) return false;
const auto group = Trim(input_group);
@@ -4773,6 +4775,7 @@ void GuiApplication::GalleryAction(const std::string& action,
? wall.groups[group_index - 1] : ""));
std::vector<ui::GalleryRecentDevice> devices;
std::set<std::string> seen;
int available = 0;
for (const auto& [_, recent] : recent_connections_) {
if (!gallery::Workspace::ValidId(recent.remote_id) ||
!seen.insert(recent.remote_id).second)
@@ -4781,25 +4784,31 @@ void GuiApplication::GalleryAction(const std::string& action,
device.id = UiText(recent.remote_id);
device.name = UiText(settings_.RecentConnectionDisplayName(recent));
device.online = device_presence_cache_.IsOnline(recent.remote_id);
device.added = wall.Contains(recent.remote_id);
device.selected = device.added;
if (!device.added) ++available;
devices.push_back(std::move(device));
}
ui_->gallery_recent_model->set_vector(std::move(devices));
ui_->wall->set_gallery_recent_devices(ui_->gallery_recent_model);
ui_->wall->set_gallery_recent_selected(0);
ui_->wall->set_gallery_recent_available(available);
return;
}
if (action == "recent-close") {
ui_->gallery_recent_model->set_vector({});
ui_->wall->set_gallery_recent_selected(0);
ui_->wall->set_gallery_recent_available(0);
ui_->wall->set_gallery_notice("");
return;
}
if (action == "recent-select" || action == "recent-all") {
const bool select_all = ui_->wall->get_gallery_recent_selected() <
int(ui_->gallery_recent_model->row_count());
ui_->wall->get_gallery_recent_available();
int count = 0;
for (size_t i = 0; i < ui_->gallery_recent_model->row_count(); ++i) {
auto device = *ui_->gallery_recent_model->row_data(i);
if (device.added) continue;
if (action == "recent-all" || std::string(device.id) == value) {
device.selected = action == "recent-all" ? select_all : !device.selected;
ui_->gallery_recent_model->set_row_data(i, device);
@@ -5179,14 +5188,24 @@ void GuiApplication::SyncGallery() {
}
if (ui_->wall->get_gallery_importing()) {
// Keep the picker selection and ordering stable when presence changes.
int available = 0, selected = 0;
for (size_t i = 0; i < ui_->gallery_recent_model->row_count(); ++i) {
auto device = *ui_->gallery_recent_model->row_data(i);
const bool online = device_presence_cache_.IsOnline(std::string(device.id));
if (device.online != online) {
const bool added = ui_->gallery.Contains(std::string(device.id));
if (device.online != online || device.added != added) {
device.online = online;
if (device.added != added) device.selected = added;
device.added = added;
ui_->gallery_recent_model->set_row_data(i, device);
}
if (!device.added) {
++available;
if (device.selected) ++selected;
}
}
ui_->wall->set_gallery_recent_available(available);
ui_->wall->set_gallery_recent_selected(selected);
}
const auto tr = [this](const char* zh, const char* en,
const char* ru) -> std::string {
@@ -62,6 +62,9 @@ struct Workspace {
std::all_of(id.begin(), id.end(),
[](unsigned char c) { return c >= '0' && c <= '9'; });
}
bool Contains(const std::string &id) const {
return wall_ids_.count(id) != 0;
}
bool Add(const std::string &id, const std::string &group = {}) {
if (!ValidId(id))
return false;
+14 -12
View File
@@ -33,6 +33,7 @@ export struct GalleryRecentDevice {
id: string,
name: string,
selected: bool,
added: bool,
online: bool,
}
export struct GalleryActionDevice {
@@ -159,6 +160,7 @@ export component GalleryView inherits Rectangle {
in-out property <bool> importing: false;
in property <[GalleryRecentDevice]> recent-devices;
in property <int> recent-selected: 0;
in property <int> recent-available: 0;
in property <string> import-group;
private property <bool> confirming: false;
private property <string> action-name;
@@ -922,10 +924,10 @@ export component GalleryView inherits Rectangle {
background: white; border-radius: 8px; border-width: 1px; border-color: #b2b2b2;
Text { x: 18px; y: 16px; height: 24px; text: GalleryStrings.tr("从最近连接添加", "Add from recent connections", "Добавить из недавних"); font-size: 16px; }
Text { x: 18px; y: 44px; width: 404px; height: 18px; text: GalleryStrings.tr("加入桌面墙后,可通过批量选择连接", "Add devices, then use Select to connect them.", "После добавления подключайтесь через выбор."); color: #62666d; font-size: 11px; }
ImGuiCheckBox { x: 18px; y: 74px; enabled: root.recent-devices.length > 0; checked: root.recent-devices.length > 0 && root.recent-selected == root.recent-devices.length; }
Text { x: 45px; y: 74px; height: 21px; text: GalleryStrings.tr("全选", "Select all", "Выбрать все"); font-size: 12px; vertical-alignment: center; }
TouchArea { x: 18px; y: 74px; width: 144px; height: 21px; enabled: root.recent-devices.length > 0; clicked => { root.action("recent-all", ""); } }
Text { x: 224px; y: 74px; width: 198px; height: 21px; text: GalleryStrings.tr("已选 ", "Selected ", "Выбрано ") + root.recent-selected + " / " + root.recent-devices.length; horizontal-alignment: right; vertical-alignment: center; font-size: 12px; color: #62666d; }
ImGuiCheckBox { x: 18px; y: 74px; enabled: root.recent-available > 0; checked: root.recent-devices.length > 0 && root.recent-selected == root.recent-available; }
Text { x: 45px; y: 74px; height: 21px; text: GalleryStrings.tr("全选", "Select all", "Выбрать все"); color: root.recent-available > 0 ? #24272d : #92969e; font-size: 12px; vertical-alignment: center; }
TouchArea { x: 18px; y: 74px; width: 144px; height: 21px; enabled: root.recent-available > 0; clicked => { root.action("recent-all", ""); } }
Text { x: 224px; y: 74px; width: 198px; height: 21px; text: GalleryStrings.tr("待添加 ", "To add ", "К добавлению ") + root.recent-selected + " / " + root.recent-available; horizontal-alignment: right; vertical-alignment: center; font-size: 12px; color: #62666d; }
Rectangle {
x: 18px; y: 102px; width: 404px; height: 160px;
border-width: 1px; border-color: #d8dadd; border-radius: 4px; clip: true;
@@ -935,17 +937,17 @@ export component GalleryView inherits Rectangle {
viewport-height: max(self.height, root.recent-devices.length * 44px);
for device[index] in root.recent-devices: Rectangle {
y: index * 44px; width: recent-list.viewport-width; height: 44px;
background: device.selected ? #edf5fe : row-touch.has-hover ? #f4f5f6 : white;
ImGuiCheckBox { x: 8px; y: 11px; checked: device.selected; }
Text { x: 36px; y: 3px; width: parent.width - 126px; height: 20px; text: device.name; font-size: 12px; overflow: elide; vertical-alignment: center; }
Text { x: 36px; y: 23px; width: parent.width - 126px; height: 16px; text: device.id; font-size: 11px; color: #808080; }
Rectangle { x: parent.width - 74px; y: 19px; width: 6px; height: 6px; border-radius: 3px; background: device.online ? #21b567 : #92969e; }
background: device.added ? #f1f2f4 : device.selected ? #edf5fe : row-touch.has-hover ? #f4f5f6 : white;
ImGuiCheckBox { x: 8px; y: 11px; enabled: !device.added; checked: device.added || device.selected; }
Text { x: 36px; y: 3px; width: parent.width - 126px; height: 20px; text: device.name; color: device.added ? #92969e : #24272d; font-size: 12px; overflow: elide; vertical-alignment: center; }
Text { x: 36px; y: 23px; width: parent.width - 126px; height: 16px; text: device.id; font-size: 11px; color: device.added ? #92969e : #808080; }
Rectangle { x: parent.width - 74px; y: 19px; width: 6px; height: 6px; border-radius: 3px; background: !device.added && device.online ? #21b567 : #92969e; }
Text {
x: parent.width - 61px; y: 12px; width: 57px; height: 20px;
text: device.online ? GalleryStrings.tr("在线", "Online", "В сети") : GalleryStrings.tr("离线", "Offline", "Не в сети");
color: device.online ? #17854c : #808080; font-size: 11px; vertical-alignment: center;
text: device.added ? GalleryStrings.tr("已添加", "Added", "Добавлено") : device.online ? GalleryStrings.tr("在线", "Online", "В сети") : GalleryStrings.tr("离线", "Offline", "Не в сети");
color: device.added ? #92969e : device.online ? #17854c : #808080; font-size: 11px; vertical-alignment: center;
}
row-touch := TouchArea { clicked => { root.action("recent-select", device.id); } }
row-touch := TouchArea { enabled: !device.added; clicked => { root.action("recent-select", device.id); } }
}
}
if root.recent-devices.length == 0: Text { text: GalleryStrings.tr("暂无最近连接", "No recent connections", "Нет недавних подключений"); color: #808080; font-size: 12px; horizontal-alignment: center; vertical-alignment: center; }
+3 -1
View File
@@ -341,6 +341,7 @@ export component MainWindow inherits Window {
in-out property <bool> gallery-importing: false;
in property <[GalleryRecentDevice]> gallery-recent-devices;
in property <int> gallery-recent-selected: 0;
in property <int> gallery-recent-available: 0;
in property <string> gallery-import-group;
callback open-gallery();
callback toggle-gallery-fullscreen();
@@ -1337,7 +1338,8 @@ export component MainWindow inherits Window {
selected-devices: root.gallery-selected-devices;
focused: root.gallery-focused; batch <=> root.gallery-batch; adding <=> root.gallery-adding;
importing <=> root.gallery-importing; recent-devices: root.gallery-recent-devices;
recent-selected: root.gallery-recent-selected; import-group: root.gallery-import-group;
recent-selected: root.gallery-recent-selected;
recent-available: root.gallery-recent-available; import-group: root.gallery-import-group;
action(code, value) => { root.gallery-action(code, value); }
swap-devices(source, target) => { root.gallery-swap(source, target) }
add-device(id, password, group, remember) => { root.gallery-add-device(id, password, group, remember) }
+1 -1
View File
@@ -11,7 +11,7 @@
## 使用
- 在桌面墙中点“添加 → 通过设备 ID 添加”,填写设备 ID、密码和可选的分组名称,再点“添加并连接”。密码仅用于本次连接,勾选“记住密码”才会通过原有凭据机制保存;不会写入桌面墙配置。
- “添加 → 从近期连接添加”支持多选、全选和统一指定分组。导入后只加入桌面墙,使用“选择 → 连接”再发起连接。同一分组内重复设备会跳过;不指定分组时,已在桌面墙中的设备不会重复加入。
- “添加 → 从近期连接添加”支持多选、全选和统一指定分组。已加入桌面墙的设备显示为灰色、保持勾选并标注“已添加”,不可操作,不受当前分组筛选影响;全选和待添加数量只计算尚未加入的设备,全部已添加时禁用添加按钮。导入后只加入桌面墙,使用“选择 → 连接”再发起连接。
- 连接成功后立即记录在连接页的“最近连接”中,无需等到断开,也不要求记住密码。失败的连接不会新增最近记录。
- “全部设备”显示保存的成员及当前活动会话。分组成员与连接相互独立:断开后成员仍在,重启后不会自动连接。
- 卡片名称栏只显示设备名,长名称省略,不再显示状态圆点。未在线的设备(离线或在线状态未知)整张卡片使用灰色,包括预览背景、边框和名称;在线但尚未连接的设备保持正常样式。选中边框、复选框和操作入口仍可用。悬停画面可查看设备名称、ID 和在线状态,精简模式也支持。在线状态订阅包含全部分组中的设备;尚未收到结果、结果过期或服务器断连时显示未知,已有活动连接的设备仍显示在线。