frontengine 1.0.11__tar.gz → 1.0.13__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 (136) hide show
  1. {frontengine-1.0.11 → frontengine-1.0.13}/PKG-INFO +1 -1
  2. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/pet/desktop_pet.py +106 -4
  3. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/multi_language/english.py +1 -0
  4. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/multi_language/traditional_chinese.py +1 -0
  5. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine.egg-info/PKG-INFO +1 -1
  6. {frontengine-1.0.11 → frontengine-1.0.13}/pyproject.toml +1 -1
  7. {frontengine-1.0.11 → frontengine-1.0.13}/LICENSE +0 -0
  8. {frontengine-1.0.11 → frontengine-1.0.13}/README.md +0 -0
  9. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/__init__.py +0 -0
  10. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/__main__.py +0 -0
  11. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/__init__.py +0 -0
  12. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/base_widget.py +0 -0
  13. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/gif/__init__.py +0 -0
  14. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/gif/paint_gif.py +0 -0
  15. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/image/__init__.py +0 -0
  16. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/image/paint_image.py +0 -0
  17. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/load/__init__.py +0 -0
  18. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/load/load_someone_make_ui.py +0 -0
  19. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/overlay_factory.py +0 -0
  20. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/particle/__init__.py +0 -0
  21. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/particle/particle_ui.py +0 -0
  22. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/pet/__init__.py +0 -0
  23. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/scene/__init__.py +0 -0
  24. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/scene/extend_graphic_scene.py +0 -0
  25. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/scene/extend_graphic_view.py +0 -0
  26. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/scene/scene.py +0 -0
  27. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/sound_player/__init__.py +0 -0
  28. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/sound_player/sound_effect.py +0 -0
  29. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/sound_player/sound_player.py +0 -0
  30. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/text/__init__.py +0 -0
  31. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/text/draw_text.py +0 -0
  32. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/video/__init__.py +0 -0
  33. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/video/video_player.py +0 -0
  34. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/web/__init__.py +0 -0
  35. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/web/webview.py +0 -0
  36. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/show/window_helpers.py +0 -0
  37. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/system_tray/__init__.py +0 -0
  38. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/system_tray/extend_system_tray.py +0 -0
  39. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/__init__.py +0 -0
  40. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/color/__init__.py +0 -0
  41. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/color/global_color.py +0 -0
  42. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/dialog/__init__.py +0 -0
  43. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
  44. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
  45. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/dialog/save_file_dialog.py +0 -0
  46. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/main_ui.py +0 -0
  47. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/menu/__init__.py +0 -0
  48. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/menu/help_menu.py +0 -0
  49. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/menu/how_to_menu.py +0 -0
  50. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/menu/language_menu.py +0 -0
  51. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/menu/preset_menu.py +0 -0
  52. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/menu/settings_menu.py +0 -0
  53. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/__init__.py +0 -0
  54. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/control_center/__init__.py +0 -0
  55. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/control_center/control_center_ui.py +0 -0
  56. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/gif/__init__.py +0 -0
  57. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
  58. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/image/__init__.py +0 -0
  59. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/image/image_setting_ui.py +0 -0
  60. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/particle/__init__.py +0 -0
  61. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
  62. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/pet/__init__.py +0 -0
  63. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/pet/pet_setting_ui.py +0 -0
  64. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/__init__.py +0 -0
  65. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
  66. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/scene_page/__init__.py +0 -0
  67. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
  68. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
  69. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
  70. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
  71. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
  72. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
  73. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
  74. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
  75. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
  76. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/sound_player/__init__.py +0 -0
  77. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
  78. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/text/__init__.py +0 -0
  79. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/text/text_setting_ui.py +0 -0
  80. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/utils.py +0 -0
  81. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/video/__init__.py +0 -0
  82. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/video/video_setting_ui.py +0 -0
  83. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/web/__init__.py +0 -0
  84. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/ui/page/web/web_setting_ui.py +0 -0
  85. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/user_setting/__init__.py +0 -0
  86. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/user_setting/preset_repository.py +0 -0
  87. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/user_setting/scene_setting.py +0 -0
  88. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/user_setting/user_setting_file.py +0 -0
  89. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/__init__.py +0 -0
  90. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/browser/__init__.py +0 -0
  91. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/browser/browser.py +0 -0
  92. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/critical_exit/__init__.py +0 -0
  93. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
  94. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/critical_exit/critical_exit.py +0 -0
  95. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/critical_exit/win32_vk.py +0 -0
  96. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/exception/__init__.py +0 -0
  97. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/exception/exception_tags.py +0 -0
  98. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/exception/exceptions.py +0 -0
  99. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/file/__init__.py +0 -0
  100. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/file/open/__init__.py +0 -0
  101. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/file/open/open_file.py +0 -0
  102. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/file/save/__init__.py +0 -0
  103. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/file/save/save_file.py +0 -0
  104. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/hotkey/__init__.py +0 -0
  105. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/hotkey/hotkey_service.py +0 -0
  106. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/json/__init__.py +0 -0
  107. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/json/json_file.py +0 -0
  108. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/json/json_repository.py +0 -0
  109. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/json_format/__init__.py +0 -0
  110. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/json_format/json_process.py +0 -0
  111. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/logging/__init__.py +0 -0
  112. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/logging/loggin_instance.py +0 -0
  113. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/multi_language/__init__.py +0 -0
  114. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/multi_language/france.py +0 -0
  115. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/multi_language/germany.py +0 -0
  116. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/multi_language/italy.py +0 -0
  117. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/multi_language/language_wrapper.py +0 -0
  118. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/multi_language/russian.py +0 -0
  119. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
  120. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/preset_schedule/__init__.py +0 -0
  121. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
  122. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/redirect_manager/__init__.py +0 -0
  123. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
  124. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/smart_pause/__init__.py +0 -0
  125. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
  126. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/theme_schedule/__init__.py +0 -0
  127. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
  128. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/utils/web_url.py +0 -0
  129. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/worker/__init__.py +0 -0
  130. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine/worker/qthread_worker.py +0 -0
  131. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine.egg-info/SOURCES.txt +0 -0
  132. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine.egg-info/dependency_links.txt +0 -0
  133. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine.egg-info/entry_points.txt +0 -0
  134. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine.egg-info/requires.txt +0 -0
  135. {frontengine-1.0.11 → frontengine-1.0.13}/frontengine.egg-info/top_level.txt +0 -0
  136. {frontengine-1.0.11 → frontengine-1.0.13}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.11
3
+ Version: 1.0.13
4
4
  Summary: FrontEngine is use-define frontview or only use like screen saver
5
5
  Author-email: JE-Chen <jechenmailman@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/Intergration-Automation-Testing/FrontEngine
@@ -144,6 +144,38 @@ def windows_platforms(exclude_hwnds=()) -> list:
144
144
  return []
145
145
 
146
146
 
147
+ def read_battery():
148
+ """
149
+ 回傳 (電量百分比, 是否充電中);無法取得時回傳 None。僅 Windows 實作。
150
+ Return (percent, charging) or None when unavailable. Windows only.
151
+ """
152
+ if sys.platform != "win32":
153
+ return None
154
+ try:
155
+ import ctypes
156
+
157
+ class _SPS(ctypes.Structure):
158
+ _fields_ = [
159
+ ("ACLineStatus", ctypes.c_byte),
160
+ ("BatteryFlag", ctypes.c_byte),
161
+ ("BatteryLifePercent", ctypes.c_byte),
162
+ ("SystemStatusFlag", ctypes.c_byte),
163
+ ("BatteryLifeTime", ctypes.c_ulong),
164
+ ("BatteryFullLifeTime", ctypes.c_ulong),
165
+ ]
166
+
167
+ status = _SPS()
168
+ if not ctypes.windll.kernel32.GetSystemPowerStatus(ctypes.byref(status)):
169
+ return None
170
+ percent = status.BatteryLifePercent & 0xFF
171
+ if percent == 255: # unknown / no battery
172
+ return None
173
+ return (int(percent), status.ACLineStatus == 1)
174
+ except Exception as error: # pragma: no cover - Win32 boundary
175
+ front_engine_logger.warning(f"[read_battery] error: {error!r}")
176
+ return None
177
+
178
+
147
179
  def nearest_peer(center, peers):
148
180
  """
149
181
  回傳離 center 最近的同伴座標與距離;無同伴回傳 (None, inf)。
@@ -323,6 +355,8 @@ class PetMotion:
323
355
  self.on_platform = False
324
356
  self.platform_span: Optional[Tuple[float, float]] = None
325
357
  self.ground_feet = 0.0
358
+ # 追向某個 x(用於朝同伴走過去玩耍)/ Horizontal target to walk toward (play).
359
+ self.follow_target_x: Optional[float] = None
326
360
 
327
361
  @property
328
362
  def facing_left(self) -> bool:
@@ -335,6 +369,13 @@ class PetMotion:
335
369
  """設定可站立的視窗上緣平台 / Set standable window top-edge platforms."""
336
370
  self.platforms = list(platforms)
337
371
 
372
+ def set_follow(self, target_x) -> None:
373
+ """設定要走向的 x 座標(朝同伴玩耍)/ Set a horizontal target to walk toward."""
374
+ self.follow_target_x = float(target_x)
375
+
376
+ def clear_follow(self) -> None:
377
+ self.follow_target_x = None
378
+
338
379
  def set_target(self, x: float, y: float) -> None:
339
380
  self.target = (float(x), float(y))
340
381
 
@@ -347,6 +388,7 @@ class PetMotion:
347
388
  self.surface = SURFACE_FLOOR
348
389
  self.on_platform = False
349
390
  self.platform_span = None
391
+ self.follow_target_x = None
350
392
 
351
393
  def step(self) -> Tuple[int, int]:
352
394
  left, top, right, bottom = self.bounds
@@ -364,6 +406,8 @@ class PetMotion:
364
406
  )
365
407
  if airborne:
366
408
  return self._step_fall(left, top, right, bottom, floor_y)
409
+ if self.follow_target_x is not None:
410
+ return self._step_follow(left, top, right, bottom, floor_y)
367
411
  if self.on_platform:
368
412
  return self._step_platform(left, top, right, bottom, floor_y)
369
413
  if self.surface != SURFACE_FLOOR:
@@ -437,6 +481,25 @@ class PetMotion:
437
481
  self._new_state(force_walk=True)
438
482
  return int(self.x), int(self.y)
439
483
 
484
+ def _step_follow(self, left, top, right, bottom, floor_y) -> Tuple[int, int]:
485
+ """朝 follow_target_x 走過去;抵達附近即清除並恢復隨機行為。"""
486
+ center_x = self.x + self.width / 2.0
487
+ if abs(center_x - self.follow_target_x) <= self.speed + 2.0:
488
+ self.follow_target_x = None
489
+ self._new_state()
490
+ return int(self.x), int(self.y)
491
+ self.state = "walk"
492
+ self.vx = float(self.speed) if self.follow_target_x >= center_x else float(-self.speed)
493
+ self.x += self.vx
494
+ if self.on_platform and self.platform_span is not None:
495
+ span_left, span_right = self.platform_span
496
+ self.x = min(max(self.x, span_left), span_right - self.width)
497
+ self.y = float(self.ground_feet - self.height)
498
+ else:
499
+ self.x = min(max(self.x, float(left)), float(right - self.width))
500
+ self.y = float(floor_y)
501
+ return int(self.x), int(self.y)
502
+
440
503
  def _platform_under(self) -> Optional[Tuple[float, float]]:
441
504
  """回傳目前站立平台的水平範圍;平台已消失(視窗移走/關閉)則回傳 None。"""
442
505
  body_left = self.x
@@ -637,6 +700,9 @@ class DesktopPetWidget(BaseWidget):
637
700
  self._peers_provider = None
638
701
  self._peer_greeted = False
639
702
  self._peer_tick = 0
703
+ # 電量提醒 / Low-battery reaction
704
+ self._battery_provider = read_battery
705
+ self._battery_warned = False
640
706
  self._bubble = SpeechBubble()
641
707
  self._chatter_timer = QTimer(self)
642
708
  self._chatter_timer.setSingleShot(True)
@@ -651,6 +717,8 @@ class DesktopPetWidget(BaseWidget):
651
717
  self.menu.addAction(self.close_action)
652
718
 
653
719
  MEET_DISTANCE = 90.0
720
+ PLAY_RANGE = 320.0
721
+ PLAY_CHANCE = 0.25
654
722
 
655
723
  def set_pet_window_flag(self) -> None:
656
724
  """寵物需接收滑鼠以便拖曳,故 allow_input=True 並置頂。"""
@@ -664,8 +732,8 @@ class DesktopPetWidget(BaseWidget):
664
732
  self._peers_provider = provider
665
733
 
666
734
  def _check_peers(self) -> None:
667
- """靠近其他寵物時轉向並打招呼(帶遲滯,避免重複)。"""
668
- if self._peers_provider is None or not self._talk:
735
+ """靠近其他寵物時走過去玩耍、抵達後轉向打招呼(帶遲滯,避免重複)。"""
736
+ if self._peers_provider is None:
669
737
  return
670
738
  try:
671
739
  peers = self._peers_provider()
@@ -675,9 +743,19 @@ class DesktopPetWidget(BaseWidget):
675
743
  peer, distance = nearest_peer(my_center, peers)
676
744
  if peer is None:
677
745
  self._peer_greeted = False
746
+ self.motion.clear_follow()
678
747
  return
748
+ # play: a floor pet may walk over to a near-ish peer
749
+ if self.motion.behaviour == BEHAVIOUR_FLOOR:
750
+ if self.MEET_DISTANCE < distance <= self.PLAY_RANGE:
751
+ if self.motion.follow_target_x is not None or self._chatter_rng.random() < self.PLAY_CHANCE:
752
+ self.motion.set_follow(peer[0])
753
+ elif distance > self.PLAY_RANGE:
754
+ self.motion.clear_follow()
755
+ # greet: face and say a meet line once per approach
679
756
  if distance <= self.MEET_DISTANCE:
680
- if not self._peer_greeted:
757
+ self.motion.clear_follow()
758
+ if self._talk and not self._peer_greeted:
681
759
  self._peer_greeted = True
682
760
  self.motion.vx = abs(self.motion.vx) if peer[0] >= my_center[0] else -abs(self.motion.vx)
683
761
  pool = self._messages.get("meet") or []
@@ -766,6 +844,7 @@ class DesktopPetWidget(BaseWidget):
766
844
  "happy": lines("pet_chatter_happy", "I'm so happy!|You're the best!|(^o^)"),
767
845
  "sad": lines("pet_chatter_sad", "Feeling a bit lonely...|Pet me?|(._.)"),
768
846
  "meet": lines("pet_chatter_meet", "Hi friend!|Hello!|Let's play!"),
847
+ "battery": lines("pet_chatter_battery", "Battery's low - plug me in?|Low power!|Find a charger?"),
769
848
  "any": lines("pet_chatter_any", "Hi there!|(^_^)|Keep going!"),
770
849
  }
771
850
 
@@ -800,9 +879,31 @@ class DesktopPetWidget(BaseWidget):
800
879
  def _on_chatter(self) -> None:
801
880
  self._mood.decay() # a little neglect over time
802
881
  self._persist_mood()
803
- self.say()
882
+ if not self._warn_battery(): # a low-battery warning takes priority
883
+ self.say()
804
884
  self._schedule_chatter()
805
885
 
886
+ BATTERY_THRESHOLD = 20
887
+
888
+ def _warn_battery(self) -> bool:
889
+ """低電量時提醒一次;充電或回升後重置。回傳是否有發出提醒。"""
890
+ if not self._talk:
891
+ return False
892
+ status = self._battery_provider()
893
+ if status is None:
894
+ return False
895
+ percent, charging = status
896
+ if not charging and percent <= self.BATTERY_THRESHOLD:
897
+ if not self._battery_warned:
898
+ self._battery_warned = True
899
+ pool = self._messages.get("battery") or []
900
+ if pool:
901
+ self.say(pool[self._chatter_rng.randrange(len(pool))])
902
+ return True
903
+ elif charging or percent > self.BATTERY_THRESHOLD + 10:
904
+ self._battery_warned = False
905
+ return False
906
+
806
907
  def say(self, text: Optional[str] = None) -> None:
807
908
  """顯示一句台詞(text 為 None 時依心情/時段隨機挑)。"""
808
909
  if not self._talk:
@@ -844,6 +945,7 @@ class DesktopPetWidget(BaseWidget):
844
945
  self._last_move_delta = (0, 0)
845
946
  self._drag_offset = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
846
947
  self.motion.wake() # interacting wakes a sleeping pet
948
+ self.motion.clear_follow()
847
949
  self._mood.pet() # petting cheers it up
848
950
  self._persist_mood()
849
951
  self._play_sound()
@@ -238,6 +238,7 @@ english_word_dict = {
238
238
  "pet_chatter_happy": "I'm so happy!|You're the best!|(^o^)/|Best day ever!",
239
239
  "pet_chatter_sad": "Feeling a bit lonely...|Pet me?|(._.)|Don't forget about me~",
240
240
  "pet_chatter_meet": "Hi friend!|Hello there!|Let's play!|Fancy meeting you here!",
241
+ "pet_chatter_battery": "Battery's low - plug me in?|Low power, careful!|Find a charger soon?|Running on fumes here~",
241
242
  "pet_start": "Spawn pet",
242
243
  "pet_message_box_text": "Pet image not found",
243
244
  }
@@ -239,6 +239,7 @@ traditional_chinese_word_dict = {
239
239
  "pet_chatter_happy": "我好開心!|你最棒了!|(^o^)/|今天真美好!",
240
240
  "pet_chatter_sad": "有點寂寞…|摸摸我好嗎?|(._.)|別忘了我~",
241
241
  "pet_chatter_meet": "嗨朋友!|你好呀!|一起玩吧!|在這遇到你真巧!",
242
+ "pet_chatter_battery": "電量很低,幫我插電好嗎?|快沒電了,小心!|該找充電器囉?|我快撐不住了~",
242
243
  "pet_start": "召喚寵物",
243
244
  "pet_message_box_text": "找不到寵物圖片",
244
245
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.11
3
+ Version: 1.0.13
4
4
  Summary: FrontEngine is use-define frontview or only use like screen saver
5
5
  Author-email: JE-Chen <jechenmailman@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/Intergration-Automation-Testing/FrontEngine
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "frontengine"
9
- version = "1.0.11"
9
+ version = "1.0.13"
10
10
  authors = [
11
11
  { name = "JE-Chen", email = "jechenmailman@gmail.com" },
12
12
  ]
File without changes
File without changes
File without changes