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