ok-script 2.0.23b1__tar.gz → 3.0.0b2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/PKG-INFO +11 -1
  2. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/README.md +10 -0
  3. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/__init__.py +40 -5
  4. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/events.py +10 -0
  5. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/MainWindow.py +47 -12
  6. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/common/config.py +3 -3
  7. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/buttons.py +3 -2
  8. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/icons.py +4 -3
  9. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/qss.py +7 -1
  10. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/settings/settings_page.py +0 -5
  11. ok_script-3.0.0b2/ok/ui/qt/shell/lazy_page.py +32 -0
  12. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/shell/run_bar.py +18 -2
  13. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/tasks_page.py +24 -8
  14. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/util/app.py +22 -7
  15. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok_script.egg-info/PKG-INFO +11 -1
  16. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok_script.egg-info/SOURCES.txt +2 -0
  17. ok_script-3.0.0b2/tests/test_lazy_page.py +47 -0
  18. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_main_window_system_theme.py +1 -1
  19. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_shell.py +16 -3
  20. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/develop/SKILL.md +0 -0
  21. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/develop/agents/openai.yaml +0 -0
  22. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/develop/references/windows-input.md +0 -0
  23. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/generate-templates/SKILL.md +0 -0
  24. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/reload-tasks/SKILL.md +0 -0
  25. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/reload-tasks/agents/openai.yaml +0 -0
  26. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/setup-env/SKILL.md +0 -0
  27. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/setup-env/agents/openai.yaml +0 -0
  28. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/setup-env/assets/ok-script-develop/SKILL.md +0 -0
  29. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/setup-project/SKILL.md +0 -0
  30. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/setup-project/agents/openai.yaml +0 -0
  31. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/use_venv/SKILL.md +0 -0
  32. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/write-test/SKILL.md +0 -0
  33. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/.agents/skills/write-test/agents/openai.yaml +0 -0
  34. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/LICENSE.txt +0 -0
  35. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/MANIFEST.in +0 -0
  36. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/diagnostics/qq_trace.py +0 -0
  37. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/docs/agent-setup.md +0 -0
  38. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/docs/feature-crops.md +0 -0
  39. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/docs/mcp.md +0 -0
  40. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/examples/mcp_observe.py +0 -0
  41. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/__main__.py +0 -0
  42. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/alas/__init__.py +0 -0
  43. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/alas/emulator_base.py +0 -0
  44. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/alas/emulator_windows.py +0 -0
  45. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/alas/platform_windows.py +0 -0
  46. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/alas/utils.py +0 -0
  47. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/assets/default-icon.png +0 -0
  48. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/__init__.py +0 -0
  49. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/adb/__init__.py +0 -0
  50. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/adb/deep.py +0 -0
  51. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/adb/minitouch.py +0 -0
  52. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/adb/nemu_ipc.py +0 -0
  53. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/adb/nemu_utils.py +0 -0
  54. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/adb/pool.py +0 -0
  55. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/adb/timer.py +0 -0
  56. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/adb/util.py +0 -0
  57. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/windows/__init__.py +0 -0
  58. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/windows/d3d11.py +0 -0
  59. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/capture/windows/dump.py +0 -0
  60. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/cli.py +0 -0
  61. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/__init__.py +0 -0
  62. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/capture_labels.py +0 -0
  63. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/code_runner.py +0 -0
  64. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/config_schema.py +0 -0
  65. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/downloads.py +0 -0
  66. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/icons.py +0 -0
  67. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/mcp_runner.py +0 -0
  68. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/mcp_server.py +0 -0
  69. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/notifications.py +0 -0
  70. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/plugin_staging.py +0 -0
  71. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/plugins.py +0 -0
  72. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/screenshot.py +0 -0
  73. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/script_editing.py +0 -0
  74. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/script_packager.py +0 -0
  75. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/script_templates.py +0 -0
  76. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/skills.py +0 -0
  77. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/start_controller.py +0 -0
  78. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/task_manager.py +0 -0
  79. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/template_store.py +0 -0
  80. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/translation.py +0 -0
  81. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/core/ui_config.py +0 -0
  82. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/DeviceManager.py +0 -0
  83. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/__init__.py +0 -0
  84. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture.py +0 -0
  85. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/__init__.py +0 -0
  86. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/adb.py +0 -0
  87. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/base.py +0 -0
  88. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/bitblt.py +0 -0
  89. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/bitblt_utils.py +0 -0
  90. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/browser.py +0 -0
  91. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/desktop_duplication.py +0 -0
  92. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/hwnd_window.py +0 -0
  93. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/image.py +0 -0
  94. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/nemu_ipc.py +0 -0
  95. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/types.py +0 -0
  96. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/update.py +0 -0
  97. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/windows_graphics.py +0 -0
  98. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/capture_methods/windows_graphics_hdr.py +0 -0
  99. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction.py +0 -0
  100. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/__init__.py +0 -0
  101. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/adb.py +0 -0
  102. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/base.py +0 -0
  103. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/browser.py +0 -0
  104. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/do_nothing.py +0 -0
  105. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/foreground_post_message.py +0 -0
  106. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/genshin.py +0 -0
  107. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/keys.py +0 -0
  108. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/post_message.py +0 -0
  109. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/pydirect.py +0 -0
  110. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/pynput.py +0 -0
  111. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/interaction_methods/swipe.py +0 -0
  112. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/device/intercation.py +0 -0
  113. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/feature/Box.py +0 -0
  114. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/feature/Feature.py +0 -0
  115. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/feature/FeatureSet.py +0 -0
  116. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/feature/__init__.py +0 -0
  117. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/gui/__init__.py +0 -0
  118. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/gui/util/pyappify_startup.py +0 -0
  119. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/notification/__init__.py +0 -0
  120. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/notification/manager.py +0 -0
  121. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/notification/messenger_images.py +0 -0
  122. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/notification/pipeline.py +0 -0
  123. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/notification/ppocr.py +0 -0
  124. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/notification/providers.py +0 -0
  125. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/notification/system.py +0 -0
  126. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/notification/windows_messenger.py +0 -0
  127. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ocr/__init__.py +0 -0
  128. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ocr/download_paddle_model.py +0 -0
  129. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
  130. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
  131. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
  132. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
  133. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
  134. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
  135. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
  136. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
  137. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
  138. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Media/__init__.py +0 -0
  139. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
  140. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Security/__init__.py +0 -0
  141. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
  142. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/Storage/__init__.py +0 -0
  143. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/UI/ViewManagement/__init__.py +0 -0
  144. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/UI/__init__.py +0 -0
  145. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/Windows/__init__.py +0 -0
  146. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/__init__.py +0 -0
  147. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/delegate.py +0 -0
  148. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/export.py +0 -0
  149. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/idldsl.py +0 -0
  150. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/inspectable.py +0 -0
  151. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/roapi.py +0 -0
  152. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/types.py +0 -0
  153. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/rotypes/winstring.py +0 -0
  154. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/task/DiagnosisTask.py +0 -0
  155. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/task/TaskExecutor.py +0 -0
  156. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/task/__init__.py +0 -0
  157. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/task/exceptions.py +0 -0
  158. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/task/task.py +0 -0
  159. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/test/OKTestRunner.py +0 -0
  160. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/test/RunTests.py +0 -0
  161. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/test/TaskTestCase.py +0 -0
  162. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/test/__init__.py +0 -0
  163. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/third_party/__init__.py +0 -0
  164. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/third_party/paperclip.py +0 -0
  165. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/__init__.py +0 -0
  166. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/overlay/__init__.py +0 -0
  167. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/overlay/win32_gdi.py +0 -0
  168. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/Communicate.py +0 -0
  169. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/MessageWindow.py +0 -0
  170. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/StartController.py +0 -0
  171. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/__init__.py +0 -0
  172. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/about/AboutTab.py +0 -0
  173. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/about/UpdateCard.py +0 -0
  174. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/about/__init__.py +0 -0
  175. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/common/__init__.py +0 -0
  176. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/debug/OverlayWidget.py +0 -0
  177. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/debug/Screenshot.py +0 -0
  178. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/debug/__init__.py +0 -0
  179. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/debug/diagnosis_page.py +0 -0
  180. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/events.py +0 -0
  181. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/GettextTranslator.py +0 -0
  182. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/__init__.py +0 -0
  183. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/en_US.qm +0 -0
  184. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/en_US.ts +0 -0
  185. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/es_ES.qm +0 -0
  186. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/es_ES.ts +0 -0
  187. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/ja_JP.qm +0 -0
  188. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/ja_JP.ts +0 -0
  189. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/ko_KR.qm +0 -0
  190. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/ko_KR.ts +0 -0
  191. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/path.py +0 -0
  192. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/update.py +0 -0
  193. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/zh_CN.qm +0 -0
  194. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/zh_CN.ts +0 -0
  195. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/zh_TW.qm +0 -0
  196. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/i18n/zh_TW.ts +0 -0
  197. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/__init__.py +0 -0
  198. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/cards.py +0 -0
  199. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/dialogs.py +0 -0
  200. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/feedback.py +0 -0
  201. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/gallery.py +0 -0
  202. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/inputs.py +0 -0
  203. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/labels.py +0 -0
  204. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/layout.py +0 -0
  205. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/navigation.py +0 -0
  206. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/options.py +0 -0
  207. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/popover.py +0 -0
  208. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/switch.py +0 -0
  209. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/tabs.py +0 -0
  210. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/theme.py +0 -0
  211. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/kit/window.py +0 -0
  212. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/overlay/OverlayWindow.py +0 -0
  213. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/overlay/__init__.py +0 -0
  214. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/plugins/PluginTab.py +0 -0
  215. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/plugins/__init__.py +0 -0
  216. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/plugins/imported_tabs.py +0 -0
  217. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/qt.qrc +0 -0
  218. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/resources.py +0 -0
  219. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/settings/GlobalConfigTab.py +0 -0
  220. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/settings/__init__.py +0 -0
  221. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/settings/config_section.py +0 -0
  222. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/shell/__init__.py +0 -0
  223. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/shell/connection.py +0 -0
  224. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/shell/diagnostics.py +0 -0
  225. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/shell/log_page.py +0 -0
  226. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/shell/nav_icons.py +0 -0
  227. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/start/__init__.py +0 -0
  228. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/EditTaskTab.py +0 -0
  229. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/MarkUpWindow.py +0 -0
  230. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/ModifyListDialog.py +0 -0
  231. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/PythonHighlighter.py +0 -0
  232. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/RecordScript.py +0 -0
  233. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/ScheduleTaskTab.py +0 -0
  234. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/ScriptPackager.py +0 -0
  235. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/TaskManger.py +0 -0
  236. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/TaskOpButton.py +0 -0
  237. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/TemplateFactory.py +0 -0
  238. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/TemplateTab.py +0 -0
  239. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/__init__.py +0 -0
  240. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/config_editors.py +0 -0
  241. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/config_form.py +0 -0
  242. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/mouse_buttons.py +0 -0
  243. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/tasks/schedule_index_sync.py +0 -0
  244. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/util/Alert.py +0 -0
  245. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/util/InitWorker.py +0 -0
  246. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/util/__init__.py +0 -0
  247. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/util/download.py +0 -0
  248. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/util/pip_util.py +0 -0
  249. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/util/pyappify_startup.py +0 -0
  250. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/util/touch_scroll.py +0 -0
  251. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/util/windows_thumbnail.py +0 -0
  252. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/Card.py +0 -0
  253. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/CustomTab.py +0 -0
  254. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/FlowLayout.py +0 -0
  255. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/ImageWidget.py +0 -0
  256. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/ImportWarningDialog.py +0 -0
  257. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/ListTableWidgetItem.py +0 -0
  258. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/NumericTableWidgetItem.py +0 -0
  259. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/SortingTableWidgetItem.py +0 -0
  260. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/StartLoadingDialog.py +0 -0
  261. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/Tab.py +0 -0
  262. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/TabWidget.py +0 -0
  263. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/UpdateConfigWidgetItem.py +0 -0
  264. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/YesNonWidgetItem.py +0 -0
  265. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/ui/qt/widget/__init__.py +0 -0
  266. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/update/__init__.py +0 -0
  267. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/update/copy_ok_folder.py +0 -0
  268. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/update/inline_ok_requirements.py +0 -0
  269. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/Analytics.py +0 -0
  270. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/GlobalConfig.py +0 -0
  271. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/__init__.py +0 -0
  272. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/blur.py +0 -0
  273. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/clazz.py +0 -0
  274. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/collection.py +0 -0
  275. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/color.py +0 -0
  276. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/config.py +0 -0
  277. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/explorer.py +0 -0
  278. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/file.py +0 -0
  279. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/gpu_driver_settings.py +0 -0
  280. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/handler.py +0 -0
  281. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/i18n.py +0 -0
  282. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/logger.py +0 -0
  283. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/partial_sync_repo.py +0 -0
  284. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/print_hwnd.py +0 -0
  285. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/process.py +0 -0
  286. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/version.py +0 -0
  287. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/window.py +0 -0
  288. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok/util/windows_schedule.py +0 -0
  289. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok_script.egg-info/dependency_links.txt +0 -0
  290. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok_script.egg-info/entry_points.txt +0 -0
  291. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok_script.egg-info/not-zip-safe +0 -0
  292. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok_script.egg-info/requires.txt +0 -0
  293. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/ok_script.egg-info/top_level.txt +0 -0
  294. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/pyproject.toml +0 -0
  295. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/setup.cfg +0 -0
  296. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/setup.py +0 -0
  297. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_app.py +0 -0
  298. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_base_interaction.py +0 -0
  299. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_blur.py +0 -0
  300. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_box.py +0 -0
  301. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_capture_update.py +0 -0
  302. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_cli.py +0 -0
  303. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_core_events.py +0 -0
  304. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_core_ui_services.py +0 -0
  305. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_device_manager.py +0 -0
  306. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_diagnosis_page.py +0 -0
  307. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_executor_jobs.py +0 -0
  308. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_explorer.py +0 -0
  309. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_global_config.py +0 -0
  310. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_gpu_driver_settings.py +0 -0
  311. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_handler.py +0 -0
  312. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_headless_imports.py +0 -0
  313. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_inline_ok_requirements.py +0 -0
  314. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_kit.py +0 -0
  315. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_log_page.py +0 -0
  316. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_logger.py +0 -0
  317. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_main_window_notifications.py +0 -0
  318. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_main_window_startup_tab.py +0 -0
  319. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_markup_window.py +0 -0
  320. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_mcp_cleanup.py +0 -0
  321. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_mcp_runner.py +0 -0
  322. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_mcp_server.py +0 -0
  323. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_mcp_setting.py +0 -0
  324. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_missing_frame.py +0 -0
  325. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_mouse_buttons.py +0 -0
  326. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_navigation_state.py +0 -0
  327. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_nemu_ipc_capture.py +0 -0
  328. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_notifications.py +0 -0
  329. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_ok_mutex.py +0 -0
  330. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_overlay_custom_draw.py +0 -0
  331. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_overlay_lifecycle.py +0 -0
  332. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_package_metadata.py +0 -0
  333. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_plugin_staging.py +0 -0
  334. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_plugin_tabs.py +0 -0
  335. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_plugins.py +0 -0
  336. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_process.py +0 -0
  337. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_process_mutex.py +0 -0
  338. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_pyappify_startup_update.py +0 -0
  339. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_qt_events.py +0 -0
  340. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_qt_page_layout.py +0 -0
  341. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_runtime_startup.py +0 -0
  342. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_schedule_startup.py +0 -0
  343. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_schedule_task_index_sync.py +0 -0
  344. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_screenshot_naming.py +0 -0
  345. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_screenshot_rendering.py +0 -0
  346. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_settings_page.py +0 -0
  347. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_skills.py +0 -0
  348. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_start_controller.py +0 -0
  349. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_task_executor_next_frame.py +0 -0
  350. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_task_executor_queue.py +0 -0
  351. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_task_reloading.py +0 -0
  352. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_tasks_page.py +0 -0
  353. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_template_compression.py +0 -0
  354. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_template_generation.py +0 -0
  355. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_template_tab.py +0 -0
  356. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_touch_scroll.py +0 -0
  357. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_translation_fallback.py +0 -0
  358. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_ui_config.py +0 -0
  359. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_version.py +0 -0
  360. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_windows_graphics_capture.py +0 -0
  361. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_windows_graphics_hdr.py +0 -0
  362. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_windows_schedule_target_parse.py +0 -0
  363. {ok_script-2.0.23b1 → ok_script-3.0.0b2}/tests/test_windows_schedule_xml.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ok-script
3
- Version: 2.0.23b1
3
+ Version: 3.0.0b2
4
4
  Summary: Vibe Coding Automation Framework
5
5
  Author-email: ok-oldking <firedcto@gmail.com>
6
6
  License: ok-script License
@@ -230,6 +230,16 @@ python -m venv .venv
230
230
  - [白荆回廊](https://github.com/ok-oldking/ok-baijing)(停止维护)
231
231
  - [崩坏:星穹铁道](https://github.com/Shasnow/ok-starrailassistant)(停止维护)
232
232
 
233
+ ## 开发 ok-script
234
+
235
+ 在本仓库中测试界面改动时,可以用 [main.py](main.py) 中的演示配置直接从源码启动 GUI:
236
+
237
+ ```powershell
238
+ .\.venv\Scripts\python.exe main.py
239
+ ```
240
+
241
+ 它以记事本为目标窗口,无需游戏,并注册了一个演示一次性任务和一个触发任务,让任务、计划任务和模板页面都有内容。设置和日志保存在已被 git 忽略的 `configs/` 和 `logs/` 目录中。需要测试其他选项时,修改 `main.py` 中的 `config` 字典或演示任务即可。
242
+
233
243
  ## 社区与发布
234
244
 
235
245
  - 开发者 QQ 群:938132715
@@ -106,6 +106,16 @@ python -m venv .venv
106
106
  - [白荆回廊](https://github.com/ok-oldking/ok-baijing)(停止维护)
107
107
  - [崩坏:星穹铁道](https://github.com/Shasnow/ok-starrailassistant)(停止维护)
108
108
 
109
+ ## 开发 ok-script
110
+
111
+ 在本仓库中测试界面改动时,可以用 [main.py](main.py) 中的演示配置直接从源码启动 GUI:
112
+
113
+ ```powershell
114
+ .\.venv\Scripts\python.exe main.py
115
+ ```
116
+
117
+ 它以记事本为目标窗口,无需游戏,并注册了一个演示一次性任务和一个触发任务,让任务、计划任务和模板页面都有内容。设置和日志保存在已被 git 忽略的 `configs/` 和 `logs/` 目录中。需要测试其他选项时,修改 `main.py` 中的 `config` 字典或演示任务即可。
118
+
109
119
  ## 社区与发布
110
120
 
111
121
  - 开发者 QQ 群:938132715
@@ -310,6 +310,8 @@ class App(_OverlayConfigMixin):
310
310
  self.global_config = task_executor.global_config if task_executor else None
311
311
  from ok.ui.qt.util.app import init_app_config
312
312
  self.app, self.locale = init_app_config()
313
+ from ok.ui.qt.common.config import cfg as ui_config
314
+ ui_config.language_changed.connect(self._on_language_changed)
313
315
  install_qt_event_dispatcher()
314
316
  self.app.aboutToQuit.connect(self._close_device_manager)
315
317
  if task_executor is not None:
@@ -461,6 +463,44 @@ class App(_OverlayConfigMixin):
461
463
  self.do_show_main()
462
464
 
463
465
  def do_show_main(self):
466
+ self._create_main_window()
467
+ self.main_window.show()
468
+ self.main_window.bring_to_front()
469
+
470
+ logger.debug(f'show_main_window end')
471
+
472
+ def _on_language_changed(self):
473
+ # The signal comes from a widget in the window being replaced; rebuild once it returns.
474
+ from PySide6.QtCore import QTimer
475
+ QTimer.singleShot(0, self._apply_language)
476
+
477
+ def _apply_language(self):
478
+ from ok.ui.qt.util.app import install_translator
479
+ self.locale = install_translator(self.app)
480
+ self.po_translation = None
481
+ if og.executor is not None:
482
+ og.executor.locale = self.locale
483
+ og.executor.load_tr()
484
+ logger.info(f'language changed to {self.locale.name()}')
485
+
486
+ old_window = self.main_window
487
+ if old_window is None:
488
+ return
489
+ # Every page translates its text on construction, so build a fresh window.
490
+ visible = old_window.isVisible()
491
+ old_window.update_ok_config()
492
+ old_window.dispose()
493
+ self._create_main_window()
494
+ # Startup work in the first showEvent has already run for this process.
495
+ self.main_window.shown = True
496
+ self.main_window.switch_to(self.main_window.setting_tab)
497
+ if visible:
498
+ self.main_window.show()
499
+ self.main_window.bring_to_front()
500
+ old_window.hide()
501
+ old_window.deleteLater()
502
+
503
+ def _create_main_window(self):
464
504
  from ok.ui.qt.MainWindow import MainWindow
465
505
 
466
506
  self.main_window = MainWindow(self, self.config, self.ok_config, self.icon, self.title, self.version,
@@ -482,11 +522,6 @@ class App(_OverlayConfigMixin):
482
522
  if hasattr(og.my_app, 'on_show_main_window'):
483
523
  og.my_app.on_show_main_window(self.main_window)
484
524
 
485
- self.main_window.show()
486
- self.main_window.bring_to_front()
487
-
488
- logger.debug(f'show_main_window end')
489
-
490
525
  def exec(self):
491
526
  logger.info('app.exec()')
492
527
  import signal
@@ -45,6 +45,10 @@ class EventSignal:
45
45
  elif callback in self._subscribers:
46
46
  self._subscribers.remove(callback)
47
47
 
48
+ def disconnect_where(self, predicate: Callable[[Callable[..., Any]], bool]) -> None:
49
+ with self._lock:
50
+ self._subscribers = [callback for callback in self._subscribers if not predicate(callback)]
51
+
48
52
  def emit(self, *args: Any, **kwargs: Any) -> None:
49
53
  with self._lock:
50
54
  subscribers = tuple(self._subscribers)
@@ -94,6 +98,12 @@ class EventBus:
94
98
  self.any.emit(EventMessage(name, args, kwargs))
95
99
  return forward
96
100
 
101
+ def disconnect_where(self, predicate: Callable[[Callable[..., Any]], bool]) -> None:
102
+ """Remove every subscriber of every event for which ``predicate`` is true."""
103
+ self.any.disconnect_where(predicate)
104
+ for name in self._event_names:
105
+ getattr(self, name).disconnect_where(predicate)
106
+
97
107
  def emit_draw_box(self, key=None, boxes=None, color=None, frame=None, debug=True):
98
108
  self.draw_box.emit(key, boxes, color, frame, debug)
99
109
 
@@ -2,7 +2,7 @@ import os
2
2
  import threading
3
3
 
4
4
  import pyappify
5
- from PySide6.QtCore import QCoreApplication, QEvent, QSize, Qt, QTimer
5
+ from PySide6.QtCore import QCoreApplication, QEvent, QObject, QSize, Qt, QTimer
6
6
  from PySide6.QtGui import QColor
7
7
  from PySide6.QtWidgets import QApplication, QHBoxLayout, QMenu, QStackedWidget, QSystemTrayIcon, QVBoxLayout
8
8
 
@@ -34,6 +34,7 @@ from ok.ui.qt.common.config import cfg as ui_config
34
34
  from ok.ui.qt.kit import Dialog, KitWindow, NavigationView, Theme as KitTheme, set_toast_bottom_margin, show_toast, \
35
35
  theme as kit_theme
36
36
  from ok.ui.qt.kit.theme import set_style_property
37
+ from ok.ui.qt.shell.lazy_page import LazyPage
37
38
  from ok.ui.qt.shell.nav_icons import nav_icon
38
39
  from ok.ui.qt.shell.run_bar import RunBar
39
40
  from ok.ui.qt.util.Alert import alert_error
@@ -117,7 +118,7 @@ class MainWindow(KitWindow):
117
118
  set_toast_bottom_margin(self, PAGE_MARGIN)
118
119
 
119
120
  self.schedule_tab = None
120
- self.global_config_tabs = []
121
+ self.global_config_tabs = [] # [(config, LazyPage)]
121
122
 
122
123
  # Prepare custom tabs and separate them by add_after_default_tabs
123
124
  before_custom_tabs = []
@@ -155,9 +156,13 @@ class MainWindow(KitWindow):
155
156
  self.edit_task_tab = EditTaskTab()
156
157
  self.add_page(self.edit_task_tab, "pen", self.tr('Script'), SECTION_DEVELOP)
157
158
 
159
+ # Settings, Templates and global config pages are rarely opened, so they are
160
+ # built on first use (LazyPage) to keep window construction fast.
158
161
  if og.task_manager.has_custom or debug:
159
- from ok.ui.qt.tasks.TemplateTab import TemplateTab
160
- self.template_tab = TemplateTab(config=config)
162
+ def template_tab():
163
+ from ok.ui.qt.tasks.TemplateTab import TemplateTab
164
+ return TemplateTab(config=config)
165
+ self.template_tab = LazyPage(template_tab)
161
166
  self.add_page(self.template_tab, "image", self.tr('Templates'), SECTION_DEVELOP)
162
167
 
163
168
  from ok.ui.qt.debug.diagnosis_page import DiagnosisPage
@@ -192,9 +197,11 @@ class MainWindow(KitWindow):
192
197
  notification_tab = None
193
198
  for name, config_obj, option in global_config.get_all_visible_configs():
194
199
  if getattr(option, 'show_at_tab', False):
195
- from ok.ui.qt.settings.GlobalConfigTab import GlobalConfigTab
196
- config_tab = GlobalConfigTab(config_obj, option)
197
- self.global_config_tabs.append(config_tab)
200
+ def global_config_tab(config_obj=config_obj, option=option):
201
+ from ok.ui.qt.settings.GlobalConfigTab import GlobalConfigTab
202
+ return GlobalConfigTab(config_obj, option)
203
+ config_tab = LazyPage(global_config_tab)
204
+ self.global_config_tabs.append((config_obj, config_tab))
198
205
  if name == NOTIFICATION_OPTION_NAME:
199
206
  notification_tab = config_tab
200
207
  else:
@@ -204,8 +211,10 @@ class MainWindow(KitWindow):
204
211
  self.notification_tab = notification_tab
205
212
  self.add_page(notification_tab, "bell", self.app.tr(NOTIFICATION_OPTION_NAME), SECTION_GAME)
206
213
 
207
- from ok.ui.qt.settings.settings_page import SettingsPage
208
- self.setting_tab = SettingsPage()
214
+ def settings_page():
215
+ from ok.ui.qt.settings.settings_page import SettingsPage
216
+ return SettingsPage()
217
+ self.setting_tab = LazyPage(settings_page)
209
218
  self.add_page(self.setting_tab, "gear", self.tr('Settings'), bottom=True)
210
219
 
211
220
  from ok.ui.qt.about.AboutTab import AboutTab
@@ -275,6 +284,8 @@ class MainWindow(KitWindow):
275
284
  def switch_to(self, widget):
276
285
  if self.stack.indexOf(widget) < 0:
277
286
  return
287
+ if isinstance(widget, LazyPage):
288
+ widget.page()
278
289
  self.stack.setCurrentWidget(widget)
279
290
  self.navigation.set_current(widget.objectName())
280
291
 
@@ -442,12 +453,12 @@ class MainWindow(KitWindow):
442
453
  logger.debug(f'bring_to_front native activation failed: {e}')
443
454
 
444
455
  def goto_global_config(self, key):
445
- for config_tab in self.global_config_tabs:
446
- if config_tab.has_key(key):
456
+ for config_obj, config_tab in self.global_config_tabs:
457
+ if key in config_obj:
447
458
  self.switch_to(config_tab)
448
459
  return
449
460
  self.switch_to(self.setting_tab)
450
- self.setting_tab.goto_config(key)
461
+ self.setting_tab.page().goto_config(key)
451
462
 
452
463
  def tray_quit(self):
453
464
  logger.info('main window tray_quit')
@@ -669,6 +680,30 @@ class MainWindow(KitWindow):
669
680
  except Exception as e:
670
681
  logger.error(f'Error importing .okscript file: {e}')
671
682
 
683
+ def dispose(self):
684
+ """Release app-wide hooks so a replacement window can take over, e.g. after a language change."""
685
+ if self.update_check_timer is not None:
686
+ self.update_check_timer.stop()
687
+ self.tray.hide()
688
+ self.run_bar.dispose()
689
+ notification_manager = getattr(self, 'notification_manager', None)
690
+ if notification_manager is not None:
691
+ # Stopping waits for the pipeline thread; keep the GUI thread free.
692
+ threading.Thread(target=notification_manager.stop, name='NotificationStop', daemon=True).start()
693
+ controller = getattr(self, '_imported_tab_controller', None)
694
+ if controller is not None:
695
+ controller.dispose()
696
+ for page in list(self._pages.values()):
697
+ cleanup = getattr(page, 'dispose', None) or getattr(page, 'stop_worker', None)
698
+ if callable(cleanup):
699
+ try:
700
+ cleanup()
701
+ except Exception as error:
702
+ logger.error(f'Failed to dispose page {page.objectName()}', error)
703
+ # The event bus holds strong references; drop the ones owned by this window's widgets.
704
+ owners = {id(obj) for obj in (self, *self.findChildren(QObject))}
705
+ communicate.disconnect_where(lambda callback: id(getattr(callback, '__self__', None)) in owners)
706
+
672
707
  def closeEvent(self, event):
673
708
  if self.app.exit_event.is_set():
674
709
  logger.info("Window closed exit_event.is_set")
@@ -39,13 +39,13 @@ def deserialize_language(value) -> Language:
39
39
 
40
40
 
41
41
  class UiConfig(QObject):
42
- """The language (applied on restart) and the theme mode (applied live).
42
+ """The language and the theme mode, both applied live.
43
43
 
44
44
  The file also accepts the older qfluentwidgets layout
45
45
  (``MainWindow.Language`` and ``QFluentWidgets.ThemeMode``).
46
46
  """
47
47
 
48
- restart_required = Signal()
48
+ language_changed = Signal()
49
49
  theme_changed = Signal()
50
50
 
51
51
  def __init__(self, path: str):
@@ -83,7 +83,7 @@ class UiConfig(QObject):
83
83
  return
84
84
  self.language = language
85
85
  self.save()
86
- self.restart_required.emit()
86
+ self.language_changed.emit()
87
87
 
88
88
  def set_theme_mode(self, mode: str) -> None:
89
89
  mode = getattr(mode, "value", mode)
@@ -6,7 +6,7 @@ from ok.ui.qt.kit.icons import icon as kit_icon
6
6
  from ok.ui.qt.kit.theme import set_style_property, theme
7
7
 
8
8
  VARIANTS = ("secondary", "primary", "tonal", "subtle", "danger")
9
- SIZES = {"normal": (36, 14, 16), "small": (30, 10, 14)}
9
+ SIZES = {"normal": (36, 14, 18), "small": (30, 10, 16)}
10
10
 
11
11
  _ICON_COLOR = {"primary": "on_accent", "danger": "danger"}
12
12
 
@@ -48,7 +48,8 @@ class Button(QPushButton):
48
48
  height, padding, _ = SIZES[size]
49
49
  layout = QHBoxLayout(self)
50
50
  layout.setContentsMargins(padding, 0, padding, 0)
51
- layout.setSpacing(8)
51
+ # Glyphs leave a few pixels of air inside their box, so this reads wider than it is.
52
+ layout.setSpacing(5)
52
53
  layout.addStretch(1)
53
54
  layout.addWidget(self._icon_label)
54
55
  layout.addWidget(self._text_label)
@@ -17,9 +17,10 @@ from PySide6.QtGui import QColor, QIcon, QIconEngine, QImage, QPainter, QPixmap
17
17
  from PySide6.QtSvg import QSvgRenderer
18
18
 
19
19
  _PATHS = {
20
- "play": '<path d="M7 4.5v15l12-7.5z" fill="currentColor" stroke="none"/>',
21
- "pause": '<path d="M8 5v14M16 5v14"/>',
22
- "stop": '<rect x="6" y="6" width="12" height="12" rx="2" fill="currentColor" stroke="none"/>',
20
+ "play": '<path d="M7 3.5v17L20.5 12z" fill="currentColor" stroke="currentColor" stroke-width="1.5"/>',
21
+ "pause": '<rect x="5.5" y="4" width="4.5" height="16" rx="1.25" fill="currentColor" stroke="none"/>'
22
+ '<rect x="14" y="4" width="4.5" height="16" rx="1.25" fill="currentColor" stroke="none"/>',
23
+ "stop": '<rect x="4.5" y="4.5" width="15" height="15" rx="2.5" fill="currentColor" stroke="none"/>',
23
24
  "power": '<path d="M12 3v9M6.3 6.8a8 8 0 1 0 11.4 0"/>',
24
25
  "check": '<path d="M5 12.5l4.5 4.5L19 7"/>',
25
26
  "x": '<path d="M6 6l12 12M18 6 6 18"/>',
@@ -218,12 +218,13 @@ QAbstractItemView {{
218
218
  selection-color: {text};
219
219
  outline: 0;
220
220
  }}
221
+ QTableView::item {{ padding: 0 12px; }}
221
222
  QHeaderView::section {{
222
223
  background: {surface_alt};
223
224
  color: {text_secondary};
224
225
  border: 0;
225
226
  border-bottom: 1px solid {border};
226
- padding: 6px 10px;
227
+ padding: 6px 12px;
227
228
  font-weight: 600;
228
229
  }}
229
230
 
@@ -387,6 +388,11 @@ QLabel#taskTile {{
387
388
  font-size: 12px;
388
389
  font-weight: 600;
389
390
  }}
391
+ TaskIconTile#taskTile {{
392
+ background: transparent;
393
+ border: 0;
394
+ border-radius: 0;
395
+ }}
390
396
  QPushButton#sectionHeader {{
391
397
  background: transparent;
392
398
  border: 0;
@@ -9,7 +9,6 @@ from PySide6.QtWidgets import QButtonGroup, QFrame, QHBoxLayout, QPushButton, QS
9
9
  from ok import og
10
10
  from ok.ui.qt.common.config import Language, cfg
11
11
  from ok.ui.qt.kit.cards import SettingGroup, SettingRow
12
- from ok.ui.qt.kit.feedback import show_toast
13
12
  from ok.ui.qt.kit.inputs import ComboBox
14
13
  from ok.ui.qt.kit.labels import Label
15
14
  from ok.ui.qt.kit.tabs import TabStrip
@@ -83,7 +82,6 @@ class SettingsPage(QWidget):
83
82
  layout.addWidget(anchor_holder)
84
83
  layout.addWidget(self.scroll, 1)
85
84
  theme.install(self)
86
- cfg.restart_required.connect(self._show_restart_notice)
87
85
 
88
86
  # --- sections -------------------------------------------------------------
89
87
 
@@ -163,6 +161,3 @@ class SettingsPage(QWidget):
163
161
 
164
162
  def _set_theme(self, key: str) -> None:
165
163
  cfg.set_theme_mode(key)
166
-
167
- def _show_restart_notice(self) -> None:
168
- show_toast(self, _t('Configuration takes effect after restart'), _t('Updated successfully'), "success")
@@ -0,0 +1,32 @@
1
+ from PySide6.QtWidgets import QVBoxLayout, QWidget
2
+
3
+
4
+ class LazyPage(QWidget):
5
+ """Stands in for a page in the main stack and builds it on first use.
6
+
7
+ Use :meth:`page` to reach the real page; it is built if needed.
8
+ """
9
+
10
+ def __init__(self, factory, parent=None):
11
+ super().__init__(parent)
12
+ self._factory = factory
13
+ self._page = None
14
+ self._layout = QVBoxLayout(self)
15
+ self._layout.setContentsMargins(0, 0, 0, 0)
16
+
17
+ def is_built(self) -> bool:
18
+ return self._page is not None
19
+
20
+ def page(self) -> QWidget:
21
+ if self._page is None:
22
+ self._page = self._factory()
23
+ self._factory = None
24
+ self._layout.addWidget(self._page)
25
+ return self._page
26
+
27
+ def dispose(self) -> None:
28
+ if self._page is None:
29
+ return
30
+ cleanup = getattr(self._page, 'dispose', None) or getattr(self._page, 'stop_worker', None)
31
+ if callable(cleanup):
32
+ cleanup()
@@ -41,9 +41,14 @@ def format_elapsed(seconds: float) -> str:
41
41
 
42
42
 
43
43
  def game_display_name(config) -> str:
44
- """The game's name from the ``game_name`` config, or a generic "Game"."""
44
+ """The translated ``game_name`` config, or a generic "Game"."""
45
45
 
46
- return (config or {}).get('game_name') or _t("RunBar", "Game")
46
+ from ok import og
47
+
48
+ name = (config or {}).get('game_name')
49
+ if name:
50
+ return og.app.tr(name) if og.app is not None else name
51
+ return _t("RunBar", "Game")
47
52
 
48
53
 
49
54
  @dataclass
@@ -321,6 +326,17 @@ class RunBar(QFrame):
321
326
 
322
327
  # --- global hotkey (runs on the handler thread) ----------------------------
323
328
 
329
+ def dispose(self) -> None:
330
+ """Release the hotkey and stop polling so a replacement run bar can bind it."""
331
+ self.timer.stop()
332
+ self.handler.post(self._release_hotkey)
333
+ self.handler.join(1)
334
+
335
+ def _release_hotkey(self) -> None:
336
+ # The hotkey belongs to the thread that registered it, so release it there.
337
+ windll.user32.UnregisterHotKey(None, HOTKEY_ID)
338
+ self.handler.stop()
339
+
324
340
  def _check_hotkey(self) -> None:
325
341
  new_hotkey = self.basic_options.get('Start/Stop')
326
342
  if new_hotkey != self.current_hotkey:
@@ -111,6 +111,14 @@ def task_icon(task):
111
111
  return None if resolved == FALLBACK else resolved
112
112
 
113
113
 
114
+ def task_category_icon(key, fallback=None):
115
+ """Resolve app-provided category artwork, keeping the default kit icons."""
116
+
117
+ config = getattr(og, 'config', None) or {}
118
+ source = config.get('task_category_icons', {}).get(key, fallback)
119
+ return nav_icon(source) if source is not None else None
120
+
121
+
114
122
  def split_leading_symbol(name: str):
115
123
  """Split a leading emoji or symbol off a task name: ``("📅", "Daily Task")``.
116
124
 
@@ -176,7 +184,7 @@ def matches_filter(task, key: str, is_trigger: bool) -> bool:
176
184
  # --- list -------------------------------------------------------------------------
177
185
 
178
186
  class TaskIconTile(QLabel):
179
- """The task's own icon on a rounded tile, or its monogram."""
187
+ """The task's own icon or monogram, without a background tile."""
180
188
 
181
189
  def __init__(self, task, size: int = 36, parent=None):
182
190
  super().__init__(parent)
@@ -313,7 +321,7 @@ class TaskSection(Card):
313
321
 
314
322
  toggled = Signal(bool)
315
323
 
316
- def __init__(self, title: str, icon_name: str, parent=None):
324
+ def __init__(self, title: str, icon_name, parent=None):
317
325
  super().__init__(parent)
318
326
  self.rows = []
319
327
  self._expanded = True
@@ -388,7 +396,9 @@ class TaskSection(Card):
388
396
 
389
397
  def _refresh_icons(self) -> None:
390
398
  dpr = self.devicePixelRatioF()
391
- self.icon_label.setPixmap(kit_icon(self._icon_name, "text", 1.8).pixmap(QSize(16, 16), dpr))
399
+ source = nav_icon(self._icon_name)
400
+ icon = kit_icon(source, "text", 1.8) if isinstance(source, str) else source
401
+ self.icon_label.setPixmap(icon.pixmap(QSize(16, 16), dpr))
392
402
  chevron = "chevron-up" if self._expanded else "chevron-down"
393
403
  self.chevron.setPixmap(kit_icon(chevron, "text_tertiary", 2).pixmap(QSize(14, 14), dpr))
394
404
 
@@ -471,6 +481,9 @@ class TaskDetail(QWidget):
471
481
  self.info_table.verticalHeader().hide()
472
482
  self.info_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
473
483
  self.info_table.horizontalHeader().setStretchLastSection(True)
484
+ # Left-aligned headers line up with the padded cell text below them.
485
+ self.info_table.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
486
+ self.info_table.verticalHeader().setDefaultSectionSize(40)
474
487
  self.info_table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
475
488
  self.info_table.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
476
489
  self.pages = QStackedWidget()
@@ -670,8 +683,8 @@ class TasksPage(QWidget):
670
683
  top.addWidget(self.filter_tabs)
671
684
  top.addStretch(1)
672
685
 
673
- self.onetime_section = TaskSection(_t("TasksPage", "On-demand"), "bolt")
674
- self.trigger_section = TaskSection(_t("TasksPage", "Triggers"), "timer")
686
+ self.onetime_section = TaskSection(_t("TasksPage", "On-demand"), task_category_icon(KIND_ONETIME, "bolt"))
687
+ self.trigger_section = TaskSection(_t("TasksPage", "Triggers"), task_category_icon(KIND_TRIGGER, "timer"))
675
688
  self.onetime_section.toggled.connect(lambda _on: self._layout_sections())
676
689
  self.trigger_section.toggled.connect(lambda _on: self._layout_sections())
677
690
  self.list_column = QVBoxLayout()
@@ -743,10 +756,13 @@ class TasksPage(QWidget):
743
756
 
744
757
  both_kinds = bool(self.onetime_tasks) and bool(self.trigger_tasks)
745
758
  groups = task_groups(self.onetime_tasks + self.trigger_tasks)
746
- self.filter_tabs.add_tab(KIND_ALL, _t("TasksPage", "All"), len(self.onetime_tasks) + len(self.trigger_tasks))
759
+ self.filter_tabs.add_tab(KIND_ALL, _t("TasksPage", "All"), len(self.onetime_tasks) + len(self.trigger_tasks),
760
+ task_category_icon(KIND_ALL))
747
761
  if both_kinds:
748
- self.filter_tabs.add_tab(KIND_ONETIME, _t("TasksPage", "On-demand"), len(self.onetime_tasks), "bolt")
749
- self.filter_tabs.add_tab(KIND_TRIGGER, _t("TasksPage", "Triggers"), len(self.trigger_tasks), "timer")
762
+ self.filter_tabs.add_tab(KIND_ONETIME, _t("TasksPage", "On-demand"), len(self.onetime_tasks),
763
+ task_category_icon(KIND_ONETIME, "bolt"))
764
+ self.filter_tabs.add_tab(KIND_TRIGGER, _t("TasksPage", "Triggers"), len(self.trigger_tasks),
765
+ task_category_icon(KIND_TRIGGER, "timer"))
750
766
  if groups:
751
767
  self.filter_tabs.add_separator()
752
768
  for name, group_icon in groups.items():
@@ -9,6 +9,27 @@ from ok.ui.qt.common.config import cfg
9
9
 
10
10
  logger = Logger.get_logger(__name__)
11
11
 
12
+ _translator = None
13
+
14
+
15
+ def install_translator(app):
16
+ """Replace the installed Qt translator with one for ``cfg.language``; returns the locale."""
17
+ global _translator
18
+ if _translator is not None:
19
+ app.removeTranslator(_translator)
20
+ _translator.deleteLater()
21
+ _translator = None
22
+ locale = cfg.language.value
23
+ translator = QTranslator(app)
24
+ if translator.load(locale.name(), ":/i18n"):
25
+ app.installTranslator(translator)
26
+ _translator = translator
27
+ logger.info(f"translator install success {locale}, {QCoreApplication.translate('MainWindow', 'Debug')}")
28
+ else:
29
+ translator.deleteLater()
30
+ logger.info(f"No translation available for {locale}, falling back to English/default.")
31
+ return locale
32
+
12
33
 
13
34
  def init_app_config():
14
35
  logger.debug(f'resources.qt_resource_name {resources.qt_resource_name} theme {cfg.theme_mode}')
@@ -20,13 +41,7 @@ def init_app_config():
20
41
  app.setAttribute(Qt.AA_UseHighDpiPixmaps)
21
42
  app.setAttribute(Qt.AA_DontCreateNativeWidgetSiblings)
22
43
 
23
- locale = cfg.language.value
24
- translator = QTranslator(app)
25
- if translator.load(locale.name(), ":/i18n"):
26
- app.installTranslator(translator)
27
- logger.info(f"translator install success {locale}, {QCoreApplication.translate('MainWindow', 'Debug')}")
28
- else:
29
- logger.info(f"No translation available for {locale}, falling back to English/default.")
44
+ locale = install_translator(app)
30
45
 
31
46
  from ok.ui.qt.kit import Theme, theme
32
47
  theme.set_theme(Theme(cfg.theme_mode))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ok-script
3
- Version: 2.0.23b1
3
+ Version: 3.0.0b2
4
4
  Summary: Vibe Coding Automation Framework
5
5
  Author-email: ok-oldking <firedcto@gmail.com>
6
6
  License: ok-script License
@@ -230,6 +230,16 @@ python -m venv .venv
230
230
  - [白荆回廊](https://github.com/ok-oldking/ok-baijing)(停止维护)
231
231
  - [崩坏:星穹铁道](https://github.com/Shasnow/ok-starrailassistant)(停止维护)
232
232
 
233
+ ## 开发 ok-script
234
+
235
+ 在本仓库中测试界面改动时,可以用 [main.py](main.py) 中的演示配置直接从源码启动 GUI:
236
+
237
+ ```powershell
238
+ .\.venv\Scripts\python.exe main.py
239
+ ```
240
+
241
+ 它以记事本为目标窗口,无需游戏,并注册了一个演示一次性任务和一个触发任务,让任务、计划任务和模板页面都有内容。设置和日志保存在已被 git 忽略的 `configs/` 和 `logs/` 目录中。需要测试其他选项时,修改 `main.py` 中的 `config` 字典或演示任务即可。
242
+
233
243
  ## 社区与发布
234
244
 
235
245
  - 开发者 QQ 群:938132715
@@ -214,6 +214,7 @@ ok/ui/qt/settings/settings_page.py
214
214
  ok/ui/qt/shell/__init__.py
215
215
  ok/ui/qt/shell/connection.py
216
216
  ok/ui/qt/shell/diagnostics.py
217
+ ok/ui/qt/shell/lazy_page.py
217
218
  ok/ui/qt/shell/log_page.py
218
219
  ok/ui/qt/shell/nav_icons.py
219
220
  ok/ui/qt/shell/run_bar.py
@@ -306,6 +307,7 @@ tests/test_handler.py
306
307
  tests/test_headless_imports.py
307
308
  tests/test_inline_ok_requirements.py
308
309
  tests/test_kit.py
310
+ tests/test_lazy_page.py
309
311
  tests/test_log_page.py
310
312
  tests/test_logger.py
311
313
  tests/test_main_window_notifications.py
@@ -0,0 +1,47 @@
1
+ import os
2
+ import unittest
3
+ from unittest.mock import Mock
4
+
5
+ os.environ.setdefault('QT_QPA_PLATFORM', 'offscreen')
6
+
7
+ from PySide6.QtWidgets import QApplication, QWidget
8
+
9
+ from ok.ui.qt.shell.lazy_page import LazyPage
10
+
11
+
12
+ class TestLazyPage(unittest.TestCase):
13
+ @classmethod
14
+ def setUpClass(cls):
15
+ cls.qt_app = QApplication.instance() or QApplication([])
16
+
17
+ def test_builds_once_on_first_use(self):
18
+ factory = Mock(side_effect=QWidget)
19
+ lazy = LazyPage(factory)
20
+
21
+ self.assertFalse(lazy.is_built())
22
+ factory.assert_not_called()
23
+
24
+ page = lazy.page()
25
+ self.assertIs(page, lazy.page())
26
+ self.assertIs(lazy, page.parentWidget())
27
+ factory.assert_called_once_with()
28
+
29
+ def test_dispose_skips_unbuilt_page(self):
30
+ factory = Mock(side_effect=QWidget)
31
+ LazyPage(factory).dispose()
32
+
33
+ factory.assert_not_called()
34
+
35
+ def test_dispose_forwards_to_built_page(self):
36
+ page = QWidget()
37
+ page.dispose = Mock()
38
+ lazy = LazyPage(lambda: page)
39
+ lazy.page()
40
+
41
+ lazy.dispose()
42
+
43
+ page.dispose.assert_called_once_with()
44
+
45
+
46
+ if __name__ == "__main__":
47
+ unittest.main()
@@ -48,7 +48,7 @@ class TestUiConfig(unittest.TestCase):
48
48
  self.assertEqual("dark", config.theme_mode)
49
49
 
50
50
  restart, themed = Mock(), Mock()
51
- config.restart_required.connect(restart)
51
+ config.language_changed.connect(restart)
52
52
  config.theme_changed.connect(themed)
53
53
  config.set_language(Language.ENGLISH)
54
54
  config.set_theme_mode("light")