diff --git a/CHANGELOG/v2.3.0-beta.2/CHANGELOG.md b/CHANGELOG/v2.3.0-beta.2/CHANGELOG.md
index ce8d00841..405be9e78 100644
--- a/CHANGELOG/v2.3.0-beta.2/CHANGELOG.md
+++ b/CHANGELOG/v2.3.0-beta.2/CHANGELOG.md
@@ -15,6 +15,7 @@ v2.3 - Shiroko (砂狼白子) beta 2
- 优化 **浮窗**,切换同步收纳显示
- 优化 **计时器**,倒计时页面居中显示,秒表居中与所有时钟字距优化
- 优化 **更新安装**,管理员静默安装并退出
+- 优化 **ClassIsland 联动**,现在可以传递更多信息
## 🐛 修复问题
diff --git a/app/common/IPC_URL/csharp_ipc_handler.py b/app/common/IPC_URL/csharp_ipc_handler.py
index 7bd9260ab..6a4aced32 100644
--- a/app/common/IPC_URL/csharp_ipc_handler.py
+++ b/app/common/IPC_URL/csharp_ipc_handler.py
@@ -1,13 +1,23 @@
import sys
import asyncio
import threading
-from typing import Optional
+from typing import Optional, Any, TypedDict
from loguru import logger
from app.tools.path_utils import get_data_path
CSHARP_AVAILABLE = False
+
+class SelectedStudentNotificationInfo(TypedDict):
+ student_id: int
+ student_name: str
+ display_text: str
+ exists: bool
+ group_name: str
+ lottery_name: str
+
+
if sys.platform == "win32":
try:
sys.path.append(str(get_data_path("dlls")))
@@ -31,7 +41,12 @@
GeneratedIpcFactory,
)
from SecRandom4Ci.Interface.Enums import ResultType
- from SecRandom4Ci.Interface.Models import CallResult, NotificationData, Student
+ from SecRandom4Ci.Interface.Models import (
+ CallResult,
+ Student,
+ NotificationData,
+ NotificationItem,
+ )
from SecRandom4Ci.Interface.Services import ISecRandomService
CSHARP_AVAILABLE = True
@@ -117,7 +132,7 @@ def stop_ipc_client(self):
def send_notification(
self,
class_name,
- selected_students,
+ selected_students: list[SelectedStudentNotificationInfo],
draw_count=1,
settings=None,
settings_group=None,
@@ -130,6 +145,13 @@ def send_notification(
if not self.is_connected:
return False
+ coerced_students: list[SelectedStudentNotificationInfo] = []
+ for student in selected_students or []:
+ item = self._coerce_student(student)
+ if item is None:
+ continue
+ coerced_students.append(item)
+
if settings:
display_duration = settings.get("notification_display_duration", 5)
else:
@@ -156,11 +178,11 @@ def send_notification(
result.ClassName = class_name
result.DrawCount = draw_count
result.DisplayDuration = display_duration
- for student in selected_students:
+ for student in coerced_students:
cs_student = Student()
- cs_student.StudentId = student[0]
- cs_student.StudentName = student[1]
- cs_student.Exists = student[2]
+ cs_student.StudentId = student["student_id"]
+ cs_student.StudentName = student["display_text"]
+ cs_student.Exists = student["exists"]
result.SelectedStudents.Add(cs_student)
randomService.NotifyResult(result)
@@ -193,12 +215,16 @@ def send_notification(
data.ClassName = class_name
data.DrawCount = draw_count
data.DisplayDuration = display_duration
- for student in selected_students:
- cs_student = Student()
- cs_student.StudentId = student[0]
- cs_student.StudentName = student[1]
- cs_student.Exists = student[2]
- data.Items.Add(cs_student)
+ for student in coerced_students:
+ item = NotificationItem()
+ item.StudentId = student["student_id"]
+ item.StudentName = student["student_name"]
+ item.Exists = student["exists"]
+ item.HasGroup = bool(student["group_name"])
+ item.GroupName = student["group_name"]
+ item.IsLottery = bool(student["lottery_name"])
+ item.LotteryName = student["lottery_name"]
+ data.Items.Add(item)
randomService.ShowNotification(data)
return True
@@ -452,6 +478,61 @@ def check_plugin_alive(self) -> bool:
return randomService.IsAlive() == "Yes"
except Exception:
return False
+
+ @staticmethod
+ def _safe_int(value: Any) -> int:
+ try:
+ if value is None:
+ return 0
+ return int(value)
+ except Exception:
+ return 0
+
+ def _coerce_student(self, value: Any) -> SelectedStudentNotificationInfo | None:
+ if isinstance(value, dict):
+ student_id = self._safe_int(value.get("student_id", value.get("id", 0)))
+ student_name = str(
+ value.get("student_name", value.get("name", "")) or ""
+ )
+ display_text = str(
+ value.get(
+ "display_text", value.get("display", value.get("text", ""))
+ )
+ or student_name
+ )
+ exists = bool(value.get("exists", value.get("exist", True)))
+ group_name = str(value.get("group_name", value.get("group", "")) or "")
+ lottery_name = str(
+ value.get(
+ "lottery_name",
+ value.get(
+ "lottery",
+ value.get("prize_name", value.get("prize", "")),
+ ),
+ )
+ or ""
+ )
+ return {
+ "student_id": student_id,
+ "student_name": student_name,
+ "display_text": display_text,
+ "exists": exists,
+ "group_name": group_name,
+ "lottery_name": lottery_name,
+ }
+
+ if isinstance(value, (list, tuple)) and len(value) >= 3:
+ student_name = str(value[1] or "")
+ return {
+ "student_id": self._safe_int(value[0]),
+ "student_name": student_name,
+ "display_text": student_name,
+ "exists": bool(value[2]),
+ "group_name": "",
+ "lottery_name": "",
+ }
+
+ return None
else:
class CSharpIPCHandler:
diff --git a/app/common/lottery/lottery_manager.py b/app/common/lottery/lottery_manager.py
index 5c37005db..96b440463 100644
--- a/app/common/lottery/lottery_manager.py
+++ b/app/common/lottery/lottery_manager.py
@@ -376,7 +376,16 @@ def get_random_items(self, count):
selected_prizes = [system_random.choice(self.prizes) for _ in range(count)]
if not self.enable_student_assignment or not self.current_class_name:
- return selected_prizes
+ prizes_with_meta = []
+ for prize in selected_prizes:
+ prize_copy = dict(prize)
+ prize_name = prize_copy.get("name", "")
+ prize_copy["ipc_lottery_name"] = str(prize_name or "")
+ prize_copy["ipc_group_name"] = ""
+ prize_copy["ipc_student_name"] = ""
+ prize_copy["ipc_display_text"] = str(prize_name or "")
+ prizes_with_meta.append(prize_copy)
+ return prizes_with_meta
candidates = RollCallUtils._get_filtered_candidates(
self.current_class_name,
@@ -400,6 +409,7 @@ def get_random_items(self, count):
for prize in selected_prizes:
prize_copy = dict(prize)
prize_name = prize_copy.get("name", "")
+ prize_copy["ipc_lottery_name"] = str(prize_name or "")
group_name = ""
student_name = ""
@@ -422,10 +432,13 @@ def get_random_items(self, count):
else:
student_name = system_random.choice(candidates).get("name", "")
+ prize_copy["ipc_group_name"] = str(group_name or "")
+ prize_copy["ipc_student_name"] = str(student_name or "")
if group_name or student_name:
prize_copy["name"] = self._format_prize_student_text(
prize_name, group_name, student_name, show_random
)
+ prize_copy["ipc_display_text"] = str(prize_copy.get("name", "") or "")
prizes_with_students.append(prize_copy)
@@ -502,6 +515,7 @@ def draw_final_items(self, count):
except Exception:
show_random = 0
+ include_group = show_random in (0, 1, 2, 5, 6, 7, 8, 9)
from app.common.data.list import get_group_members
for idx, prize in enumerate(selected_prizes_dict):
@@ -522,6 +536,9 @@ def draw_final_items(self, count):
)
display_name = prize_name
+ ipc_group_name = ""
+ ipc_student_name = ""
+ ipc_display_text = str(prize_name or "")
if student_tuple and len(student_tuple) >= 2 and student_tuple[1]:
group_name = ""
student_name = ""
@@ -545,18 +562,29 @@ def draw_final_items(self, count):
else:
student_name = str(student_tuple[1])
+ ipc_group_name = str(group_name or "")
+ ipc_student_name = str(student_name or "")
display_name = self._format_prize_student_text(
prize_name, group_name, student_name, show_random
)
+ ipc_display_text = str(display_name or "")
selected_prizes_with_students.append((prize_id, display_name, prize_exist))
prize_copy = dict(prize)
+ prize_copy["ipc_lottery_name"] = str(prize_name or "")
+ prize_copy["ipc_group_name"] = ipc_group_name if include_group else ""
+ prize_copy["ipc_student_name"] = ipc_student_name
+ prize_copy["ipc_display_text"] = ipc_display_text
if isinstance(student_dict, dict):
prize_copy["student"] = student_dict
prize_copy["student_id"] = student_dict.get("id", "")
prize_copy["student_name"] = student_dict.get("name", "")
prize_copy["student_exist"] = student_dict.get("exist", True)
+ if include_group and not prize_copy["ipc_group_name"]:
+ prize_copy["ipc_group_name"] = str(
+ student_dict.get("group", "") or ""
+ )
updated_prizes_dict.append(prize_copy)
result["selected_prizes"] = selected_prizes_with_students
@@ -937,11 +965,65 @@ def stop_animation(widget):
settings = widget.manager.get_notification_settings(refresh=True)
if settings is not None:
+ settings_for_notify = (
+ dict(settings) if isinstance(settings, dict) else settings
+ )
+ show_random = readme_settings_async("lottery_settings", "show_random")
+ try:
+ show_random = int(show_random or 0)
+ except Exception:
+ show_random = 0
+ include_group = show_random in (0, 1, 2, 5, 6, 7, 8, 9)
+ ipc_selected_students = []
+ for prize in widget.final_selected_students_dict or []:
+ if not isinstance(prize, dict):
+ continue
+ student = prize.get("student")
+ if not isinstance(student, dict):
+ student = None
+ try:
+ student_id = int(prize.get("student_id", 0) or 0)
+ except Exception:
+ student_id = 0
+ if not student_id and student is not None:
+ try:
+ student_id = int(student.get("id", 0) or 0)
+ except Exception:
+ student_id = 0
+ student_name = str(
+ prize.get("ipc_student_name", "")
+ or prize.get("student_name", "")
+ or ""
+ )
+ display_text = str(
+ prize.get("ipc_display_text", "") or prize.get("name", "") or ""
+ )
+ group_name = str(prize.get("ipc_group_name", "") or "")
+ if not include_group:
+ group_name = ""
+ lottery_name = str(
+ prize.get("ipc_lottery_name", "") or prize.get("name", "") or ""
+ )
+ exists = bool(prize.get("student_exist", prize.get("exist", True)))
+ ipc_selected_students.append(
+ {
+ "student_id": student_id,
+ "student_name": student_name,
+ "display_text": display_text,
+ "exists": exists,
+ "group_name": group_name,
+ "lottery_name": lottery_name,
+ }
+ )
+
+ if ipc_selected_students and isinstance(settings_for_notify, dict):
+ settings_for_notify["ipc_selected_students"] = ipc_selected_students
+
ResultDisplayUtils.show_notification_if_enabled(
widget.final_pool_name,
widget.final_selected_students,
actual_draw_count,
- settings,
+ settings_for_notify,
settings_group="lottery_notification_settings",
)
@@ -991,6 +1073,24 @@ def draw_random(widget):
display_count = min(display_count, remaining_count)
prizes = widget.manager.get_random_items(display_count)
+ ipc_selected_students = []
+ for p in prizes or []:
+ if not isinstance(p, dict):
+ continue
+ ipc_selected_students.append(
+ {
+ "student_id": 0,
+ "student_name": str(p.get("ipc_student_name", "") or ""),
+ "display_text": str(
+ p.get("ipc_display_text", p.get("name", "")) or ""
+ ),
+ "exists": bool(p.get("exist", True)),
+ "group_name": str(p.get("ipc_group_name", "") or ""),
+ "lottery_name": str(
+ p.get("ipc_lottery_name", p.get("name", "")) or ""
+ ),
+ }
+ )
selected_prizes = [(p["id"], p["name"], p.get("exist", True)) for p in prizes]
display_result_animated(
@@ -998,6 +1098,7 @@ def draw_random(widget):
selected_prizes,
widget.manager.current_pool_name,
draw_count=display_count,
+ ipc_selected_students=ipc_selected_students,
)
@@ -1034,7 +1135,9 @@ def display_result(widget, selected_students, pool_name, draw_count=None):
ResultDisplayUtils.display_results_in_grid(widget.result_grid, student_labels)
-def display_result_animated(widget, selected_students, pool_name, draw_count=None):
+def display_result_animated(
+ widget, selected_students, pool_name, draw_count=None, ipc_selected_students=None
+):
render_settings = widget.manager.get_render_settings(refresh=False)
if draw_count is None:
draw_count = widget.current_count
@@ -1069,11 +1172,18 @@ def display_result_animated(widget, selected_students, pool_name, draw_count=Non
settings = widget.manager.get_notification_settings(refresh=False)
if settings is not None:
+ settings_for_notify = dict(settings) if isinstance(settings, dict) else settings
+ if (
+ ipc_selected_students
+ and isinstance(settings_for_notify, dict)
+ and isinstance(ipc_selected_students, list)
+ ):
+ settings_for_notify["ipc_selected_students"] = ipc_selected_students
ResultDisplayUtils.show_notification_if_enabled(
pool_name,
selected_students,
draw_count,
- settings,
+ settings_for_notify,
settings_group="lottery_notification_settings",
is_animating=True,
)
diff --git a/app/common/notification/notification_service.py b/app/common/notification/notification_service.py
index 9ac29a510..045cd8ca4 100644
--- a/app/common/notification/notification_service.py
+++ b/app/common/notification/notification_service.py
@@ -962,15 +962,17 @@ def send_to_classisland(
"""
try:
+ import re
def _normalize_text(value):
text = str(value or "")
text = text.replace("\r\n", "\n").replace("\r", "\n")
+ text = text.strip()
if "\n" in text:
- text = " - ".join(
- [part.strip() for part in text.split("\n") if part.strip()]
- )
- return text
+ text = text.replace("\n", " - ")
+ text = re.sub(r"\s*-\s*", " - ", text)
+ text = re.sub(r"\s{2,}", " ", text)
+ return text.strip()
show_random = 0
if settings:
@@ -979,6 +981,10 @@ def _normalize_text(value):
except Exception:
show_random = 0
+ ipc_students = None
+ if isinstance(settings, dict):
+ ipc_students = settings.get("ipc_selected_students")
+
group_mode = False
for item in selected_students or []:
if (
@@ -989,28 +995,62 @@ def _normalize_text(value):
group_mode = True
break
- if group_mode:
- from app.common.data.list import get_group_members
-
+ if isinstance(ipc_students, list) and ipc_students:
+ selected_students_for_ipc = []
+ for item in ipc_students:
+ if not isinstance(item, dict):
+ continue
+ try:
+ student_id = int(item.get("student_id", 0) or 0)
+ except Exception:
+ student_id = 0
+ student_name = _normalize_text(item.get("student_name", ""))
+ display_text = (
+ _normalize_text(item.get("display_text", "")) or student_name
+ )
+ group_name_raw = _normalize_text(item.get("group_name", ""))
+ lottery_name = _normalize_text(item.get("lottery_name", ""))
+ is_lottery = bool(
+ settings_group and "lottery" in str(settings_group)
+ ) or bool(lottery_name)
+ group_name = group_name_raw if (group_mode or is_lottery) else ""
+ if group_mode and (not is_lottery) and show_random == 0:
+ group_name = ""
+ selected_students_for_ipc.append(
+ {
+ "student_id": student_id,
+ "student_name": student_name,
+ "display_text": display_text,
+ "exists": bool(item.get("exists", True)),
+ "group_name": group_name,
+ "lottery_name": lottery_name,
+ }
+ )
+ elif group_mode:
selected_students_for_ipc = []
for item in selected_students or []:
if not isinstance(item, (list, tuple)) or len(item) < 3:
continue
- group_name = _normalize_text(item[1])
+ group_display_text = _normalize_text(item[1])
exist = bool(item[2])
- if show_random in (1, 2):
- group_members = get_group_members(class_name, group_name)
- if group_members:
- selected_member = system_random.choice(group_members)
- selected_name = _normalize_text(
- (selected_member or {}).get("name", "")
- )
- if selected_name:
- group_name = f"{group_name} - {selected_name}"
+ group_name = ""
+ student_name = group_display_text
+ if show_random > 0 and " - " in group_display_text:
+ parts = group_display_text.split(" - ", 1)
+ if len(parts) == 2 and parts[0].strip() and parts[1].strip():
+ group_name = parts[0].strip()
+ student_name = parts[1].strip()
selected_students_for_ipc.append(
- (0, _normalize_text(group_name), exist)
+ {
+ "student_id": 0,
+ "student_name": student_name,
+ "display_text": group_display_text,
+ "exists": exist,
+ "group_name": group_name,
+ "lottery_name": "",
+ }
)
else:
selected_students_for_ipc = []
@@ -1020,8 +1060,18 @@ def _normalize_text(value):
student_id = item[0]
if student_id is None:
student_id = 0
+ normalized_name = _normalize_text(item[1])
+ exist = bool(item[2])
+
selected_students_for_ipc.append(
- (student_id, _normalize_text(item[1]), bool(item[2]))
+ {
+ "student_id": int(student_id or 0),
+ "student_name": normalized_name,
+ "display_text": normalized_name,
+ "exists": exist,
+ "group_name": "",
+ "lottery_name": "",
+ }
)
cs_ipc = CSharpIPCHandler.instance()
diff --git a/app/common/roll_call/roll_call_manager.py b/app/common/roll_call/roll_call_manager.py
index 3693da006..e3734e255 100644
--- a/app/common/roll_call/roll_call_manager.py
+++ b/app/common/roll_call/roll_call_manager.py
@@ -577,6 +577,7 @@ def stop_animation(widget):
result.get("class_name") or widget.manager.current_class_name
)
widget.final_selected_students_dict = result.get("selected_students_dict") or []
+ widget.final_ipc_selected_students = result.get("ipc_selected_students") or []
widget.final_group_filter = (
result.get("group_filter") or widget.range_combobox.currentText()
)
@@ -616,6 +617,9 @@ def stop_animation(widget):
selected_students=widget.final_selected_students,
draw_count=actual_draw_count,
settings_group="roll_call_notification_settings",
+ ipc_selected_students=getattr(
+ widget, "final_ipc_selected_students", None
+ ),
)
play_voice_result(widget)
@@ -717,6 +721,11 @@ def display_result_animated(widget, selected_students, class_name, draw_count=No
if draw_count is None:
draw_count = widget.current_count
+ if group_index == 1:
+ selected_students = RollCallUtils.render_group_display_students(
+ class_name, selected_students, display_dict.get("show_random", 0)
+ )
+
student_labels = ResultDisplayUtils.create_student_label(
class_name=class_name,
selected_students=selected_students,
diff --git a/app/common/roll_call/roll_call_utils.py b/app/common/roll_call/roll_call_utils.py
index 38f2312f7..c01a68608 100644
--- a/app/common/roll_call/roll_call_utils.py
+++ b/app/common/roll_call/roll_call_utils.py
@@ -291,10 +291,17 @@ def draw_random_students(
selected_groups = RollCallUtils.draw_random_groups(
students_dict_list, current_count, draw_type
)
+ show_random = readme_settings_async("roll_call_settings", "show_random")
+ selected_groups, ipc_selected_students = (
+ RollCallUtils.render_group_display_students_and_ipc(
+ class_name, selected_groups, show_random
+ )
+ )
return {
"selected_students": selected_groups,
"class_name": class_name,
"selected_students_dict": [],
+ "ipc_selected_students": ipc_selected_students,
"group_filter": group_filter,
"gender_filter": gender_filter,
}
@@ -405,6 +412,101 @@ def draw_random_groups(students_dict_list, current_count, draw_type):
return selected_groups
+ @staticmethod
+ def render_group_display_students(class_name, selected_students, show_random):
+ rendered, _ = RollCallUtils.render_group_display_students_and_ipc(
+ class_name, selected_students, show_random
+ )
+ return rendered
+
+ @staticmethod
+ def render_group_display_students_and_ipc(
+ class_name, selected_students, show_random
+ ):
+ try:
+ show_random = int(show_random or 0)
+ except Exception:
+ show_random = 0
+
+ try:
+ from app.common.data.list import get_group_members
+ except Exception:
+ get_group_members = None
+
+ rendered = []
+ ipc_selected_students = []
+ for item in selected_students or []:
+ if not isinstance(item, (list, tuple)) or len(item) < 3:
+ continue
+
+ student_id = item[0]
+ name = str(item[1] or "")
+ exist = bool(item[2])
+
+ if student_id is not None:
+ rendered.append((student_id, name, exist))
+ ipc_selected_students.append(
+ {
+ "student_id": int(student_id or 0),
+ "student_name": name,
+ "display_text": name,
+ "exists": exist,
+ "group_name": "",
+ "lottery_name": "",
+ }
+ )
+ continue
+
+ group_name = name
+ selected_name = ""
+ if (
+ show_random > 0
+ and get_group_members is not None
+ and class_name
+ and group_name
+ ):
+ try:
+ group_members = get_group_members(class_name, group_name) or []
+ except Exception:
+ group_members = []
+
+ if group_members:
+ try:
+ selected_member = system_random.choice(group_members)
+ except Exception:
+ selected_member = None
+ selected_name = str(
+ (selected_member or {}).get("name", "") or ""
+ ).strip()
+ if selected_name:
+ display_text = f"{group_name} - {selected_name}"
+ rendered.append((None, display_text, exist))
+ ipc_selected_students.append(
+ {
+ "student_id": 0,
+ "student_name": selected_name,
+ "display_text": display_text,
+ "exists": exist,
+ "group_name": group_name,
+ "lottery_name": "",
+ }
+ )
+ continue
+
+ rendered.append((None, group_name, exist))
+ ipc_selected_students.append(
+ {
+ "student_id": 0,
+ "student_name": group_name,
+ "display_text": group_name,
+ "exists": exist,
+ "group_name": group_name if show_random > 0 else "",
+ "lottery_name": "",
+ }
+ )
+
+ return rendered, ipc_selected_students
+
@staticmethod
def prepare_notification_settings():
"""
@@ -736,6 +838,7 @@ def show_notification_if_enabled(
draw_count,
settings_group="roll_call_notification_settings",
display_settings=None,
+ ipc_selected_students=None,
is_animating=False,
):
"""
@@ -759,6 +862,12 @@ def show_notification_if_enabled(
settings = RollCallUtils.prepare_notification_settings_by_group(
settings_group, display_settings
)
+ if (
+ ipc_selected_students
+ and isinstance(ipc_selected_students, list)
+ and isinstance(settings, dict)
+ ):
+ settings["ipc_selected_students"] = ipc_selected_students
ResultDisplayUtils.show_notification_if_enabled(
class_name,
selected_students,
diff --git a/app/view/guide/pages.py b/app/view/guide/pages.py
index 5e2862b29..c5db1be0e 100644
--- a/app/view/guide/pages.py
+++ b/app/view/guide/pages.py
@@ -1066,7 +1066,19 @@ def _test_classisland(self):
try:
handler = CSharpIPCHandler.instance()
if handler.is_connected:
- handler.send_notification("SecRandom Test", [(0, "Test Student", True)])
+ handler.send_notification(
+ "SecRandom Test",
+ [
+ {
+ "student_id": 0,
+ "student_name": "Test Student",
+ "display_text": "Test Student",
+ "exists": True,
+ "group_name": "",
+ "lottery_name": "",
+ }
+ ],
+ )
self.statusLabel.setText(
get_any_position_value_async("guide", "test_page", "success")
)
diff --git a/app/view/main/quick_draw_animation.py b/app/view/main/quick_draw_animation.py
index 2f52ac042..e95314793 100644
--- a/app/view/main/quick_draw_animation.py
+++ b/app/view/main/quick_draw_animation.py
@@ -39,6 +39,7 @@ def __init__(self, roll_call_widget):
self.final_selected_students = None
self.final_class_name = None
self.final_selected_students_dict = None
+ self.final_ipc_selected_students = None
self.final_group_filter = None
self.final_gender_filter = None
@@ -127,6 +128,7 @@ def _set_final_result(self, result):
self.final_selected_students = result["selected_students"]
self.final_class_name = result["class_name"]
self.final_selected_students_dict = result["selected_students_dict"]
+ self.final_ipc_selected_students = result.get("ipc_selected_students")
self.final_group_filter = result["group_filter"]
self.final_gender_filter = result["gender_filter"]
@@ -136,6 +138,9 @@ def _sync_final_result_to_widget(self):
self.roll_call_widget.final_selected_students_dict = (
self.final_selected_students_dict
)
+ self.roll_call_widget.final_ipc_selected_students = (
+ self.final_ipc_selected_students
+ )
self.roll_call_widget.final_group_filter = self.final_group_filter
self.roll_call_widget.final_gender_filter = self.final_gender_filter
@@ -281,6 +286,7 @@ def stop_animation(self):
draw_count=draw_count,
settings_group="quick_draw_notification_settings",
display_settings=self.quick_draw_settings,
+ ipc_selected_students=self.final_ipc_selected_students,
is_animating=False,
)
@@ -412,7 +418,9 @@ def display_final_result(self, quick_draw_settings):
class_name=self.final_class_name,
selected_students=self.final_selected_students,
draw_count=draw_count,
- group_index=0,
+ group_index=getattr(
+ self.roll_call_widget.range_combobox, "currentIndex", lambda: 0
+ )(),
settings_group="quick_draw_settings",
display_settings=quick_draw_settings,
)
@@ -437,6 +445,7 @@ def display_final_result(self, quick_draw_settings):
draw_count=draw_count,
settings_group="quick_draw_notification_settings",
display_settings=quick_draw_settings,
+ ipc_selected_students=self.final_ipc_selected_students,
)
except Exception as e:
@@ -478,6 +487,7 @@ def _update_floating_notification(self):
draw_count=draw_count,
settings_group="quick_draw_notification_settings",
display_settings=self.quick_draw_settings,
+ ipc_selected_students=self.final_ipc_selected_students,
is_animating=True,
)
@@ -504,7 +514,9 @@ def display_result_animated(
display_format=display_settings["display_format"],
display_style=0,
show_student_image=display_settings["student_image"],
- group_index=0,
+ group_index=getattr(
+ self.roll_call_widget.range_combobox, "currentIndex", lambda: 0
+ )(),
show_random=display_settings["show_random"],
settings_group="quick_draw_settings",
)
diff --git a/data/dlls/SecRandom4Ci.Interface.dll b/data/dlls/SecRandom4Ci.Interface.dll
index 48e8faf90..95bd427f9 100644
Binary files a/data/dlls/SecRandom4Ci.Interface.dll and b/data/dlls/SecRandom4Ci.Interface.dll differ
diff --git a/data/dlls/SecRandom4Ci.Interface.pdb b/data/dlls/SecRandom4Ci.Interface.pdb
index d74340c5b..36841eaf6 100644
Binary files a/data/dlls/SecRandom4Ci.Interface.pdb and b/data/dlls/SecRandom4Ci.Interface.pdb differ
diff --git a/data/dlls/dotnet.runtimeconfig.json b/data/dlls/dotnet.runtimeconfig.json
index 77961a6fb..dce8e146d 100644
--- a/data/dlls/dotnet.runtimeconfig.json
+++ b/data/dlls/dotnet.runtimeconfig.json
@@ -19,4 +19,4 @@
"CSWINRT_USE_WINDOWS_UI_XAML_PROJECTIONS": false
}
}
-}
\ No newline at end of file
+}
diff --git a/vendors/pythonnet-stub-generator/LICENCE.md b/vendors/pythonnet-stub-generator/LICENCE.md
index cc83c82d4..96d355a7c 100644
--- a/vendors/pythonnet-stub-generator/LICENCE.md
+++ b/vendors/pythonnet-stub-generator/LICENCE.md
@@ -19,4 +19,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
\ No newline at end of file
+SOFTWARE.
diff --git a/vendors/pythonnet-stub-generator/csharp/.gitignore b/vendors/pythonnet-stub-generator/csharp/.gitignore
index 062627280..a437a6530 100644
--- a/vendors/pythonnet-stub-generator/csharp/.gitignore
+++ b/vendors/pythonnet-stub-generator/csharp/.gitignore
@@ -34,4 +34,4 @@ msbuild.err
msbuild.wrn
# Visual Studio 2015
-.vs/
\ No newline at end of file
+.vs/
diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator.sln.DotSettings b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator.sln.DotSettings
index 0e3eaee1e..a61075532 100644
--- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator.sln.DotSettings
+++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator.sln.DotSettings
@@ -1,4 +1,4 @@
True
True
- True
\ No newline at end of file
+ True
diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/ClassScope.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/ClassScope.cs
index d2a7517c6..22629be52 100644
--- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/ClassScope.cs
+++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/ClassScope.cs
@@ -54,4 +54,4 @@ public static IEnumerable AccessibleGenerics
}
}
-}
\ No newline at end of file
+}
diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/MethodComparer.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/MethodComparer.cs
index 01d69f43a..9e478d517 100644
--- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/MethodComparer.cs
+++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/MethodComparer.cs
@@ -16,7 +16,7 @@ public int Compare(MethodInfo a, MethodInfo b)
var aName = a.NonGenericName();
var bName = b.NonGenericName();
-
+
var nameCompare = string.Compare(aName, bName, StringComparison.InvariantCulture);
if (nameCompare != 0) return nameCompare;
@@ -84,4 +84,4 @@ float GetDepth(Type t, bool addGenerics)
return string.Compare(aParamString, bParamString, StringComparison.Ordinal);
}
}
-}
\ No newline at end of file
+}
diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/PythonStubTask.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/PythonStubTask.cs
index a3460e002..b696db7df 100644
--- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/PythonStubTask.cs
+++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/PythonStubTask.cs
@@ -38,4 +38,4 @@ public override bool Execute()
}
}
-}
\ No newline at end of file
+}
diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StringBuilderExtensions.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StringBuilderExtensions.cs
index 4cf52c8c0..80ad8d0e0 100644
--- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StringBuilderExtensions.cs
+++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StringBuilderExtensions.cs
@@ -4,7 +4,7 @@
namespace PythonNetStubGenerator
{
-
+
public static class StringBuilderExtensions
{
public static StringBuilder Indent(this StringBuilder sb)
@@ -22,5 +22,5 @@ public class IndentScope: IDisposable
public IndentScope() => IndentLevel++;
public void Dispose() => IndentLevel--;
}
-
-}
\ No newline at end of file
+
+}
diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubBuilder.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubBuilder.cs
index b126e49c1..ff40ca735 100644
--- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubBuilder.cs
+++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubBuilder.cs
@@ -9,7 +9,7 @@ namespace PythonNetStubGenerator
public static class StubBuilder
{
private static HashSet SearchPaths { get; } = new HashSet();
-
+
public static DirectoryInfo BuildAssemblyStubs(DirectoryInfo destPath, FileInfo[] targetAssemblyPaths, DirectoryInfo[] searchPaths = null)
{
// prepare resolver
@@ -21,7 +21,7 @@ public static DirectoryInfo BuildAssemblyStubs(DirectoryInfo destPath, FileInfo[
{
var assemblyToStub = Assembly.LoadFrom(targetAssemblyPath.FullName);
SearchPaths.Add(targetAssemblyPath.Directory);
-
+
if (searchPaths != null)
foreach (var path in SearchPaths)
SearchPaths.Add(path);
diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubWriter.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubWriter.cs
index c6471e983..5832cf79b 100644
--- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubWriter.cs
+++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubWriter.cs
@@ -728,7 +728,7 @@ private static bool IsGenericMethodCallable(MethodInfo method)
// be used more than once in Method signatures. In CLR, this is not the case, since the
// Type of a single parameter can sometimes be used to infer the generic parameter of the method,
// which can point to a different implementation/specialization.
- // For now, I will assume that Python.NET uses some runtime information in the object reference to
+ // For now, I will assume that Python.NET uses some runtime information in the object reference to
// dispatch the correct method. And we can use the type bound to type the method parameter.
// Todo: I've skipped this complication. For now we'll force the user to pass in the generic parameters
@@ -898,7 +898,7 @@ private static void WriteEnum(StringBuilder sb, Type stubType)
var underlyingType = stubType.GetEnumUnderlyingType().ToPythonType();
sb.Indent().AppendLine($"class {stubType.Name}(typing.SupportsInt):");
using var _ = new IndentScope();
-
+
sb.Indent().AppendLine("@typing.overload");
sb.Indent().AppendLine($"def __init__(self, value : {underlyingType}) -> None: ...");
sb.Indent().AppendLine("@typing.overload");
diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/SymbolScope.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/SymbolScope.cs
index 3325b993f..412e44621 100644
--- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/SymbolScope.cs
+++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/SymbolScope.cs
@@ -22,7 +22,7 @@ public void Dispose()
Scopes.Remove(this);
}
- public bool HasConflict(string cleanName, string typeNamespace) =>
+ public bool HasConflict(string cleanName, string typeNamespace) =>
typeNamespace != Namespace && ReservedSymbols.Contains(cleanName);
}
-}
\ No newline at end of file
+}
diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubTool/Program.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubTool/Program.cs
index e4aa889dd..98133748f 100644
--- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubTool/Program.cs
+++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubTool/Program.cs
@@ -34,7 +34,7 @@ static int Main(
infos.Add(assemblyPath);
}
-
+
Console.WriteLine($"building stubs...");
try