frontengine 1.0.34__tar.gz → 1.0.35__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.
- {frontengine-1.0.34 → frontengine-1.0.35}/PKG-INFO +1 -1
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/base_widget.py +25 -0
- frontengine-1.0.35/frontengine/show/toast/toast_widget.py +120 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/wallpaper/wallpaper_widget.py +16 -2
- frontengine-1.0.35/frontengine/ui/dialog/app_profile_dialog.py +115 -0
- frontengine-1.0.35/frontengine/ui/dialog/reminder_dialog.py +139 -0
- frontengine-1.0.35/frontengine/ui/dialog/smart_pause_dialog.py +87 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/main_ui.py +79 -9
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/menu/settings_menu.py +37 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/control_center/control_center_ui.py +68 -3
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/wallpaper/wallpaper_setting_ui.py +110 -24
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/user_setting/user_setting_file.py +12 -0
- frontengine-1.0.35/frontengine/utils/app_profile/app_profile_service.py +102 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/multi_language/english.py +30 -1
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/multi_language/traditional_chinese.py +30 -2
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/platform_info/platform_info.py +85 -0
- frontengine-1.0.35/frontengine/utils/power_mode/power_mode.py +72 -0
- frontengine-1.0.35/frontengine/utils/reminder/reminder_service.py +181 -0
- frontengine-1.0.35/frontengine/utils/smart_pause/pause_rules.py +104 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/smart_pause/smart_pause_service.py +64 -9
- frontengine-1.0.35/frontengine/utils/weather/__init__.py +0 -0
- frontengine-1.0.35/frontengine/utils/workshop/__init__.py +0 -0
- frontengine-1.0.35/frontengine/worker/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine.egg-info/PKG-INFO +1 -1
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine.egg-info/SOURCES.txt +10 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/pyproject.toml +1 -1
- frontengine-1.0.34/frontengine/utils/power_mode/power_mode.py +0 -29
- {frontengine-1.0.34 → frontengine-1.0.35}/LICENSE +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/README.md +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/__main__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/focus_shield/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/focus_shield/focus_shield_widget.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/gif/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/gif/paint_gif.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/image/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/image/paint_image.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/load/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/load/load_someone_make_ui.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/overlay_factory.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/particle/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/particle/particle_ui.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/pet/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/pet/desktop_pet.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/presentation/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/presentation/annotation_overlay.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/presentation/cursor_effects.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/presentation/keystroke_display.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/presentation/magnifier.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/scene/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/scene/extend_graphic_scene.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/scene/extend_graphic_view.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/scene/scene.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/screen_care/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/screen_care/screen_filter.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/sound_player/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/sound_player/sound_effect.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/sound_player/sound_player.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/text/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/text/draw_text.py +0 -0
- {frontengine-1.0.34/frontengine/show/video → frontengine-1.0.35/frontengine/show/toast}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/show/wallpaper → frontengine-1.0.35/frontengine/show/video}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/video/video_player.py +0 -0
- {frontengine-1.0.34/frontengine/show/web → frontengine-1.0.35/frontengine/show/wallpaper}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/system_tray → frontengine-1.0.35/frontengine/show/web}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/web/webview.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/show/window_helpers.py +0 -0
- {frontengine-1.0.34/frontengine/ui → frontengine-1.0.35/frontengine/system_tray}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/system_tray/extend_system_tray.py +0 -0
- {frontengine-1.0.34/frontengine/ui/color → frontengine-1.0.35/frontengine/ui}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/ui/dialog → frontengine-1.0.35/frontengine/ui/color}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/color/global_color.py +0 -0
- {frontengine-1.0.34/frontengine/ui/menu → frontengine-1.0.35/frontengine/ui/dialog}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/dialog/save_file_dialog.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page → frontengine-1.0.35/frontengine/ui/menu}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/menu/help_menu.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/menu/how_to_menu.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/menu/language_menu.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/menu/preset_menu.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/control_center → frontengine-1.0.35/frontengine/ui/page}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/focus → frontengine-1.0.35/frontengine/ui/page/control_center}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/gif → frontengine-1.0.35/frontengine/ui/page/focus}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/focus/focus_setting_ui.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/image → frontengine-1.0.35/frontengine/ui/page/gif}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/particle → frontengine-1.0.35/frontengine/ui/page/image}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/image/image_setting_ui.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/pet → frontengine-1.0.35/frontengine/ui/page/particle}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/presentation → frontengine-1.0.35/frontengine/ui/page/pet}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/pet/pet_setting_ui.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/scene_setting → frontengine-1.0.35/frontengine/ui/page/presentation}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/presentation/presentation_setting_ui.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/scene_setting/scene_page → frontengine-1.0.35/frontengine/ui/page/scene_setting}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/screen_care → frontengine-1.0.35/frontengine/ui/page/scene_setting/scene_page}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/sound_player → frontengine-1.0.35/frontengine/ui/page/screen_care}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/screen_care/screen_care_setting_ui.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/text → frontengine-1.0.35/frontengine/ui/page/sound_player}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/video → frontengine-1.0.35/frontengine/ui/page/text}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/text/text_setting_ui.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/utils.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/wallpaper → frontengine-1.0.35/frontengine/ui/page/video}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/video/video_setting_ui.py +0 -0
- {frontengine-1.0.34/frontengine/ui/page/web → frontengine-1.0.35/frontengine/ui/page/wallpaper}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/user_setting → frontengine-1.0.35/frontengine/ui/page/web}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/ui/page/web/web_setting_ui.py +0 -0
- {frontengine-1.0.34/frontengine/utils → frontengine-1.0.35/frontengine/user_setting}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/user_setting/preset_repository.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/user_setting/scene_setting.py +0 -0
- {frontengine-1.0.34/frontengine/utils/audio_meter → frontengine-1.0.35/frontengine/utils}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/utils/autostart → frontengine-1.0.35/frontengine/utils/app_profile}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/utils/break_reminder → frontengine-1.0.35/frontengine/utils/audio_meter}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/audio_meter/audio_envelope.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/audio_meter/screen_audio.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/audio_meter/system_audio_meter.py +0 -0
- {frontengine-1.0.34/frontengine/utils/browser → frontengine-1.0.35/frontengine/utils/autostart}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/autostart/autostart_service.py +0 -0
- {frontengine-1.0.34/frontengine/utils/critical_exit → frontengine-1.0.35/frontengine/utils/break_reminder}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/break_reminder/break_reminder.py +0 -0
- {frontengine-1.0.34/frontengine/utils/file → frontengine-1.0.35/frontengine/utils/browser}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/browser/browser.py +0 -0
- {frontengine-1.0.34/frontengine/utils/focus_shield → frontengine-1.0.35/frontengine/utils/critical_exit}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/critical_exit/critical_exit.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/critical_exit/win32_vk.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/exception/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/exception/exception_tags.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/exception/exceptions.py +0 -0
- {frontengine-1.0.34/frontengine/utils/focus_timer → frontengine-1.0.35/frontengine/utils/file}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/file/open/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/file/open/open_file.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/file/save/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/file/save/save_file.py +0 -0
- {frontengine-1.0.34/frontengine/utils/hotkey → frontengine-1.0.35/frontengine/utils/focus_shield}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/focus_shield/focus_shield.py +0 -0
- {frontengine-1.0.34/frontengine/utils/input_watch → frontengine-1.0.35/frontengine/utils/focus_timer}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/focus_timer/focus_timer.py +0 -0
- {frontengine-1.0.34/frontengine/utils/json → frontengine-1.0.35/frontengine/utils/hotkey}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/hotkey/hotkey_service.py +0 -0
- {frontengine-1.0.34/frontengine/utils/logging → frontengine-1.0.35/frontengine/utils/input_watch}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/input_watch/input_watch_service.py +0 -0
- {frontengine-1.0.34/frontengine/utils/multi_language → frontengine-1.0.35/frontengine/utils/json}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/json/json_file.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/json/json_repository.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/json_format/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/json_format/json_process.py +0 -0
- {frontengine-1.0.34/frontengine/utils/pet_chat → frontengine-1.0.35/frontengine/utils/logging}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/logging/loggin_instance.py +0 -0
- {frontengine-1.0.34/frontengine/utils/platform_info → frontengine-1.0.35/frontengine/utils/multi_language}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/multi_language/france.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/multi_language/germany.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/multi_language/italy.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/multi_language/language_wrapper.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/multi_language/russian.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
- {frontengine-1.0.34/frontengine/utils/playlist → frontengine-1.0.35/frontengine/utils/pet_chat}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/pet_chat/pet_chat_service.py +0 -0
- {frontengine-1.0.34/frontengine/utils/plugins → frontengine-1.0.35/frontengine/utils/platform_info}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/utils/power_mode → frontengine-1.0.35/frontengine/utils/playlist}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/playlist/playlist.py +0 -0
- {frontengine-1.0.34/frontengine/utils/preset_schedule → frontengine-1.0.35/frontengine/utils/plugins}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/plugins/plugin_loader.py +0 -0
- {frontengine-1.0.34/frontengine/utils/redirect_manager → frontengine-1.0.35/frontengine/utils/power_mode}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/utils/smart_pause → frontengine-1.0.35/frontengine/utils/preset_schedule}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
- {frontengine-1.0.34/frontengine/utils/system_stats → frontengine-1.0.35/frontengine/utils/redirect_manager}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
- {frontengine-1.0.34/frontengine/utils/text_source → frontengine-1.0.35/frontengine/utils/reminder}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/utils/theme_schedule → frontengine-1.0.35/frontengine/utils/smart_pause}/__init__.py +0 -0
- {frontengine-1.0.34/frontengine/utils/weather → frontengine-1.0.35/frontengine/utils/system_stats}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/system_stats/system_stats.py +0 -0
- {frontengine-1.0.34/frontengine/utils/workshop → frontengine-1.0.35/frontengine/utils/text_source}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/text_source/text_source.py +0 -0
- {frontengine-1.0.34/frontengine/worker → frontengine-1.0.35/frontengine/utils/theme_schedule}/__init__.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/weather/weather_service.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/web_url.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/utils/workshop/workshop_content.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine/worker/qthread_worker.py +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine.egg-info/dependency_links.txt +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine.egg-info/entry_points.txt +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine.egg-info/requires.txt +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/frontengine.egg-info/top_level.txt +0 -0
- {frontengine-1.0.34 → frontengine-1.0.35}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: frontengine
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.35
|
|
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
|
|
@@ -8,6 +8,7 @@ from PySide6.QtWidgets import QWidget
|
|
|
8
8
|
from frontengine.show.window_helpers import apply_overlay_window_flags, load_overlay_icon
|
|
9
9
|
from frontengine.user_setting.user_setting_file import get_overlay_geometry, save_overlay_geometry
|
|
10
10
|
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
11
|
+
from frontengine.utils.power_mode.power_mode import DEFAULT_TIER, normalize_tier, tier_render_scale
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class BaseWidget(QWidget):
|
|
@@ -29,6 +30,9 @@ class BaseWidget(QWidget):
|
|
|
29
30
|
# 綠幕背景色:設了就以不透明色填滿背景,方便 OBS 去背
|
|
30
31
|
# Chroma key colour: fills the background opaquely so OBS can key it out.
|
|
31
32
|
self.background_color: Optional[QColor] = None
|
|
33
|
+
# 畫質檔位:影響更新頻率上限與算圖縮放(見 utils/power_mode)
|
|
34
|
+
# Quality tier: caps the refresh rate and scales rendering (see utils/power_mode).
|
|
35
|
+
self.quality_tier: str = DEFAULT_TIER
|
|
32
36
|
self._drag_origin = None
|
|
33
37
|
self._geometry_restored = False
|
|
34
38
|
|
|
@@ -44,6 +48,27 @@ class BaseWidget(QWidget):
|
|
|
44
48
|
front_engine_logger.info(f"{self.__class__.__name__} set_ui_variable | opacity: {opacity}")
|
|
45
49
|
self.opacity = opacity
|
|
46
50
|
|
|
51
|
+
def set_quality_tier(self, tier: str) -> None:
|
|
52
|
+
"""
|
|
53
|
+
設定畫質檔位。基底類別只記下來並通知子類別,實際怎麼省由子類別決定
|
|
54
|
+
(例如放慢自己的計時器、用較低解析度算圖)。
|
|
55
|
+
Set the quality tier. The base class records it and tells the subclass;
|
|
56
|
+
what to actually give up - timer rate, render resolution - is the
|
|
57
|
+
subclass's call.
|
|
58
|
+
"""
|
|
59
|
+
self.quality_tier = normalize_tier(tier)
|
|
60
|
+
front_engine_logger.info(
|
|
61
|
+
f"{self.__class__.__name__} set_quality_tier | tier: {self.quality_tier}")
|
|
62
|
+
self.apply_quality_tier()
|
|
63
|
+
self.update()
|
|
64
|
+
|
|
65
|
+
def apply_quality_tier(self) -> None:
|
|
66
|
+
"""子類別覆寫這裡,把新的檔位套到自己的計時器/算圖上。"""
|
|
67
|
+
|
|
68
|
+
def render_scale(self) -> float:
|
|
69
|
+
"""目前檔位的算圖縮放,1.0 表示原生解析度。"""
|
|
70
|
+
return tier_render_scale(self.quality_tier)
|
|
71
|
+
|
|
47
72
|
def set_background_color(self, color) -> None:
|
|
48
73
|
"""
|
|
49
74
|
設定綠幕背景色(傳 None 取消)。背景以不透明色填滿,內容再依原本的
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""
|
|
2
|
+
提示卡:在畫面上方短暫顯示一行字(提醒到期、規則觸發等),時間到自己關掉。
|
|
3
|
+
點擊穿透,不會擋到底下的操作。
|
|
4
|
+
|
|
5
|
+
A toast: a line of text shown briefly near the top of the screen - a reminder
|
|
6
|
+
coming due, a rule firing - that closes itself. Click-through, so it never gets
|
|
7
|
+
in the way of what is underneath.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Optional
|
|
12
|
+
|
|
13
|
+
from PySide6.QtCore import Qt, QTimer
|
|
14
|
+
from PySide6.QtGui import QColor, QFont, QFontMetrics, QGuiApplication, QPainter
|
|
15
|
+
|
|
16
|
+
from frontengine.show.base_widget import BaseWidget
|
|
17
|
+
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
18
|
+
|
|
19
|
+
DEFAULT_DURATION_MS = 5000
|
|
20
|
+
MIN_DURATION_MS = 500
|
|
21
|
+
_PADDING = 18
|
|
22
|
+
_CORNER_RADIUS = 10
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def clamp_duration(value, fallback: int = DEFAULT_DURATION_MS) -> int:
|
|
26
|
+
"""顯示時間至少半秒,避免設成 0 讓提示閃一下就不見。"""
|
|
27
|
+
try:
|
|
28
|
+
return max(MIN_DURATION_MS, int(value))
|
|
29
|
+
except (TypeError, ValueError):
|
|
30
|
+
return fallback
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ToastWidget(BaseWidget):
|
|
34
|
+
"""
|
|
35
|
+
一張自動消失的提示卡。文字寬度決定卡片寬度,位置預設貼在主螢幕上方置中。
|
|
36
|
+
An auto-dismissing toast. The card is sized to its text and sits centred
|
|
37
|
+
near the top of the primary screen by default.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, message: str = "", duration_ms: int = DEFAULT_DURATION_MS,
|
|
41
|
+
font_size: int = 18) -> None:
|
|
42
|
+
front_engine_logger.info(f"[ToastWidget] Init | message={message!r}")
|
|
43
|
+
super().__init__()
|
|
44
|
+
self.message: str = str(message)
|
|
45
|
+
self.duration_ms: int = clamp_duration(duration_ms)
|
|
46
|
+
self.text_color = QColor("#ffffff")
|
|
47
|
+
self.card_color = QColor(20, 20, 20, 230)
|
|
48
|
+
self.opacity = 1.0
|
|
49
|
+
# 提示卡不該被拖曳擺位,也不接受點擊
|
|
50
|
+
# A toast is never dragged into place and never takes clicks.
|
|
51
|
+
self.overlay_lockable = False
|
|
52
|
+
self._font = QFont()
|
|
53
|
+
self._font.setPointSize(max(8, int(font_size)))
|
|
54
|
+
self._close_timer = QTimer(self)
|
|
55
|
+
self._close_timer.setSingleShot(True)
|
|
56
|
+
self._close_timer.timeout.connect(self.close)
|
|
57
|
+
self.set_ui_window_flag(show_on_bottom=False)
|
|
58
|
+
self.resize_to_message()
|
|
59
|
+
|
|
60
|
+
def set_message(self, message: str) -> None:
|
|
61
|
+
"""換一則訊息並重新計算卡片大小。"""
|
|
62
|
+
self.message = str(message)
|
|
63
|
+
self.resize_to_message()
|
|
64
|
+
self.update()
|
|
65
|
+
|
|
66
|
+
def card_size(self) -> tuple:
|
|
67
|
+
"""依文字算出卡片的寬高(含內距)。"""
|
|
68
|
+
metrics = QFontMetrics(self._font)
|
|
69
|
+
width = metrics.horizontalAdvance(self.message) + _PADDING * 2
|
|
70
|
+
height = metrics.height() + _PADDING
|
|
71
|
+
return (max(80, width), max(36, height))
|
|
72
|
+
|
|
73
|
+
def resize_to_message(self) -> None:
|
|
74
|
+
width, height = self.card_size()
|
|
75
|
+
self.resize(width, height)
|
|
76
|
+
self.move_to_top_centre()
|
|
77
|
+
|
|
78
|
+
def move_to_top_centre(self, screen=None) -> None:
|
|
79
|
+
"""擺到螢幕上方置中(離頂端一小段距離,避開全螢幕程式的標題列)。"""
|
|
80
|
+
target = screen or QGuiApplication.primaryScreen()
|
|
81
|
+
if target is None: # pragma: no cover - no screen at all
|
|
82
|
+
return
|
|
83
|
+
available = target.availableGeometry()
|
|
84
|
+
self.move(
|
|
85
|
+
available.x() + (available.width() - self.width()) // 2,
|
|
86
|
+
available.y() + max(24, available.height() // 12),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
def show_toast(self, screen=None) -> None:
|
|
90
|
+
"""顯示並在時間到時自動關閉。"""
|
|
91
|
+
self.resize_to_message()
|
|
92
|
+
self.move_to_top_centre(screen)
|
|
93
|
+
self.show()
|
|
94
|
+
self._close_timer.start(self.duration_ms)
|
|
95
|
+
|
|
96
|
+
def draw_content(self, painter: QPainter) -> None:
|
|
97
|
+
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
|
|
98
|
+
painter.setPen(Qt.PenStyle.NoPen)
|
|
99
|
+
painter.setBrush(self.card_color)
|
|
100
|
+
painter.drawRoundedRect(self.rect(), _CORNER_RADIUS, _CORNER_RADIUS)
|
|
101
|
+
painter.setFont(self._font)
|
|
102
|
+
painter.setPen(self.text_color)
|
|
103
|
+
painter.drawText(self.rect(), Qt.AlignmentFlag.AlignCenter, self.message)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def show_toast(message: str, duration_ms: int = DEFAULT_DURATION_MS,
|
|
107
|
+
screen=None) -> Optional[ToastWidget]:
|
|
108
|
+
"""
|
|
109
|
+
顯示一則提示卡並回傳它(訊息為空就不顯示,回傳 None)。呼叫端不必自己
|
|
110
|
+
管生命週期:時間到會自己 close,而 BaseWidget 帶著 WA_DeleteOnClose。
|
|
111
|
+
Show a toast and hand it back (None for an empty message). Callers do not
|
|
112
|
+
have to manage its life: it closes itself, and BaseWidget carries
|
|
113
|
+
WA_DeleteOnClose.
|
|
114
|
+
"""
|
|
115
|
+
text = str(message or "").strip()
|
|
116
|
+
if not text:
|
|
117
|
+
return None
|
|
118
|
+
toast = ToastWidget(text, duration_ms)
|
|
119
|
+
toast.show_toast(screen)
|
|
120
|
+
return toast
|
|
@@ -13,12 +13,13 @@ from __future__ import annotations
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import Optional
|
|
15
15
|
|
|
16
|
-
from PySide6.QtCore import QRect, QTimer
|
|
16
|
+
from PySide6.QtCore import QRect, Qt, QTimer
|
|
17
17
|
from PySide6.QtGui import QMovie, QPainter, QPixmap
|
|
18
18
|
|
|
19
19
|
from frontengine.show.base_widget import BaseWidget
|
|
20
20
|
from frontengine.utils.audio_meter.audio_envelope import AudioEnvelope
|
|
21
21
|
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
22
|
+
from frontengine.utils.power_mode.power_mode import tier_interval
|
|
22
23
|
|
|
23
24
|
_ANIMATED_SUFFIXES = (".gif", ".webp")
|
|
24
25
|
MIN_REACT_SCALE = 1.0
|
|
@@ -105,12 +106,17 @@ class WallpaperWidget(BaseWidget):
|
|
|
105
106
|
if strength is not None:
|
|
106
107
|
self.react_strength = max(0, min(100, int(strength)))
|
|
107
108
|
if self.audio_react:
|
|
108
|
-
self._react_timer.start(self.REACT_INTERVAL_MS)
|
|
109
|
+
self._react_timer.start(tier_interval(self.REACT_INTERVAL_MS, self.quality_tier))
|
|
109
110
|
else:
|
|
110
111
|
self._react_timer.stop()
|
|
111
112
|
self.scale = MIN_REACT_SCALE
|
|
112
113
|
self.update()
|
|
113
114
|
|
|
115
|
+
def apply_quality_tier(self) -> None:
|
|
116
|
+
"""畫質檔位改變時,跟著調整脈動的更新頻率(算圖縮放在繪製時套用)。"""
|
|
117
|
+
if self._react_timer.isActive():
|
|
118
|
+
self._react_timer.start(tier_interval(self.REACT_INTERVAL_MS, self.quality_tier))
|
|
119
|
+
|
|
114
120
|
def _update_scale(self) -> None:
|
|
115
121
|
"""取一次音量、平滑後換成縮放比例。"""
|
|
116
122
|
if not self.audio_react or self._level_provider is None:
|
|
@@ -141,6 +147,14 @@ class WallpaperWidget(BaseWidget):
|
|
|
141
147
|
pixmap = self.current_pixmap()
|
|
142
148
|
if pixmap is None or pixmap.isNull():
|
|
143
149
|
return
|
|
150
|
+
# 低畫質檔位先把來源縮小再放大回來:算的像素少,看起來只是稍軟。
|
|
151
|
+
# Lower tiers shrink the source before scaling it back up: fewer pixels
|
|
152
|
+
# to push, at the cost of a slightly softer picture.
|
|
153
|
+
scale = self.render_scale()
|
|
154
|
+
if scale < 1.0:
|
|
155
|
+
pixmap = pixmap.scaled(
|
|
156
|
+
max(1, int(pixmap.width() * scale)), max(1, int(pixmap.height() * scale)),
|
|
157
|
+
Qt.AspectRatioMode.IgnoreAspectRatio, Qt.TransformationMode.FastTransformation)
|
|
144
158
|
width = int(self.width() * self.scale)
|
|
145
159
|
height = int(self.height() * self.scale)
|
|
146
160
|
# 放大時往外溢出,維持置中,畫面才不會出現黑邊
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""
|
|
2
|
+
程式對應預設集:切到某個程式時自動套用一組覆蓋層設定(例如打開剪輯軟體
|
|
3
|
+
就換成「工作」那組)。左欄填程式名稱,右欄挑一個已儲存的預設集。
|
|
4
|
+
|
|
5
|
+
Per-app profiles: apply a saved preset when a given app takes focus - the
|
|
6
|
+
"work" set when the editor comes up. The left column is the app name, the right
|
|
7
|
+
column picks one of your saved presets.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Dict, Optional
|
|
12
|
+
|
|
13
|
+
from PySide6.QtWidgets import (
|
|
14
|
+
QAbstractItemView, QComboBox, QDialog, QDialogButtonBox, QGridLayout, QLabel, QPushButton,
|
|
15
|
+
QTableWidget, QTableWidgetItem, QWidget,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from frontengine.user_setting.preset_repository import PresetRepository
|
|
19
|
+
from frontengine.user_setting.user_setting_file import user_setting_dict, write_user_setting
|
|
20
|
+
from frontengine.utils.app_profile.app_profile_service import normalize_profiles
|
|
21
|
+
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
22
|
+
from frontengine.utils.multi_language.language_wrapper import language_wrapper
|
|
23
|
+
from frontengine.utils.smart_pause.pause_rules import normalize_app_name
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _t(key: str, fallback: str) -> str:
|
|
27
|
+
return language_wrapper.language_word_dict.get(key, fallback)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def current_profiles() -> Dict[str, str]:
|
|
31
|
+
"""目前設定裡的 {程式: 預設集} 對照表。"""
|
|
32
|
+
return normalize_profiles(user_setting_dict.get("app_profiles"))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class AppProfileDialog(QDialog):
|
|
36
|
+
"""編輯「程式 → 預設集」對照表。"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, parent: Optional[QWidget] = None) -> None:
|
|
39
|
+
front_engine_logger.info("[AppProfileDialog] Init")
|
|
40
|
+
super().__init__(parent)
|
|
41
|
+
self.setWindowTitle(_t("app_profile_title", "App profiles"))
|
|
42
|
+
self.presets = PresetRepository().list_presets()
|
|
43
|
+
|
|
44
|
+
self.table = QTableWidget(0, 2)
|
|
45
|
+
self.table.setHorizontalHeaderLabels([
|
|
46
|
+
_t("app_profile_app_column", "Application"),
|
|
47
|
+
_t("app_profile_preset_column", "Preset"),
|
|
48
|
+
])
|
|
49
|
+
self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
|
50
|
+
self.table.horizontalHeader().setStretchLastSection(True)
|
|
51
|
+
|
|
52
|
+
self.add_button = QPushButton(_t("app_profile_add", "Add"))
|
|
53
|
+
self.add_button.clicked.connect(lambda: self.add_row("", ""))
|
|
54
|
+
self.remove_button = QPushButton(_t("app_profile_remove", "Remove"))
|
|
55
|
+
self.remove_button.clicked.connect(self.remove_selected_row)
|
|
56
|
+
self.hint_label = QLabel(
|
|
57
|
+
_t("app_profile_hint",
|
|
58
|
+
"Presets are saved from the Presets menu. Without any saved preset "
|
|
59
|
+
"there is nothing to apply."))
|
|
60
|
+
self.hint_label.setWordWrap(True)
|
|
61
|
+
|
|
62
|
+
self.button_box = QDialogButtonBox(
|
|
63
|
+
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
|
|
64
|
+
self.button_box.accepted.connect(self.accept)
|
|
65
|
+
self.button_box.rejected.connect(self.reject)
|
|
66
|
+
|
|
67
|
+
layout = QGridLayout(self)
|
|
68
|
+
layout.addWidget(self.table, 0, 0, 1, 2)
|
|
69
|
+
layout.addWidget(self.add_button, 1, 0)
|
|
70
|
+
layout.addWidget(self.remove_button, 1, 1)
|
|
71
|
+
layout.addWidget(self.hint_label, 2, 0, 1, 2)
|
|
72
|
+
layout.addWidget(self.button_box, 3, 0, 1, 2)
|
|
73
|
+
|
|
74
|
+
for app, preset in current_profiles().items():
|
|
75
|
+
self.add_row(app, preset)
|
|
76
|
+
|
|
77
|
+
def add_row(self, app: str = "", preset: str = "") -> None:
|
|
78
|
+
"""加一列(預設集下拉選單列出所有已儲存的預設集)。"""
|
|
79
|
+
row = self.table.rowCount()
|
|
80
|
+
self.table.insertRow(row)
|
|
81
|
+
self.table.setItem(row, 0, QTableWidgetItem(str(app)))
|
|
82
|
+
combobox = QComboBox()
|
|
83
|
+
combobox.addItems(self.presets)
|
|
84
|
+
# 設定裡指到已被刪掉的預設集時,仍把名稱留著讓使用者看得到
|
|
85
|
+
# Keep a name that points at a deleted preset visible instead of silently
|
|
86
|
+
# swapping it for another one.
|
|
87
|
+
if preset and preset not in self.presets:
|
|
88
|
+
combobox.addItem(str(preset))
|
|
89
|
+
if preset:
|
|
90
|
+
combobox.setCurrentText(str(preset))
|
|
91
|
+
self.table.setCellWidget(row, 1, combobox)
|
|
92
|
+
|
|
93
|
+
def remove_selected_row(self) -> None:
|
|
94
|
+
row = self.table.currentRow()
|
|
95
|
+
if row >= 0:
|
|
96
|
+
self.table.removeRow(row)
|
|
97
|
+
|
|
98
|
+
def profiles(self) -> Dict[str, str]:
|
|
99
|
+
"""目前表格上的對照表(空白列會被略過)。"""
|
|
100
|
+
profiles: Dict[str, str] = {}
|
|
101
|
+
for row in range(self.table.rowCount()):
|
|
102
|
+
item = self.table.item(row, 0)
|
|
103
|
+
combobox = self.table.cellWidget(row, 1)
|
|
104
|
+
app = normalize_app_name(item.text() if item else "")
|
|
105
|
+
preset = combobox.currentText().strip() if combobox else ""
|
|
106
|
+
if app and preset:
|
|
107
|
+
profiles[app] = preset
|
|
108
|
+
return profiles
|
|
109
|
+
|
|
110
|
+
def accept(self) -> None:
|
|
111
|
+
profiles = self.profiles()
|
|
112
|
+
user_setting_dict["app_profiles"] = profiles
|
|
113
|
+
write_user_setting()
|
|
114
|
+
front_engine_logger.info(f"[AppProfileDialog] saved | {profiles}")
|
|
115
|
+
super().accept()
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""
|
|
2
|
+
自訂提醒設定:每隔一段時間提醒一次(喝水、起來走走),或每天在固定時間
|
|
3
|
+
提醒一次(會議、吃藥)。提醒會以畫面上方的提示卡顯示。
|
|
4
|
+
|
|
5
|
+
Custom reminder settings: every N minutes (drink water, stand up) or once a day
|
|
6
|
+
at a set time (a meeting, a pill). Reminders appear as a toast near the top of
|
|
7
|
+
the screen.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Any, Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
from PySide6.QtCore import Qt
|
|
14
|
+
from PySide6.QtWidgets import (
|
|
15
|
+
QAbstractItemView, QComboBox, QDialog, QDialogButtonBox, QGridLayout, QLabel, QPushButton,
|
|
16
|
+
QTableWidget, QTableWidgetItem, QWidget,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from frontengine.user_setting.user_setting_file import user_setting_dict, write_user_setting
|
|
20
|
+
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
21
|
+
from frontengine.utils.multi_language.language_wrapper import language_wrapper
|
|
22
|
+
from frontengine.utils.reminder.reminder_service import (
|
|
23
|
+
KIND_AT, KIND_EVERY, normalize_reminder, normalize_reminders,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
_COLUMN_LABEL = 0
|
|
27
|
+
_COLUMN_KIND = 1
|
|
28
|
+
_COLUMN_VALUE = 2
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _t(key: str, fallback: str) -> str:
|
|
32
|
+
return language_wrapper.language_word_dict.get(key, fallback)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def current_reminders() -> List[Dict[str, Any]]:
|
|
36
|
+
"""目前設定裡的提醒清單(壞掉的項目會被跳過)。"""
|
|
37
|
+
return normalize_reminders(user_setting_dict.get("reminders"))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ReminderDialog(QDialog):
|
|
41
|
+
"""編輯自訂提醒清單。"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, parent: Optional[QWidget] = None) -> None:
|
|
44
|
+
front_engine_logger.info("[ReminderDialog] Init")
|
|
45
|
+
super().__init__(parent)
|
|
46
|
+
self.setWindowTitle(_t("reminder_title", "Reminders"))
|
|
47
|
+
|
|
48
|
+
self.table = QTableWidget(0, 3)
|
|
49
|
+
self.table.setHorizontalHeaderLabels([
|
|
50
|
+
_t("reminder_label_column", "Reminder"),
|
|
51
|
+
_t("reminder_kind_column", "When"),
|
|
52
|
+
_t("reminder_value_column", "Minutes / time"),
|
|
53
|
+
])
|
|
54
|
+
self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
|
55
|
+
self.table.horizontalHeader().setStretchLastSection(True)
|
|
56
|
+
|
|
57
|
+
self.add_button = QPushButton(_t("reminder_add", "Add"))
|
|
58
|
+
self.add_button.clicked.connect(lambda: self.add_row())
|
|
59
|
+
self.remove_button = QPushButton(_t("reminder_remove", "Remove"))
|
|
60
|
+
self.remove_button.clicked.connect(self.remove_selected_row)
|
|
61
|
+
self.hint_label = QLabel(
|
|
62
|
+
_t("reminder_hint",
|
|
63
|
+
"Tick a row to keep it active. \"Every\" takes minutes, \"At\" takes a "
|
|
64
|
+
"24-hour time such as 14:30."))
|
|
65
|
+
self.hint_label.setWordWrap(True)
|
|
66
|
+
|
|
67
|
+
self.button_box = QDialogButtonBox(
|
|
68
|
+
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
|
|
69
|
+
self.button_box.accepted.connect(self.accept)
|
|
70
|
+
self.button_box.rejected.connect(self.reject)
|
|
71
|
+
|
|
72
|
+
layout = QGridLayout(self)
|
|
73
|
+
layout.addWidget(self.table, 0, 0, 1, 2)
|
|
74
|
+
layout.addWidget(self.add_button, 1, 0)
|
|
75
|
+
layout.addWidget(self.remove_button, 1, 1)
|
|
76
|
+
layout.addWidget(self.hint_label, 2, 0, 1, 2)
|
|
77
|
+
layout.addWidget(self.button_box, 3, 0, 1, 2)
|
|
78
|
+
|
|
79
|
+
for reminder in current_reminders():
|
|
80
|
+
self.add_row(reminder)
|
|
81
|
+
|
|
82
|
+
def add_row(self, reminder: Optional[Dict[str, Any]] = None) -> None:
|
|
83
|
+
"""加一列;沒給資料就給一筆空白的「每 45 分鐘」。"""
|
|
84
|
+
entry = reminder or {"label": "", "kind": KIND_EVERY, "minutes": 45, "enabled": True}
|
|
85
|
+
row = self.table.rowCount()
|
|
86
|
+
self.table.insertRow(row)
|
|
87
|
+
|
|
88
|
+
label_item = QTableWidgetItem(str(entry.get("label", "")))
|
|
89
|
+
label_item.setFlags(label_item.flags() | Qt.ItemFlag.ItemIsUserCheckable)
|
|
90
|
+
label_item.setCheckState(Qt.CheckState.Checked if entry.get("enabled", True)
|
|
91
|
+
else Qt.CheckState.Unchecked)
|
|
92
|
+
self.table.setItem(row, _COLUMN_LABEL, label_item)
|
|
93
|
+
|
|
94
|
+
kind_combobox = QComboBox()
|
|
95
|
+
kind_combobox.addItem(_t("reminder_kind_every", "Every"), KIND_EVERY)
|
|
96
|
+
kind_combobox.addItem(_t("reminder_kind_at", "At"), KIND_AT)
|
|
97
|
+
kind_index = kind_combobox.findData(entry.get("kind", KIND_EVERY))
|
|
98
|
+
kind_combobox.setCurrentIndex(max(0, kind_index))
|
|
99
|
+
self.table.setCellWidget(row, _COLUMN_KIND, kind_combobox)
|
|
100
|
+
|
|
101
|
+
value = entry.get("at") if entry.get("kind") == KIND_AT else entry.get("minutes", 45)
|
|
102
|
+
self.table.setItem(row, _COLUMN_VALUE, QTableWidgetItem(str(value)))
|
|
103
|
+
|
|
104
|
+
def remove_selected_row(self) -> None:
|
|
105
|
+
row = self.table.currentRow()
|
|
106
|
+
if row >= 0:
|
|
107
|
+
self.table.removeRow(row)
|
|
108
|
+
|
|
109
|
+
def _row_entry(self, row: int) -> Optional[Dict[str, Any]]:
|
|
110
|
+
label_item = self.table.item(row, _COLUMN_LABEL)
|
|
111
|
+
value_item = self.table.item(row, _COLUMN_VALUE)
|
|
112
|
+
kind_combobox = self.table.cellWidget(row, _COLUMN_KIND)
|
|
113
|
+
if label_item is None or kind_combobox is None:
|
|
114
|
+
return None
|
|
115
|
+
kind = kind_combobox.currentData()
|
|
116
|
+
value = value_item.text().strip() if value_item else ""
|
|
117
|
+
entry = {
|
|
118
|
+
"label": label_item.text().strip(),
|
|
119
|
+
"kind": kind,
|
|
120
|
+
"enabled": label_item.checkState() == Qt.CheckState.Checked,
|
|
121
|
+
}
|
|
122
|
+
entry["at" if kind == KIND_AT else "minutes"] = value
|
|
123
|
+
return normalize_reminder(entry)
|
|
124
|
+
|
|
125
|
+
def reminders(self) -> List[Dict[str, Any]]:
|
|
126
|
+
"""目前表格上的提醒(格式不對的列會被略過)。"""
|
|
127
|
+
reminders = []
|
|
128
|
+
for row in range(self.table.rowCount()):
|
|
129
|
+
entry = self._row_entry(row)
|
|
130
|
+
if entry is not None:
|
|
131
|
+
reminders.append(entry)
|
|
132
|
+
return reminders
|
|
133
|
+
|
|
134
|
+
def accept(self) -> None:
|
|
135
|
+
reminders = self.reminders()
|
|
136
|
+
user_setting_dict["reminders"] = reminders
|
|
137
|
+
write_user_setting()
|
|
138
|
+
front_engine_logger.info(f"[ReminderDialog] saved | {len(reminders)} reminder(s)")
|
|
139
|
+
super().accept()
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""
|
|
2
|
+
智慧暫停設定:決定什麼時候該把覆蓋層暫時收起來——全螢幕程式在前景、
|
|
3
|
+
改用電池供電,或指定的程式取得焦點。
|
|
4
|
+
|
|
5
|
+
Smart-pause settings: when should the overlays stand down - a fullscreen app in
|
|
6
|
+
front, the machine on battery, or one of your own apps taking focus.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Dict, Optional
|
|
11
|
+
|
|
12
|
+
from PySide6.QtWidgets import (
|
|
13
|
+
QCheckBox, QDialog, QDialogButtonBox, QGridLayout, QLabel, QLineEdit, QWidget,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from frontengine.user_setting.user_setting_file import user_setting_dict, write_user_setting
|
|
17
|
+
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
18
|
+
from frontengine.utils.multi_language.language_wrapper import language_wrapper
|
|
19
|
+
from frontengine.utils.smart_pause.pause_rules import DEFAULT_RULES, parse_app_list
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _t(key: str, fallback: str) -> str:
|
|
23
|
+
return language_wrapper.language_word_dict.get(key, fallback)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def current_rules() -> Dict[str, Any]:
|
|
27
|
+
"""從設定讀出目前的暫停規則(缺項目就補上預設值)。"""
|
|
28
|
+
stored = user_setting_dict.get("smart_pause_rules")
|
|
29
|
+
rules = dict(DEFAULT_RULES)
|
|
30
|
+
if isinstance(stored, dict):
|
|
31
|
+
rules.update({key: stored[key] for key in DEFAULT_RULES if key in stored})
|
|
32
|
+
rules["apps"] = parse_app_list(rules.get("apps"))
|
|
33
|
+
return rules
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SmartPauseDialog(QDialog):
|
|
37
|
+
"""讓使用者挑選哪些情況要暫停覆蓋層。"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, parent: Optional[QWidget] = None) -> None:
|
|
40
|
+
front_engine_logger.info("[SmartPauseDialog] Init")
|
|
41
|
+
super().__init__(parent)
|
|
42
|
+
self.setWindowTitle(_t("smart_pause_title", "Smart pause"))
|
|
43
|
+
rules = current_rules()
|
|
44
|
+
|
|
45
|
+
self.fullscreen_checkbox = QCheckBox(
|
|
46
|
+
_t("smart_pause_fullscreen", "Pause while a fullscreen app is running"))
|
|
47
|
+
self.fullscreen_checkbox.setChecked(bool(rules.get("fullscreen", True)))
|
|
48
|
+
self.battery_checkbox = QCheckBox(
|
|
49
|
+
_t("smart_pause_battery", "Pause while running on battery"))
|
|
50
|
+
self.battery_checkbox.setChecked(bool(rules.get("battery", False)))
|
|
51
|
+
self.apps_label = QLabel(
|
|
52
|
+
_t("smart_pause_apps_label", "Pause while these apps have focus:"))
|
|
53
|
+
self.apps_edit = QLineEdit(", ".join(rules.get("apps", [])))
|
|
54
|
+
self.apps_edit.setPlaceholderText("photoshop, premiere, blender")
|
|
55
|
+
self.hint_label = QLabel(
|
|
56
|
+
_t("smart_pause_hint",
|
|
57
|
+
"Names are matched without the folder or .exe, so \"photoshop\" is enough."))
|
|
58
|
+
self.hint_label.setWordWrap(True)
|
|
59
|
+
|
|
60
|
+
self.button_box = QDialogButtonBox(
|
|
61
|
+
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
|
|
62
|
+
self.button_box.accepted.connect(self.accept)
|
|
63
|
+
self.button_box.rejected.connect(self.reject)
|
|
64
|
+
|
|
65
|
+
layout = QGridLayout(self)
|
|
66
|
+
layout.addWidget(self.fullscreen_checkbox, 0, 0, 1, 2)
|
|
67
|
+
layout.addWidget(self.battery_checkbox, 1, 0, 1, 2)
|
|
68
|
+
layout.addWidget(self.apps_label, 2, 0, 1, 2)
|
|
69
|
+
layout.addWidget(self.apps_edit, 3, 0, 1, 2)
|
|
70
|
+
layout.addWidget(self.hint_label, 4, 0, 1, 2)
|
|
71
|
+
layout.addWidget(self.button_box, 5, 0, 1, 2)
|
|
72
|
+
|
|
73
|
+
def rules(self) -> Dict[str, Any]:
|
|
74
|
+
"""目前對話框上的規則。"""
|
|
75
|
+
return {
|
|
76
|
+
"fullscreen": self.fullscreen_checkbox.isChecked(),
|
|
77
|
+
"battery": self.battery_checkbox.isChecked(),
|
|
78
|
+
"apps": parse_app_list(self.apps_edit.text()),
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
def accept(self) -> None:
|
|
82
|
+
"""寫回設定;服務每次輪詢都會重讀,不需要重啟。"""
|
|
83
|
+
rules = self.rules()
|
|
84
|
+
user_setting_dict["smart_pause_rules"] = rules
|
|
85
|
+
write_user_setting()
|
|
86
|
+
front_engine_logger.info(f"[SmartPauseDialog] saved | {rules}")
|
|
87
|
+
super().accept()
|