frontengine 1.0.13__tar.gz → 1.0.15__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.13 → frontengine-1.0.15}/PKG-INFO +1 -1
  2. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/pet/desktop_pet.py +128 -2
  3. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/user_setting/user_setting_file.py +3 -0
  4. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/multi_language/english.py +6 -0
  5. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/multi_language/traditional_chinese.py +6 -0
  6. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine.egg-info/PKG-INFO +1 -1
  7. {frontengine-1.0.13 → frontengine-1.0.15}/pyproject.toml +1 -1
  8. {frontengine-1.0.13 → frontengine-1.0.15}/LICENSE +0 -0
  9. {frontengine-1.0.13 → frontengine-1.0.15}/README.md +0 -0
  10. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/__init__.py +0 -0
  11. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/__main__.py +0 -0
  12. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/__init__.py +0 -0
  13. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/base_widget.py +0 -0
  14. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/gif/__init__.py +0 -0
  15. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/gif/paint_gif.py +0 -0
  16. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/image/__init__.py +0 -0
  17. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/image/paint_image.py +0 -0
  18. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/load/__init__.py +0 -0
  19. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/load/load_someone_make_ui.py +0 -0
  20. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/overlay_factory.py +0 -0
  21. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/particle/__init__.py +0 -0
  22. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/particle/particle_ui.py +0 -0
  23. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/pet/__init__.py +0 -0
  24. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/scene/__init__.py +0 -0
  25. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/scene/extend_graphic_scene.py +0 -0
  26. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/scene/extend_graphic_view.py +0 -0
  27. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/scene/scene.py +0 -0
  28. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/sound_player/__init__.py +0 -0
  29. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/sound_player/sound_effect.py +0 -0
  30. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/sound_player/sound_player.py +0 -0
  31. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/text/__init__.py +0 -0
  32. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/text/draw_text.py +0 -0
  33. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/video/__init__.py +0 -0
  34. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/video/video_player.py +0 -0
  35. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/web/__init__.py +0 -0
  36. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/web/webview.py +0 -0
  37. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/show/window_helpers.py +0 -0
  38. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/system_tray/__init__.py +0 -0
  39. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/system_tray/extend_system_tray.py +0 -0
  40. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/__init__.py +0 -0
  41. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/color/__init__.py +0 -0
  42. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/color/global_color.py +0 -0
  43. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/dialog/__init__.py +0 -0
  44. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
  45. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
  46. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/dialog/save_file_dialog.py +0 -0
  47. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/main_ui.py +0 -0
  48. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/menu/__init__.py +0 -0
  49. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/menu/help_menu.py +0 -0
  50. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/menu/how_to_menu.py +0 -0
  51. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/menu/language_menu.py +0 -0
  52. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/menu/preset_menu.py +0 -0
  53. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/menu/settings_menu.py +0 -0
  54. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/__init__.py +0 -0
  55. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/control_center/__init__.py +0 -0
  56. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/control_center/control_center_ui.py +0 -0
  57. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/gif/__init__.py +0 -0
  58. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
  59. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/image/__init__.py +0 -0
  60. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/image/image_setting_ui.py +0 -0
  61. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/particle/__init__.py +0 -0
  62. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
  63. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/pet/__init__.py +0 -0
  64. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/pet/pet_setting_ui.py +0 -0
  65. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/__init__.py +0 -0
  66. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
  67. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/scene_page/__init__.py +0 -0
  68. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
  69. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
  70. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
  71. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
  72. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
  73. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
  74. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
  75. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
  76. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
  77. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/sound_player/__init__.py +0 -0
  78. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
  79. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/text/__init__.py +0 -0
  80. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/text/text_setting_ui.py +0 -0
  81. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/utils.py +0 -0
  82. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/video/__init__.py +0 -0
  83. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/video/video_setting_ui.py +0 -0
  84. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/web/__init__.py +0 -0
  85. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/ui/page/web/web_setting_ui.py +0 -0
  86. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/user_setting/__init__.py +0 -0
  87. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/user_setting/preset_repository.py +0 -0
  88. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/user_setting/scene_setting.py +0 -0
  89. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/__init__.py +0 -0
  90. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/browser/__init__.py +0 -0
  91. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/browser/browser.py +0 -0
  92. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/critical_exit/__init__.py +0 -0
  93. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
  94. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/critical_exit/critical_exit.py +0 -0
  95. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/critical_exit/win32_vk.py +0 -0
  96. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/exception/__init__.py +0 -0
  97. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/exception/exception_tags.py +0 -0
  98. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/exception/exceptions.py +0 -0
  99. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/file/__init__.py +0 -0
  100. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/file/open/__init__.py +0 -0
  101. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/file/open/open_file.py +0 -0
  102. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/file/save/__init__.py +0 -0
  103. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/file/save/save_file.py +0 -0
  104. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/hotkey/__init__.py +0 -0
  105. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/hotkey/hotkey_service.py +0 -0
  106. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/json/__init__.py +0 -0
  107. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/json/json_file.py +0 -0
  108. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/json/json_repository.py +0 -0
  109. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/json_format/__init__.py +0 -0
  110. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/json_format/json_process.py +0 -0
  111. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/logging/__init__.py +0 -0
  112. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/logging/loggin_instance.py +0 -0
  113. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/multi_language/__init__.py +0 -0
  114. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/multi_language/france.py +0 -0
  115. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/multi_language/germany.py +0 -0
  116. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/multi_language/italy.py +0 -0
  117. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/multi_language/language_wrapper.py +0 -0
  118. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/multi_language/russian.py +0 -0
  119. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
  120. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/preset_schedule/__init__.py +0 -0
  121. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
  122. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/redirect_manager/__init__.py +0 -0
  123. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
  124. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/smart_pause/__init__.py +0 -0
  125. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
  126. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/theme_schedule/__init__.py +0 -0
  127. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
  128. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/utils/web_url.py +0 -0
  129. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/worker/__init__.py +0 -0
  130. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine/worker/qthread_worker.py +0 -0
  131. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine.egg-info/SOURCES.txt +0 -0
  132. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine.egg-info/dependency_links.txt +0 -0
  133. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine.egg-info/entry_points.txt +0 -0
  134. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine.egg-info/requires.txt +0 -0
  135. {frontengine-1.0.13 → frontengine-1.0.15}/frontengine.egg-info/top_level.txt +0 -0
  136. {frontengine-1.0.13 → frontengine-1.0.15}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.13
3
+ Version: 1.0.15
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,17 @@ 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
+
147
158
  def read_battery():
148
159
  """
149
160
  回傳 (電量百分比, 是否充電中);無法取得時回傳 None。僅 Windows 實作。
@@ -255,6 +266,40 @@ class PetMood:
255
266
  return self.CONTENT
256
267
 
257
268
 
269
+ class PetHunger:
270
+ """
271
+ 寵物飽足值 0~100:餵食上升、隨時間下降;level() 回傳 full/ok/hungry。
272
+ Pet fullness 0..100: feeding raises it, time lowers it; level() buckets it.
273
+ """
274
+
275
+ FULL = "full"
276
+ OK = "ok"
277
+ HUNGRY = "hungry"
278
+
279
+ def __init__(self, value: int = 70) -> None:
280
+ self.value = self._clamp(value)
281
+
282
+ @staticmethod
283
+ def _clamp(value) -> int:
284
+ try:
285
+ return max(0, min(100, int(value)))
286
+ except (TypeError, ValueError):
287
+ return 70
288
+
289
+ def feed(self, amount: int = 30) -> None:
290
+ self.value = self._clamp(self.value + amount)
291
+
292
+ def decay(self, amount: int = 1) -> None:
293
+ self.value = self._clamp(self.value - amount)
294
+
295
+ def level(self) -> str:
296
+ if self.value >= 60:
297
+ return self.FULL
298
+ if self.value <= 25:
299
+ return self.HUNGRY
300
+ return self.OK
301
+
302
+
258
303
  class SpeechBubble(QWidget):
259
304
  """寵物頭上的小對話泡泡,數秒後自動消失 / A small speech bubble that auto-hides."""
260
305
 
@@ -691,6 +736,8 @@ class DesktopPetWidget(BaseWidget):
691
736
  self._moved = False
692
737
  self._chatter_rng = _random_module.SystemRandom()
693
738
  self._mood = PetMood(user_setting_dict.get("pet_mood", 60))
739
+ self._hunger = PetHunger(user_setting_dict.get("pet_hunger", 70))
740
+ self._hunger_warned = False
694
741
  self._messages = self._load_messages()
695
742
  self._sound: Optional[QSoundEffect] = None
696
743
  self._init_sound(sound_path)
@@ -703,6 +750,11 @@ class DesktopPetWidget(BaseWidget):
703
750
  # 電量提醒 / Low-battery reaction
704
751
  self._battery_provider = read_battery
705
752
  self._battery_warned = False
753
+ # 提醒事項 / Reminders
754
+ self._now_provider = datetime.now
755
+ self._reminders: list = []
756
+ self._reminder_timer = QTimer(self)
757
+ self._reminder_timer.timeout.connect(self._check_reminders)
706
758
  self._bubble = SpeechBubble()
707
759
  self._chatter_timer = QTimer(self)
708
760
  self._chatter_timer.setSingleShot(True)
@@ -712,6 +764,13 @@ class DesktopPetWidget(BaseWidget):
712
764
  self.clone_action = QAction(language_wrapper.language_word_dict.get("pet_clone", "Clone"), self)
713
765
  self.clone_action.triggered.connect(self.clone_requested.emit)
714
766
  self.menu.addAction(self.clone_action)
767
+ self.feed_action = QAction(language_wrapper.language_word_dict.get("pet_feed", "Feed"), self)
768
+ self.feed_action.triggered.connect(self.feed)
769
+ self.menu.addAction(self.feed_action)
770
+ self.reminder_action = QAction(
771
+ language_wrapper.language_word_dict.get("pet_set_reminder", "Set reminder..."), self)
772
+ self.reminder_action.triggered.connect(self._prompt_reminder)
773
+ self.menu.addAction(self.reminder_action)
715
774
  self.close_action = QAction(language_wrapper.language_word_dict.get("control_center_close_all", "Close"), self)
716
775
  self.close_action.triggered.connect(self.close)
717
776
  self.menu.addAction(self.close_action)
@@ -829,6 +888,7 @@ class DesktopPetWidget(BaseWidget):
829
888
  self.move(int(self.motion.x), int(self.motion.y))
830
889
  self._timer.start(max(10, int(interval_ms)))
831
890
  self._schedule_chatter()
891
+ self._reminder_timer.start(10000)
832
892
 
833
893
  def _load_messages(self) -> dict:
834
894
  d = language_wrapper.language_word_dict
@@ -845,12 +905,45 @@ class DesktopPetWidget(BaseWidget):
845
905
  "sad": lines("pet_chatter_sad", "Feeling a bit lonely...|Pet me?|(._.)"),
846
906
  "meet": lines("pet_chatter_meet", "Hi friend!|Hello!|Let's play!"),
847
907
  "battery": lines("pet_chatter_battery", "Battery's low - plug me in?|Low power!|Find a charger?"),
908
+ "hungry": lines("pet_chatter_hungry", "I'm hungry...|Got a snack?|Feed me?"),
909
+ "fed": lines("pet_chatter_fed", "Yum!|Thank you!|Delicious!"),
848
910
  "any": lines("pet_chatter_any", "Hi there!|(^_^)|Keep going!"),
849
911
  }
850
912
 
851
913
  def _persist_mood(self) -> None:
852
914
  user_setting_dict["pet_mood"] = self._mood.value
853
915
 
916
+ def add_reminder(self, text: str, minutes: int) -> None:
917
+ """在 minutes 分鐘後提醒 text / Remind `text` in `minutes` minutes."""
918
+ due = self._now_provider() + timedelta(minutes=max(1, int(minutes)))
919
+ self._reminders.append((due, str(text)))
920
+ front_engine_logger.info(f"[DesktopPetWidget] reminder set | due={due}, text={text}")
921
+
922
+ def _check_reminders(self) -> None:
923
+ if not self._reminders:
924
+ return
925
+ due, remaining = pop_due_reminders(self._now_provider(), self._reminders)
926
+ self._reminders = remaining
927
+ if due:
928
+ # Reminders are explicit user requests: deliver even if chatter is off.
929
+ self._bubble.show_message(due[-1][1], self, duration_ms=12000)
930
+ self._play_sound()
931
+
932
+ def _prompt_reminder(self) -> None:
933
+ from PySide6.QtWidgets import QInputDialog
934
+
935
+ title = language_wrapper.language_word_dict.get("pet_set_reminder", "Set reminder...")
936
+ text, ok = QInputDialog.getText(
937
+ self, title, language_wrapper.language_word_dict.get("pet_reminder_prompt", "Remind me to:"))
938
+ if not ok or not text.strip():
939
+ return
940
+ minutes, ok_minutes = QInputDialog.getInt(
941
+ self, title, language_wrapper.language_word_dict.get("pet_reminder_minutes", "In how many minutes?"),
942
+ 5, 1, 1440)
943
+ if not ok_minutes:
944
+ return
945
+ self.add_reminder(text.strip(), minutes)
946
+
854
947
  def _init_sound(self, sound_path: Optional[str]) -> None:
855
948
  if not sound_path:
856
949
  return
@@ -878,11 +971,42 @@ class DesktopPetWidget(BaseWidget):
878
971
 
879
972
  def _on_chatter(self) -> None:
880
973
  self._mood.decay() # a little neglect over time
974
+ self._hunger.decay()
881
975
  self._persist_mood()
882
- if not self._warn_battery(): # a low-battery warning takes priority
976
+ # priority: low battery, then hunger, otherwise normal chatter
977
+ if not self._warn_battery() and not self._warn_hungry():
883
978
  self.say()
884
979
  self._schedule_chatter()
885
980
 
981
+ def _persist_hunger(self) -> None:
982
+ user_setting_dict["pet_hunger"] = self._hunger.value
983
+
984
+ def feed(self) -> None:
985
+ """餵食:補足飽足並讓心情變好,說一句道謝。"""
986
+ self._hunger.feed()
987
+ self._mood.pet()
988
+ self._persist_hunger()
989
+ self._persist_mood()
990
+ pool = self._messages.get("fed") or []
991
+ if pool:
992
+ self.say(pool[self._chatter_rng.randrange(len(pool))])
993
+
994
+ def _warn_hungry(self) -> bool:
995
+ """飢餓時討食一次;吃飽後重置。回傳是否有討食。"""
996
+ self._persist_hunger()
997
+ if not self._talk:
998
+ return False
999
+ if self._hunger.level() == PetHunger.HUNGRY:
1000
+ if not self._hunger_warned:
1001
+ self._hunger_warned = True
1002
+ pool = self._messages.get("hungry") or []
1003
+ if pool:
1004
+ self.say(pool[self._chatter_rng.randrange(len(pool))])
1005
+ return True
1006
+ elif self._hunger.level() == PetHunger.FULL:
1007
+ self._hunger_warned = False
1008
+ return False
1009
+
886
1010
  BATTERY_THRESHOLD = 20
887
1011
 
888
1012
  def _warn_battery(self) -> bool:
@@ -981,6 +1105,8 @@ class DesktopPetWidget(BaseWidget):
981
1105
  self._timer.stop()
982
1106
  if self._chatter_timer.isActive():
983
1107
  self._chatter_timer.stop()
1108
+ if self._reminder_timer.isActive():
1109
+ self._reminder_timer.stop()
984
1110
  self._bubble.close()
985
1111
  for kind, obj in self._sprites.values():
986
1112
  if kind == "movie":
@@ -36,6 +36,9 @@ user_setting_dict: Dict[str, Any] = {
36
36
  # 桌面寵物心情值(0~100),跨工作階段保存
37
37
  # Desktop pet mood (0..100), persisted across sessions
38
38
  "pet_mood": 60,
39
+ # 桌面寵物飽足值(0~100)
40
+ # Desktop pet fullness (0..100)
41
+ "pet_hunger": 70,
39
42
  }
40
43
 
41
44
 
@@ -225,6 +225,12 @@ english_word_dict = {
225
225
  "pet_behaviour_chase": "Chase cursor",
226
226
  "pet_climb_label": "Climb walls",
227
227
  "pet_clone": "Clone",
228
+ "pet_feed": "Feed",
229
+ "pet_chatter_hungry": "I'm hungry...|Got a snack?|Feed me, please?|My tummy's rumbling~",
230
+ "pet_chatter_fed": "Yum!|Thank you!|Delicious!|Nom nom (^o^)",
231
+ "pet_set_reminder": "Set reminder...",
232
+ "pet_reminder_prompt": "Remind me to:",
233
+ "pet_reminder_minutes": "In how many minutes?",
228
234
  "pet_choose_pack": "Choose pet pack...",
229
235
  "pet_choose_sound": "Choose sound (optional)",
230
236
  "pet_pack_empty": "No sprites (walk/idle/sleep/climb/fall/drag) found in that folder.",
@@ -226,6 +226,12 @@ traditional_chinese_word_dict = {
226
226
  "pet_behaviour_chase": "追逐游標",
227
227
  "pet_climb_label": "攀爬牆壁",
228
228
  "pet_clone": "複製",
229
+ "pet_feed": "餵食",
230
+ "pet_chatter_hungry": "我餓了…|有點心嗎?|餵餵我好嗎?|肚子咕咕叫~",
231
+ "pet_chatter_fed": "好吃!|謝謝你!|真美味!|嗯嗯 (^o^)",
232
+ "pet_set_reminder": "設定提醒...",
233
+ "pet_reminder_prompt": "提醒我:",
234
+ "pet_reminder_minutes": "幾分鐘後?",
229
235
  "pet_choose_pack": "選擇動作包資料夾...",
230
236
  "pet_choose_sound": "選擇音效(選填)",
231
237
  "pet_pack_empty": "該資料夾找不到精靈檔(walk/idle/sleep/climb/fall/drag)。",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.13
3
+ Version: 1.0.15
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.13"
9
+ version = "1.0.15"
10
10
  authors = [
11
11
  { name = "JE-Chen", email = "jechenmailman@gmail.com" },
12
12
  ]
File without changes
File without changes
File without changes