frontengine 1.0.12__tar.gz → 1.0.14__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.12 → frontengine-1.0.14}/PKG-INFO +1 -1
  2. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/pet/desktop_pet.py +114 -2
  3. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/multi_language/english.py +4 -0
  4. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/multi_language/traditional_chinese.py +4 -0
  5. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine.egg-info/PKG-INFO +1 -1
  6. {frontengine-1.0.12 → frontengine-1.0.14}/pyproject.toml +1 -1
  7. {frontengine-1.0.12 → frontengine-1.0.14}/LICENSE +0 -0
  8. {frontengine-1.0.12 → frontengine-1.0.14}/README.md +0 -0
  9. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/__init__.py +0 -0
  10. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/__main__.py +0 -0
  11. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/__init__.py +0 -0
  12. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/base_widget.py +0 -0
  13. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/gif/__init__.py +0 -0
  14. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/gif/paint_gif.py +0 -0
  15. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/image/__init__.py +0 -0
  16. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/image/paint_image.py +0 -0
  17. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/load/__init__.py +0 -0
  18. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/load/load_someone_make_ui.py +0 -0
  19. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/overlay_factory.py +0 -0
  20. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/particle/__init__.py +0 -0
  21. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/particle/particle_ui.py +0 -0
  22. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/pet/__init__.py +0 -0
  23. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/scene/__init__.py +0 -0
  24. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/scene/extend_graphic_scene.py +0 -0
  25. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/scene/extend_graphic_view.py +0 -0
  26. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/scene/scene.py +0 -0
  27. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/sound_player/__init__.py +0 -0
  28. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/sound_player/sound_effect.py +0 -0
  29. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/sound_player/sound_player.py +0 -0
  30. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/text/__init__.py +0 -0
  31. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/text/draw_text.py +0 -0
  32. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/video/__init__.py +0 -0
  33. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/video/video_player.py +0 -0
  34. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/web/__init__.py +0 -0
  35. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/web/webview.py +0 -0
  36. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/show/window_helpers.py +0 -0
  37. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/system_tray/__init__.py +0 -0
  38. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/system_tray/extend_system_tray.py +0 -0
  39. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/__init__.py +0 -0
  40. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/color/__init__.py +0 -0
  41. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/color/global_color.py +0 -0
  42. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/dialog/__init__.py +0 -0
  43. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
  44. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
  45. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/dialog/save_file_dialog.py +0 -0
  46. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/main_ui.py +0 -0
  47. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/menu/__init__.py +0 -0
  48. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/menu/help_menu.py +0 -0
  49. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/menu/how_to_menu.py +0 -0
  50. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/menu/language_menu.py +0 -0
  51. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/menu/preset_menu.py +0 -0
  52. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/menu/settings_menu.py +0 -0
  53. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/__init__.py +0 -0
  54. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/control_center/__init__.py +0 -0
  55. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/control_center/control_center_ui.py +0 -0
  56. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/gif/__init__.py +0 -0
  57. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
  58. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/image/__init__.py +0 -0
  59. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/image/image_setting_ui.py +0 -0
  60. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/particle/__init__.py +0 -0
  61. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
  62. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/pet/__init__.py +0 -0
  63. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/pet/pet_setting_ui.py +0 -0
  64. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/__init__.py +0 -0
  65. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
  66. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/scene_page/__init__.py +0 -0
  67. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
  68. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
  69. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
  70. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
  71. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
  72. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
  73. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
  74. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
  75. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
  76. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/sound_player/__init__.py +0 -0
  77. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
  78. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/text/__init__.py +0 -0
  79. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/text/text_setting_ui.py +0 -0
  80. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/utils.py +0 -0
  81. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/video/__init__.py +0 -0
  82. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/video/video_setting_ui.py +0 -0
  83. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/web/__init__.py +0 -0
  84. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/ui/page/web/web_setting_ui.py +0 -0
  85. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/user_setting/__init__.py +0 -0
  86. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/user_setting/preset_repository.py +0 -0
  87. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/user_setting/scene_setting.py +0 -0
  88. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/user_setting/user_setting_file.py +0 -0
  89. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/__init__.py +0 -0
  90. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/browser/__init__.py +0 -0
  91. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/browser/browser.py +0 -0
  92. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/critical_exit/__init__.py +0 -0
  93. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
  94. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/critical_exit/critical_exit.py +0 -0
  95. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/critical_exit/win32_vk.py +0 -0
  96. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/exception/__init__.py +0 -0
  97. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/exception/exception_tags.py +0 -0
  98. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/exception/exceptions.py +0 -0
  99. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/file/__init__.py +0 -0
  100. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/file/open/__init__.py +0 -0
  101. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/file/open/open_file.py +0 -0
  102. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/file/save/__init__.py +0 -0
  103. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/file/save/save_file.py +0 -0
  104. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/hotkey/__init__.py +0 -0
  105. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/hotkey/hotkey_service.py +0 -0
  106. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/json/__init__.py +0 -0
  107. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/json/json_file.py +0 -0
  108. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/json/json_repository.py +0 -0
  109. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/json_format/__init__.py +0 -0
  110. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/json_format/json_process.py +0 -0
  111. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/logging/__init__.py +0 -0
  112. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/logging/loggin_instance.py +0 -0
  113. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/multi_language/__init__.py +0 -0
  114. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/multi_language/france.py +0 -0
  115. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/multi_language/germany.py +0 -0
  116. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/multi_language/italy.py +0 -0
  117. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/multi_language/language_wrapper.py +0 -0
  118. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/multi_language/russian.py +0 -0
  119. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
  120. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/preset_schedule/__init__.py +0 -0
  121. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
  122. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/redirect_manager/__init__.py +0 -0
  123. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
  124. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/smart_pause/__init__.py +0 -0
  125. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
  126. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/theme_schedule/__init__.py +0 -0
  127. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
  128. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/utils/web_url.py +0 -0
  129. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/worker/__init__.py +0 -0
  130. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine/worker/qthread_worker.py +0 -0
  131. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine.egg-info/SOURCES.txt +0 -0
  132. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine.egg-info/dependency_links.txt +0 -0
  133. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine.egg-info/entry_points.txt +0 -0
  134. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine.egg-info/requires.txt +0 -0
  135. {frontengine-1.0.12 → frontengine-1.0.14}/frontengine.egg-info/top_level.txt +0 -0
  136. {frontengine-1.0.12 → frontengine-1.0.14}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.12
3
+ Version: 1.0.14
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
@@ -1,6 +1,6 @@
1
1
  import random as _random_module
2
2
  import sys
3
- from datetime import datetime
3
+ from datetime import datetime, timedelta
4
4
  from pathlib import Path
5
5
  from typing import Optional, Tuple
6
6
 
@@ -144,6 +144,49 @@ def windows_platforms(exclude_hwnds=()) -> list:
144
144
  return []
145
145
 
146
146
 
147
+ def pop_due_reminders(now, reminders):
148
+ """
149
+ 依 now 分出已到期與未到期的提醒。reminders 為 (due_datetime, text) 清單。
150
+ Split reminders into (due, remaining) at `now`. Each reminder is a
151
+ (due_datetime, text) tuple.
152
+ """
153
+ due = [item for item in reminders if item[0] <= now]
154
+ remaining = [item for item in reminders if item[0] > now]
155
+ return due, remaining
156
+
157
+
158
+ def read_battery():
159
+ """
160
+ 回傳 (電量百分比, 是否充電中);無法取得時回傳 None。僅 Windows 實作。
161
+ Return (percent, charging) or None when unavailable. Windows only.
162
+ """
163
+ if sys.platform != "win32":
164
+ return None
165
+ try:
166
+ import ctypes
167
+
168
+ class _SPS(ctypes.Structure):
169
+ _fields_ = [
170
+ ("ACLineStatus", ctypes.c_byte),
171
+ ("BatteryFlag", ctypes.c_byte),
172
+ ("BatteryLifePercent", ctypes.c_byte),
173
+ ("SystemStatusFlag", ctypes.c_byte),
174
+ ("BatteryLifeTime", ctypes.c_ulong),
175
+ ("BatteryFullLifeTime", ctypes.c_ulong),
176
+ ]
177
+
178
+ status = _SPS()
179
+ if not ctypes.windll.kernel32.GetSystemPowerStatus(ctypes.byref(status)):
180
+ return None
181
+ percent = status.BatteryLifePercent & 0xFF
182
+ if percent == 255: # unknown / no battery
183
+ return None
184
+ return (int(percent), status.ACLineStatus == 1)
185
+ except Exception as error: # pragma: no cover - Win32 boundary
186
+ front_engine_logger.warning(f"[read_battery] error: {error!r}")
187
+ return None
188
+
189
+
147
190
  def nearest_peer(center, peers):
148
191
  """
149
192
  回傳離 center 最近的同伴座標與距離;無同伴回傳 (None, inf)。
@@ -668,6 +711,14 @@ class DesktopPetWidget(BaseWidget):
668
711
  self._peers_provider = None
669
712
  self._peer_greeted = False
670
713
  self._peer_tick = 0
714
+ # 電量提醒 / Low-battery reaction
715
+ self._battery_provider = read_battery
716
+ self._battery_warned = False
717
+ # 提醒事項 / Reminders
718
+ self._now_provider = datetime.now
719
+ self._reminders: list = []
720
+ self._reminder_timer = QTimer(self)
721
+ self._reminder_timer.timeout.connect(self._check_reminders)
671
722
  self._bubble = SpeechBubble()
672
723
  self._chatter_timer = QTimer(self)
673
724
  self._chatter_timer.setSingleShot(True)
@@ -677,6 +728,10 @@ class DesktopPetWidget(BaseWidget):
677
728
  self.clone_action = QAction(language_wrapper.language_word_dict.get("pet_clone", "Clone"), self)
678
729
  self.clone_action.triggered.connect(self.clone_requested.emit)
679
730
  self.menu.addAction(self.clone_action)
731
+ self.reminder_action = QAction(
732
+ language_wrapper.language_word_dict.get("pet_set_reminder", "Set reminder..."), self)
733
+ self.reminder_action.triggered.connect(self._prompt_reminder)
734
+ self.menu.addAction(self.reminder_action)
680
735
  self.close_action = QAction(language_wrapper.language_word_dict.get("control_center_close_all", "Close"), self)
681
736
  self.close_action.triggered.connect(self.close)
682
737
  self.menu.addAction(self.close_action)
@@ -794,6 +849,7 @@ class DesktopPetWidget(BaseWidget):
794
849
  self.move(int(self.motion.x), int(self.motion.y))
795
850
  self._timer.start(max(10, int(interval_ms)))
796
851
  self._schedule_chatter()
852
+ self._reminder_timer.start(10000)
797
853
 
798
854
  def _load_messages(self) -> dict:
799
855
  d = language_wrapper.language_word_dict
@@ -809,12 +865,44 @@ class DesktopPetWidget(BaseWidget):
809
865
  "happy": lines("pet_chatter_happy", "I'm so happy!|You're the best!|(^o^)"),
810
866
  "sad": lines("pet_chatter_sad", "Feeling a bit lonely...|Pet me?|(._.)"),
811
867
  "meet": lines("pet_chatter_meet", "Hi friend!|Hello!|Let's play!"),
868
+ "battery": lines("pet_chatter_battery", "Battery's low - plug me in?|Low power!|Find a charger?"),
812
869
  "any": lines("pet_chatter_any", "Hi there!|(^_^)|Keep going!"),
813
870
  }
814
871
 
815
872
  def _persist_mood(self) -> None:
816
873
  user_setting_dict["pet_mood"] = self._mood.value
817
874
 
875
+ def add_reminder(self, text: str, minutes: int) -> None:
876
+ """在 minutes 分鐘後提醒 text / Remind `text` in `minutes` minutes."""
877
+ due = self._now_provider() + timedelta(minutes=max(1, int(minutes)))
878
+ self._reminders.append((due, str(text)))
879
+ front_engine_logger.info(f"[DesktopPetWidget] reminder set | due={due}, text={text}")
880
+
881
+ def _check_reminders(self) -> None:
882
+ if not self._reminders:
883
+ return
884
+ due, remaining = pop_due_reminders(self._now_provider(), self._reminders)
885
+ self._reminders = remaining
886
+ if due:
887
+ # Reminders are explicit user requests: deliver even if chatter is off.
888
+ self._bubble.show_message(due[-1][1], self, duration_ms=12000)
889
+ self._play_sound()
890
+
891
+ def _prompt_reminder(self) -> None:
892
+ from PySide6.QtWidgets import QInputDialog
893
+
894
+ title = language_wrapper.language_word_dict.get("pet_set_reminder", "Set reminder...")
895
+ text, ok = QInputDialog.getText(
896
+ self, title, language_wrapper.language_word_dict.get("pet_reminder_prompt", "Remind me to:"))
897
+ if not ok or not text.strip():
898
+ return
899
+ minutes, ok_minutes = QInputDialog.getInt(
900
+ self, title, language_wrapper.language_word_dict.get("pet_reminder_minutes", "In how many minutes?"),
901
+ 5, 1, 1440)
902
+ if not ok_minutes:
903
+ return
904
+ self.add_reminder(text.strip(), minutes)
905
+
818
906
  def _init_sound(self, sound_path: Optional[str]) -> None:
819
907
  if not sound_path:
820
908
  return
@@ -843,9 +931,31 @@ class DesktopPetWidget(BaseWidget):
843
931
  def _on_chatter(self) -> None:
844
932
  self._mood.decay() # a little neglect over time
845
933
  self._persist_mood()
846
- self.say()
934
+ if not self._warn_battery(): # a low-battery warning takes priority
935
+ self.say()
847
936
  self._schedule_chatter()
848
937
 
938
+ BATTERY_THRESHOLD = 20
939
+
940
+ def _warn_battery(self) -> bool:
941
+ """低電量時提醒一次;充電或回升後重置。回傳是否有發出提醒。"""
942
+ if not self._talk:
943
+ return False
944
+ status = self._battery_provider()
945
+ if status is None:
946
+ return False
947
+ percent, charging = status
948
+ if not charging and percent <= self.BATTERY_THRESHOLD:
949
+ if not self._battery_warned:
950
+ self._battery_warned = True
951
+ pool = self._messages.get("battery") or []
952
+ if pool:
953
+ self.say(pool[self._chatter_rng.randrange(len(pool))])
954
+ return True
955
+ elif charging or percent > self.BATTERY_THRESHOLD + 10:
956
+ self._battery_warned = False
957
+ return False
958
+
849
959
  def say(self, text: Optional[str] = None) -> None:
850
960
  """顯示一句台詞(text 為 None 時依心情/時段隨機挑)。"""
851
961
  if not self._talk:
@@ -923,6 +1033,8 @@ class DesktopPetWidget(BaseWidget):
923
1033
  self._timer.stop()
924
1034
  if self._chatter_timer.isActive():
925
1035
  self._chatter_timer.stop()
1036
+ if self._reminder_timer.isActive():
1037
+ self._reminder_timer.stop()
926
1038
  self._bubble.close()
927
1039
  for kind, obj in self._sprites.values():
928
1040
  if kind == "movie":
@@ -225,6 +225,9 @@ english_word_dict = {
225
225
  "pet_behaviour_chase": "Chase cursor",
226
226
  "pet_climb_label": "Climb walls",
227
227
  "pet_clone": "Clone",
228
+ "pet_set_reminder": "Set reminder...",
229
+ "pet_reminder_prompt": "Remind me to:",
230
+ "pet_reminder_minutes": "In how many minutes?",
228
231
  "pet_choose_pack": "Choose pet pack...",
229
232
  "pet_choose_sound": "Choose sound (optional)",
230
233
  "pet_pack_empty": "No sprites (walk/idle/sleep/climb/fall/drag) found in that folder.",
@@ -238,6 +241,7 @@ english_word_dict = {
238
241
  "pet_chatter_happy": "I'm so happy!|You're the best!|(^o^)/|Best day ever!",
239
242
  "pet_chatter_sad": "Feeling a bit lonely...|Pet me?|(._.)|Don't forget about me~",
240
243
  "pet_chatter_meet": "Hi friend!|Hello there!|Let's play!|Fancy meeting you here!",
244
+ "pet_chatter_battery": "Battery's low - plug me in?|Low power, careful!|Find a charger soon?|Running on fumes here~",
241
245
  "pet_start": "Spawn pet",
242
246
  "pet_message_box_text": "Pet image not found",
243
247
  }
@@ -226,6 +226,9 @@ traditional_chinese_word_dict = {
226
226
  "pet_behaviour_chase": "追逐游標",
227
227
  "pet_climb_label": "攀爬牆壁",
228
228
  "pet_clone": "複製",
229
+ "pet_set_reminder": "設定提醒...",
230
+ "pet_reminder_prompt": "提醒我:",
231
+ "pet_reminder_minutes": "幾分鐘後?",
229
232
  "pet_choose_pack": "選擇動作包資料夾...",
230
233
  "pet_choose_sound": "選擇音效(選填)",
231
234
  "pet_pack_empty": "該資料夾找不到精靈檔(walk/idle/sleep/climb/fall/drag)。",
@@ -239,6 +242,7 @@ traditional_chinese_word_dict = {
239
242
  "pet_chatter_happy": "我好開心!|你最棒了!|(^o^)/|今天真美好!",
240
243
  "pet_chatter_sad": "有點寂寞…|摸摸我好嗎?|(._.)|別忘了我~",
241
244
  "pet_chatter_meet": "嗨朋友!|你好呀!|一起玩吧!|在這遇到你真巧!",
245
+ "pet_chatter_battery": "電量很低,幫我插電好嗎?|快沒電了,小心!|該找充電器囉?|我快撐不住了~",
242
246
  "pet_start": "召喚寵物",
243
247
  "pet_message_box_text": "找不到寵物圖片",
244
248
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.12
3
+ Version: 1.0.14
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.12"
9
+ version = "1.0.14"
10
10
  authors = [
11
11
  { name = "JE-Chen", email = "jechenmailman@gmail.com" },
12
12
  ]
File without changes
File without changes
File without changes