frontengine 1.0.70__tar.gz → 1.0.72__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.70 → frontengine-1.0.72}/PKG-INFO +1 -1
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/replica/replica_widget.py +22 -3
- frontengine-1.0.72/frontengine/ui/dialog/preset_schedule_dialog.py +150 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/window_replica_dialog.py +28 -7
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/menu/settings_menu.py +9 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/english.py +21 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/france.py +21 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/germany.py +21 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/italy.py +21 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/russian.py +21 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/simplified_chinese.py +21 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/traditional_chinese.py +21 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/preset_schedule/preset_schedule_service.py +48 -1
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/window_replica/dwm_thumbnail.py +45 -2
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine.egg-info/PKG-INFO +1 -1
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine.egg-info/SOURCES.txt +1 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/pyproject.toml +1 -1
- {frontengine-1.0.70 → frontengine-1.0.72}/LICENSE +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/README.md +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/__main__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/base_widget.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/camera/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/camera/camera_widget.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/canvas/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/canvas/whiteboard_widget.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/capture/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/capture/region_capture.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/focus_shield/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/focus_shield/focus_shield_widget.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/gif/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/gif/paint_gif.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/image/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/image/paint_image.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/load/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/load/load_someone_make_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/measure/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/measure/measure_widget.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/monitor/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/monitor/monitor_widget.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/notes/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/notes/sticky_note_widget.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/overlay_factory.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/particle/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/particle/particle_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/pet/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/pet/desktop_pet.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/presentation/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/presentation/annotation_overlay.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/presentation/cursor_effects.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/presentation/keystroke_display.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/presentation/magnifier.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/replica/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/scene/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/scene/extend_graphic_scene.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/scene/extend_graphic_view.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/scene/scene.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/screen_care/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/screen_care/color_vision_widget.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/screen_care/screen_filter.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/shortcuts/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/shortcuts/shortcut_sheet.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/sound_player/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/sound_player/sound_effect.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/sound_player/sound_player.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/spectrum/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/spectrum/spectrum_widget.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/text/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/text/draw_text.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/toast/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/toast/toast_widget.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/video/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/video/video_player.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/wallpaper/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/wallpaper/wallpaper_widget.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/web/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/web/webview.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/show/window_helpers.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/system_tray/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/system_tray/extend_system_tray.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/color/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/color/global_color.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/app_profile_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/clipboard_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/how_to_use_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/reminder_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/remote_control_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/screen_privacy_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/screen_text_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/screensaver_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/signage_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/smart_pause_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/usage_report_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/dialog/window_pin_dialog.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/main_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/menu/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/menu/help_menu.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/menu/how_to_menu.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/menu/language_menu.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/menu/preset_menu.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/nav/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/nav/sidebar.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/control_center/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/control_center/control_center_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/focus/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/focus/focus_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/gif/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/image/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/image/image_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/layout_kit.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/particle/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/pet/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/pet/pet_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/presentation/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/presentation/presentation_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/scene_page/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/screen_care/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/screen_care/screen_care_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/sound_player/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/text/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/text/text_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/tools/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/tools/tools_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/utils.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/video/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/video/video_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/wallpaper/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/wallpaper/wallpaper_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/web/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/web/web_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/widgets/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/page/widgets/widgets_setting_ui.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/style/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/ui/style/app_style.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/user_setting/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/user_setting/preset_repository.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/user_setting/scene_setting.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/user_setting/user_setting_file.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/app_profile/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/app_profile/app_profile_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/audio_meter/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/audio_meter/audio_envelope.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/audio_meter/loopback_capture.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/audio_meter/microphone_meter.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/audio_meter/screen_audio.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/audio_meter/spectrum_analyzer.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/audio_meter/system_audio_meter.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/autostart/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/autostart/autostart_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/break_reminder/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/break_reminder/break_reminder.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/browser/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/browser/browser.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/clipboard/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/clipboard/clipboard_history.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/clipboard/clipboard_watcher.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/color_vision/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/color_vision/color_vision.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/critical_exit/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/critical_exit/critical_exit.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/critical_exit/win32_vk.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/exception/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/exception/exception_tags.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/exception/exceptions.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/focus_shield/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/focus_shield/focus_shield.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/focus_timer/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/focus_timer/focus_timer.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/hotkey/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/hotkey/hotkey_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/input_watch/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/input_watch/input_watch_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/input_watch/typing_watch.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/json/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/json/json_file.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/json/json_repository.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/keep_awake/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/keep_awake/keep_awake.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/logging/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/logging/loggin_instance.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/measure/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/measure/measure.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/midi/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/midi/midi_input.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/language_wrapper.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/retranslate.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/now_playing/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/now_playing/now_playing.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/pet_chat/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/pet_chat/pet_chat_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/platform_info/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/platform_info/platform_info.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/playlist/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/playlist/playlist.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/plugins/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/plugins/plugin_loader.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/power_mode/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/power_mode/power_mode.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/preset_schedule/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/recording/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/recording/frame_recorder.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/recording/gif_writer.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/redirect_manager/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/reminder/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/reminder/reminder_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/remote/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/remote/remote_server.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/screen_privacy/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/screen_privacy/capture_affinity.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/screen_privacy/share_watch.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/screen_text/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/screen_text/screen_text_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/screensaver/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/screensaver/screensaver_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/signage/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/signage/signage_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/smart_pause/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/smart_pause/pause_rules.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/steam/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/steam/steam_language.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/system_stats/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/system_stats/system_stats.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/text_source/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/text_source/text_source.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/theme_schedule/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/usage_tracking/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/usage_tracking/usage_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/usage_tracking/usage_tracker.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/virtual_camera/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/virtual_camera/camera_feed.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/virtual_camera/virtual_camera.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/weather/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/weather/weather_service.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/web_url.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/window_pin/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/window_pin/window_layout.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/window_pin/window_pin.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/window_replica/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/workshop/__init__.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/workshop/workshop_content.py +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine.egg-info/dependency_links.txt +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine.egg-info/entry_points.txt +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine.egg-info/requires.txt +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/frontengine.egg-info/top_level.txt +0 -0
- {frontengine-1.0.70 → frontengine-1.0.72}/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.72
|
|
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
|
|
@@ -20,7 +20,7 @@ from PySide6.QtWidgets import QWidget
|
|
|
20
20
|
|
|
21
21
|
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
22
22
|
from frontengine.utils.window_replica.dwm_thumbnail import (
|
|
23
|
-
DEFAULT_REPLICA_WIDTH, MIN_REPLICA_SIZE, DwmThumbnail, available, fit_within,
|
|
23
|
+
DEFAULT_REPLICA_WIDTH, MIN_REPLICA_SIZE, DwmThumbnail, available, crop_rect, fit_within,
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
|
|
@@ -28,7 +28,8 @@ class WindowReplicaWidget(QWidget):
|
|
|
28
28
|
"""顯示另一個視窗即時畫面的小視窗。"""
|
|
29
29
|
|
|
30
30
|
def __init__(self, source_handle: int, title: str = "",
|
|
31
|
-
opacity_percent: int = 100, parent: Optional[QWidget] = None
|
|
31
|
+
opacity_percent: int = 100, parent: Optional[QWidget] = None,
|
|
32
|
+
crop: Optional[tuple] = None) -> None:
|
|
32
33
|
front_engine_logger.info(f"[WindowReplicaWidget] Init | source={source_handle}")
|
|
33
34
|
super().__init__(parent)
|
|
34
35
|
self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
|
|
@@ -42,6 +43,10 @@ class WindowReplicaWidget(QWidget):
|
|
|
42
43
|
self.source_handle = int(source_handle)
|
|
43
44
|
self.source_title = title
|
|
44
45
|
self.opacity_percent = max(1, min(100, int(opacity_percent)))
|
|
46
|
+
# 裁切用比例存:來源視窗被調整大小時,框到的還是同一塊。
|
|
47
|
+
# The crop is kept as fractions so it still points at the same part of
|
|
48
|
+
# the source after that window is resized.
|
|
49
|
+
self.crop = crop
|
|
45
50
|
self.thumbnail = DwmThumbnail()
|
|
46
51
|
self._drag_origin: Optional[QPoint] = None
|
|
47
52
|
|
|
@@ -63,6 +68,14 @@ class WindowReplicaWidget(QWidget):
|
|
|
63
68
|
if not self.thumbnail.register(int(self.winId()), self.source_handle):
|
|
64
69
|
return False
|
|
65
70
|
source_size = self.thumbnail.source_size()
|
|
71
|
+
# 有裁切的話,長寬比要照框出來的那一塊算,不是照整個視窗算——否則框一條
|
|
72
|
+
# 細長的聊天欄會得到一個又寬又空的複本。
|
|
73
|
+
# With a crop the aspect ratio comes from the cropped part, not the whole
|
|
74
|
+
# window: cropping a narrow chat column would otherwise give a wide,
|
|
75
|
+
# mostly empty replica.
|
|
76
|
+
cropped = crop_rect(source_size, self.crop)
|
|
77
|
+
if cropped is not None:
|
|
78
|
+
source_size = (cropped[2] - cropped[0], cropped[3] - cropped[1])
|
|
66
79
|
width, height = fit_within(source_size, (DEFAULT_REPLICA_WIDTH,
|
|
67
80
|
int(DEFAULT_REPLICA_WIDTH * 9 / 16)))
|
|
68
81
|
self.resize(width, height)
|
|
@@ -71,7 +84,13 @@ class WindowReplicaWidget(QWidget):
|
|
|
71
84
|
|
|
72
85
|
def _refresh(self) -> None:
|
|
73
86
|
self.thumbnail.update(self.width(), self.height(),
|
|
74
|
-
opacity=int(self.opacity_percent * 255 / 100)
|
|
87
|
+
opacity=int(self.opacity_percent * 255 / 100),
|
|
88
|
+
source_rect=crop_rect(self.thumbnail.source_size(), self.crop))
|
|
89
|
+
|
|
90
|
+
def set_crop(self, crop: Optional[tuple]) -> None:
|
|
91
|
+
"""換一塊要顯示的區域(None 表示整個視窗)。"""
|
|
92
|
+
self.crop = crop
|
|
93
|
+
self._refresh()
|
|
75
94
|
|
|
76
95
|
def set_opacity_percent(self, percent: int) -> None:
|
|
77
96
|
self.opacity_percent = max(1, min(100, int(percent)))
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""
|
|
2
|
+
預設集排程設定:星期幾、幾點幾分,套用哪一個預設集。
|
|
3
|
+
|
|
4
|
+
這個排程本來就在跑,卻沒有任何介面——只能手動改 `user_setting.json`,連時間都
|
|
5
|
+
不能在畫面上設。所以這裡不只是加上星期,是讓這個功能第一次真的到得了。
|
|
6
|
+
|
|
7
|
+
Preset schedule settings: which days, what time, which preset.
|
|
8
|
+
|
|
9
|
+
The schedule was already running with no interface at all - it could only be
|
|
10
|
+
configured by hand-editing `user_setting.json`, down to the time of day. So this
|
|
11
|
+
is not only about adding days: it is what makes the feature reachable at all.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Any, Dict, List, Optional
|
|
16
|
+
|
|
17
|
+
from PySide6.QtWidgets import (
|
|
18
|
+
QCheckBox, QComboBox, QDialog, QDialogButtonBox, QGridLayout, QLabel, QSpinBox, QWidget,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
from frontengine.user_setting.preset_repository import PresetRepository
|
|
22
|
+
from frontengine.user_setting.user_setting_file import user_setting_dict, write_user_setting
|
|
23
|
+
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
24
|
+
from frontengine.utils.multi_language.language_wrapper import language_wrapper
|
|
25
|
+
from frontengine.utils.multi_language.retranslate import tr
|
|
26
|
+
from frontengine.utils.preset_schedule.preset_schedule_service import (
|
|
27
|
+
DEFAULT_PRESET_SCHEDULE, normalize_days,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
SETTING_KEY = "preset_schedule"
|
|
31
|
+
|
|
32
|
+
# 0 = 週一,和 datetime.weekday() 一致
|
|
33
|
+
# 0 = Monday, matching datetime.weekday()
|
|
34
|
+
DAY_KEYS = (
|
|
35
|
+
("weekday_monday", "Mon"),
|
|
36
|
+
("weekday_tuesday", "Tue"),
|
|
37
|
+
("weekday_wednesday", "Wed"),
|
|
38
|
+
("weekday_thursday", "Thu"),
|
|
39
|
+
("weekday_friday", "Fri"),
|
|
40
|
+
("weekday_saturday", "Sat"),
|
|
41
|
+
("weekday_sunday", "Sun"),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _t(key: str, fallback: str) -> str:
|
|
46
|
+
return language_wrapper.language_word_dict.get(key, fallback)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def current_settings() -> Dict[str, Any]:
|
|
50
|
+
"""目前的排程設定(缺項目補預設值)。"""
|
|
51
|
+
stored = user_setting_dict.get(SETTING_KEY)
|
|
52
|
+
settings = dict(DEFAULT_PRESET_SCHEDULE)
|
|
53
|
+
if isinstance(stored, dict):
|
|
54
|
+
settings.update({key: stored[key] for key in DEFAULT_PRESET_SCHEDULE if key in stored})
|
|
55
|
+
settings["days"] = normalize_days(settings.get("days"))
|
|
56
|
+
settings["enabled"] = bool(settings.get("enabled"))
|
|
57
|
+
return settings
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class PresetScheduleDialog(QDialog):
|
|
61
|
+
"""設定哪幾天、幾點,自動套用哪一個預設集。"""
|
|
62
|
+
|
|
63
|
+
def __init__(self, parent: Optional[QWidget] = None, repository=None) -> None:
|
|
64
|
+
front_engine_logger.info("[PresetScheduleDialog] Init")
|
|
65
|
+
super().__init__(parent)
|
|
66
|
+
self.setWindowTitle(_t("preset_schedule_title", "Scheduled preset"))
|
|
67
|
+
settings = current_settings()
|
|
68
|
+
self._repository = repository or PresetRepository()
|
|
69
|
+
|
|
70
|
+
self.enable_checkbox = tr(QCheckBox(), "preset_schedule_enable", "Apply a preset on a schedule")
|
|
71
|
+
self.enable_checkbox.setChecked(settings["enabled"])
|
|
72
|
+
|
|
73
|
+
self.preset_label = tr(QLabel(), "preset_schedule_preset", "Preset")
|
|
74
|
+
self.preset_combobox = QComboBox()
|
|
75
|
+
# 只列真的存在的預設集:讓人自己打名字的話,打錯了要等到排程觸發的那一刻
|
|
76
|
+
# 才會發現什麼都沒發生。
|
|
77
|
+
# Only presets that exist are listed: with a free-text name, a typo is
|
|
78
|
+
# discovered when the schedule fires and nothing happens.
|
|
79
|
+
for name in self._preset_names():
|
|
80
|
+
self.preset_combobox.addItem(name, name)
|
|
81
|
+
index = self.preset_combobox.findData(settings.get("preset"))
|
|
82
|
+
if index >= 0:
|
|
83
|
+
self.preset_combobox.setCurrentIndex(index)
|
|
84
|
+
|
|
85
|
+
self.time_label = tr(QLabel(), "preset_schedule_time", "At")
|
|
86
|
+
self.hour_spinbox = QSpinBox()
|
|
87
|
+
self.hour_spinbox.setRange(0, 23)
|
|
88
|
+
self.hour_spinbox.setValue(int(settings.get("hour", 9)) % 24)
|
|
89
|
+
self.minute_spinbox = QSpinBox()
|
|
90
|
+
self.minute_spinbox.setRange(0, 59)
|
|
91
|
+
self.minute_spinbox.setValue(int(settings.get("minute", 0)) % 60)
|
|
92
|
+
|
|
93
|
+
self.days_label = tr(QLabel(), "preset_schedule_days", "On")
|
|
94
|
+
self.day_checkboxes: List[QCheckBox] = []
|
|
95
|
+
days_holder = QWidget()
|
|
96
|
+
days_layout = QGridLayout(days_holder)
|
|
97
|
+
days_layout.setContentsMargins(0, 0, 0, 0)
|
|
98
|
+
for index, (key, fallback) in enumerate(DAY_KEYS):
|
|
99
|
+
checkbox = tr(QCheckBox(), key, fallback)
|
|
100
|
+
checkbox.setChecked(index in settings["days"])
|
|
101
|
+
days_layout.addWidget(checkbox, index // 4, index % 4)
|
|
102
|
+
self.day_checkboxes.append(checkbox)
|
|
103
|
+
|
|
104
|
+
self.hint_label = tr(
|
|
105
|
+
QLabel(), "preset_schedule_hint",
|
|
106
|
+
"With no day ticked it runs every day. It fires once as the time passes, "
|
|
107
|
+
"so starting FrontEngine after that time will not apply it late.")
|
|
108
|
+
self.hint_label.setWordWrap(True)
|
|
109
|
+
|
|
110
|
+
buttons = QDialogButtonBox(
|
|
111
|
+
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
|
|
112
|
+
buttons.accepted.connect(self.accept)
|
|
113
|
+
buttons.rejected.connect(self.reject)
|
|
114
|
+
|
|
115
|
+
layout = QGridLayout(self)
|
|
116
|
+
layout.addWidget(self.enable_checkbox, 0, 0, 1, 3)
|
|
117
|
+
layout.addWidget(self.preset_label, 1, 0)
|
|
118
|
+
layout.addWidget(self.preset_combobox, 1, 1, 1, 2)
|
|
119
|
+
layout.addWidget(self.time_label, 2, 0)
|
|
120
|
+
layout.addWidget(self.hour_spinbox, 2, 1)
|
|
121
|
+
layout.addWidget(self.minute_spinbox, 2, 2)
|
|
122
|
+
layout.addWidget(self.days_label, 3, 0)
|
|
123
|
+
layout.addWidget(days_holder, 3, 1, 1, 2)
|
|
124
|
+
layout.addWidget(self.hint_label, 4, 0, 1, 3)
|
|
125
|
+
layout.addWidget(buttons, 5, 0, 1, 3)
|
|
126
|
+
|
|
127
|
+
def _preset_names(self) -> List[str]:
|
|
128
|
+
try:
|
|
129
|
+
return [name for name in self._repository.list_presets()
|
|
130
|
+
if not name.startswith("__")]
|
|
131
|
+
except OSError as error: # pragma: no cover - filesystem boundary
|
|
132
|
+
front_engine_logger.warning(f"[PresetScheduleDialog] list failed: {error!r}")
|
|
133
|
+
return []
|
|
134
|
+
|
|
135
|
+
def collect(self) -> Dict[str, Any]:
|
|
136
|
+
"""把畫面上的選擇讀成設定。"""
|
|
137
|
+
return {
|
|
138
|
+
"enabled": self.enable_checkbox.isChecked(),
|
|
139
|
+
"preset": self.preset_combobox.currentData() or "",
|
|
140
|
+
"hour": self.hour_spinbox.value(),
|
|
141
|
+
"minute": self.minute_spinbox.value(),
|
|
142
|
+
"days": [index for index, box in enumerate(self.day_checkboxes) if box.isChecked()],
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
def accept(self) -> None:
|
|
146
|
+
user_setting_dict[SETTING_KEY] = self.collect()
|
|
147
|
+
write_user_setting()
|
|
148
|
+
front_engine_logger.info(
|
|
149
|
+
f"[PresetScheduleDialog] saved | {user_setting_dict[SETTING_KEY]}")
|
|
150
|
+
super().accept()
|
|
@@ -12,8 +12,8 @@ from typing import List, Optional, Tuple
|
|
|
12
12
|
|
|
13
13
|
from PySide6.QtCore import Qt
|
|
14
14
|
from PySide6.QtWidgets import (
|
|
15
|
-
QAbstractItemView, QDialog, QDialogButtonBox, QGridLayout, QLabel,
|
|
16
|
-
QListWidgetItem, QPushButton, QSlider, QWidget,
|
|
15
|
+
QAbstractItemView, QComboBox, QDialog, QDialogButtonBox, QGridLayout, QLabel,
|
|
16
|
+
QListWidget, QListWidgetItem, QPushButton, QSlider, QWidget,
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
from frontengine.show.replica.replica_widget import WindowReplicaWidget
|
|
@@ -23,6 +23,19 @@ from frontengine.utils.multi_language.retranslate import retranslator, tr
|
|
|
23
23
|
from frontengine.utils.window_pin import window_pin
|
|
24
24
|
from frontengine.utils.window_replica.dwm_thumbnail import available
|
|
25
25
|
|
|
26
|
+
# 要顯示來源的哪一塊,用比例(左, 上, 右, 下)表示。
|
|
27
|
+
# 用比例而不是像素:來源視窗被調整大小之後,框到的還是同一塊。
|
|
28
|
+
# Which part of the source to show, as (left, top, right, bottom) fractions.
|
|
29
|
+
# Fractions rather than pixels, so a resize of the source keeps the same part.
|
|
30
|
+
CROP_REGIONS = (
|
|
31
|
+
("window_replica_whole", "Whole window", None),
|
|
32
|
+
("window_replica_top_half", "Top half", (0.0, 0.0, 1.0, 0.5)),
|
|
33
|
+
("window_replica_bottom_half", "Bottom half", (0.0, 0.5, 1.0, 1.0)),
|
|
34
|
+
("window_replica_left_half", "Left half", (0.0, 0.0, 0.5, 1.0)),
|
|
35
|
+
("window_replica_right_half", "Right half", (0.5, 0.0, 1.0, 1.0)),
|
|
36
|
+
("window_replica_centre", "Centre", (0.25, 0.25, 0.75, 0.75)),
|
|
37
|
+
)
|
|
38
|
+
|
|
26
39
|
|
|
27
40
|
def _t(key: str, fallback: str) -> str:
|
|
28
41
|
return language_wrapper.language_word_dict.get(key, fallback)
|
|
@@ -47,6 +60,11 @@ class WindowReplicaDialog(QDialog):
|
|
|
47
60
|
self.show_button = tr(QPushButton(), "window_replica_show", "Show replica")
|
|
48
61
|
self.show_button.clicked.connect(self.start_replica)
|
|
49
62
|
|
|
63
|
+
self.crop_label = tr(QLabel(), "window_replica_region", "Show")
|
|
64
|
+
self.crop_combobox = QComboBox()
|
|
65
|
+
for key, fallback, region in CROP_REGIONS:
|
|
66
|
+
self.crop_combobox.addItem(_t(key, fallback), region)
|
|
67
|
+
|
|
50
68
|
self.opacity_label = tr(QLabel(), "window_replica_opacity", "Opacity")
|
|
51
69
|
self.opacity_slider = QSlider(Qt.Orientation.Horizontal)
|
|
52
70
|
self.opacity_slider.setRange(10, 100)
|
|
@@ -69,10 +87,12 @@ class WindowReplicaDialog(QDialog):
|
|
|
69
87
|
layout.addWidget(self.window_list, 0, 0, 1, 2)
|
|
70
88
|
layout.addWidget(self.refresh_button, 1, 0)
|
|
71
89
|
layout.addWidget(self.show_button, 1, 1)
|
|
72
|
-
layout.addWidget(self.
|
|
73
|
-
layout.addWidget(self.
|
|
74
|
-
layout.addWidget(self.
|
|
75
|
-
layout.addWidget(self.
|
|
90
|
+
layout.addWidget(self.crop_label, 2, 0)
|
|
91
|
+
layout.addWidget(self.crop_combobox, 2, 1)
|
|
92
|
+
layout.addWidget(self.opacity_label, 3, 0)
|
|
93
|
+
layout.addWidget(self.opacity_slider, 3, 1)
|
|
94
|
+
layout.addWidget(self.hint_label, 4, 0, 1, 2)
|
|
95
|
+
layout.addWidget(self.button_box, 5, 0, 1, 2)
|
|
76
96
|
|
|
77
97
|
self.show_button.setEnabled(available())
|
|
78
98
|
self.reload_windows()
|
|
@@ -106,7 +126,8 @@ class WindowReplicaDialog(QDialog):
|
|
|
106
126
|
if chosen is None:
|
|
107
127
|
return None
|
|
108
128
|
handle, title = chosen
|
|
109
|
-
replica = self._replica_factory(handle, title, self.opacity_slider.value(), None
|
|
129
|
+
replica = self._replica_factory(handle, title, self.opacity_slider.value(), None,
|
|
130
|
+
self.crop_combobox.currentData())
|
|
110
131
|
if not replica.start():
|
|
111
132
|
front_engine_logger.info(f"[WindowReplicaDialog] could not replicate {title!r}")
|
|
112
133
|
replica.close()
|
|
@@ -12,6 +12,7 @@ from frontengine.ui.dialog.hotkey_settings_dialog import HotkeySettingsDialog
|
|
|
12
12
|
from frontengine.ui.dialog.reminder_dialog import ReminderDialog
|
|
13
13
|
from frontengine.ui.dialog.remote_control_dialog import RemoteControlDialog
|
|
14
14
|
from frontengine.ui.dialog.screen_privacy_dialog import ScreenPrivacyDialog
|
|
15
|
+
from frontengine.ui.dialog.preset_schedule_dialog import PresetScheduleDialog
|
|
15
16
|
from frontengine.ui.dialog.screensaver_dialog import ScreensaverDialog
|
|
16
17
|
from frontengine.utils.keep_awake.keep_awake import available as keep_awake_available
|
|
17
18
|
from frontengine.ui.dialog.signage_dialog import SignageDialog
|
|
@@ -124,6 +125,14 @@ def build_settings_menu(ui: "FrontEngineMainUI") -> None:
|
|
|
124
125
|
menu.addAction(screensaver_action)
|
|
125
126
|
ui.screensaver_action = screensaver_action
|
|
126
127
|
|
|
128
|
+
preset_schedule_action = QAction(
|
|
129
|
+
_t("settings_menu_preset_schedule", "Scheduled preset..."), menu)
|
|
130
|
+
retranslator.bind(preset_schedule_action, "settings_menu_preset_schedule",
|
|
131
|
+
"Scheduled preset...")
|
|
132
|
+
preset_schedule_action.triggered.connect(lambda: PresetScheduleDialog(ui).exec())
|
|
133
|
+
menu.addAction(preset_schedule_action)
|
|
134
|
+
ui.preset_schedule_action = preset_schedule_action
|
|
135
|
+
|
|
127
136
|
signage_action = QAction(_t("settings_menu_signage", "Signage mode..."), menu)
|
|
128
137
|
retranslator.bind(signage_action, "settings_menu_signage", "Signage mode...")
|
|
129
138
|
signage_action.triggered.connect(lambda: _open_signage_dialog(ui))
|
|
@@ -49,6 +49,13 @@ english_word_dict = {
|
|
|
49
49
|
"pet_settle_typing": "Settle while typing",
|
|
50
50
|
"target_monitor_span": "Span all screens",
|
|
51
51
|
"tools_replicate_window": "Replicate a window...",
|
|
52
|
+
"window_replica_region": "Show",
|
|
53
|
+
"window_replica_whole": "Whole window",
|
|
54
|
+
"window_replica_top_half": "Top half",
|
|
55
|
+
"window_replica_bottom_half": "Bottom half",
|
|
56
|
+
"window_replica_left_half": "Left half",
|
|
57
|
+
"window_replica_right_half": "Right half",
|
|
58
|
+
"window_replica_centre": "Centre",
|
|
52
59
|
"window_replica_title": "Replicate a window",
|
|
53
60
|
"window_replica_refresh": "Refresh",
|
|
54
61
|
"window_replica_show": "Show replica",
|
|
@@ -259,6 +266,20 @@ english_word_dict = {
|
|
|
259
266
|
# Target monitor / control center
|
|
260
267
|
"target_monitor_label": "Target monitor",
|
|
261
268
|
"target_monitor_ask": "Ask",
|
|
269
|
+
"settings_menu_preset_schedule": "Scheduled preset...",
|
|
270
|
+
"preset_schedule_title": "Scheduled preset",
|
|
271
|
+
"preset_schedule_enable": "Apply a preset on a schedule",
|
|
272
|
+
"preset_schedule_preset": "Preset",
|
|
273
|
+
"preset_schedule_time": "At",
|
|
274
|
+
"preset_schedule_days": "On",
|
|
275
|
+
"preset_schedule_hint": "With no day ticked it runs every day. It fires once as the time passes, so starting FrontEngine after that time will not apply it late.",
|
|
276
|
+
"weekday_monday": "Mon",
|
|
277
|
+
"weekday_tuesday": "Tue",
|
|
278
|
+
"weekday_wednesday": "Wed",
|
|
279
|
+
"weekday_thursday": "Thu",
|
|
280
|
+
"weekday_friday": "Fri",
|
|
281
|
+
"weekday_saturday": "Sat",
|
|
282
|
+
"weekday_sunday": "Sun",
|
|
262
283
|
"control_center_hide_all": "Hide all",
|
|
263
284
|
"control_center_show_all": "Show all",
|
|
264
285
|
"control_center_lock_all": "Lock overlays",
|
|
@@ -50,6 +50,13 @@ french_word_dict = {
|
|
|
50
50
|
"pet_settle_typing": "Rester tranquille pendant la frappe",
|
|
51
51
|
"target_monitor_span": "Sur tous les écrans",
|
|
52
52
|
"tools_replicate_window": "Dupliquer une fenêtre...",
|
|
53
|
+
"window_replica_region": "Afficher",
|
|
54
|
+
"window_replica_whole": "Fenêtre entière",
|
|
55
|
+
"window_replica_top_half": "Moitié supérieure",
|
|
56
|
+
"window_replica_bottom_half": "Moitié inférieure",
|
|
57
|
+
"window_replica_left_half": "Moitié gauche",
|
|
58
|
+
"window_replica_right_half": "Moitié droite",
|
|
59
|
+
"window_replica_centre": "Centre",
|
|
53
60
|
"window_replica_title": "Dupliquer une fenêtre",
|
|
54
61
|
"window_replica_refresh": "Actualiser",
|
|
55
62
|
"window_replica_show": "Afficher le duplicata",
|
|
@@ -258,6 +265,20 @@ french_word_dict = {
|
|
|
258
265
|
"preset_no_presets": "Aucun préréglage enregistré pour l'instant.",
|
|
259
266
|
"target_monitor_label": "Écran cible",
|
|
260
267
|
"target_monitor_ask": "Demander",
|
|
268
|
+
"settings_menu_preset_schedule": "Préréglage programmé...",
|
|
269
|
+
"preset_schedule_title": "Préréglage programmé",
|
|
270
|
+
"preset_schedule_enable": "Appliquer un préréglage selon un horaire",
|
|
271
|
+
"preset_schedule_preset": "Préréglage",
|
|
272
|
+
"preset_schedule_time": "À",
|
|
273
|
+
"preset_schedule_days": "Le",
|
|
274
|
+
"preset_schedule_hint": "Sans jour coché, cela s'applique tous les jours. Le déclenchement a lieu au passage de l'heure : démarrer FrontEngine après ne le rattrape pas.",
|
|
275
|
+
"weekday_monday": "Lun",
|
|
276
|
+
"weekday_tuesday": "Mar",
|
|
277
|
+
"weekday_wednesday": "Mer",
|
|
278
|
+
"weekday_thursday": "Jeu",
|
|
279
|
+
"weekday_friday": "Ven",
|
|
280
|
+
"weekday_saturday": "Sam",
|
|
281
|
+
"weekday_sunday": "Dim",
|
|
261
282
|
"control_center_hide_all": "Tout masquer",
|
|
262
283
|
"control_center_show_all": "Tout afficher",
|
|
263
284
|
"control_center_lock_all": "Verrouiller les calques",
|
|
@@ -50,6 +50,13 @@ germany_word_dict = {
|
|
|
50
50
|
"pet_settle_typing": "Beim Tippen still halten",
|
|
51
51
|
"target_monitor_span": "Über alle Bildschirme",
|
|
52
52
|
"tools_replicate_window": "Fenster duplizieren...",
|
|
53
|
+
"window_replica_region": "Anzeigen",
|
|
54
|
+
"window_replica_whole": "Ganzes Fenster",
|
|
55
|
+
"window_replica_top_half": "Obere Hälfte",
|
|
56
|
+
"window_replica_bottom_half": "Untere Hälfte",
|
|
57
|
+
"window_replica_left_half": "Linke Hälfte",
|
|
58
|
+
"window_replica_right_half": "Rechte Hälfte",
|
|
59
|
+
"window_replica_centre": "Mitte",
|
|
53
60
|
"window_replica_title": "Fenster duplizieren",
|
|
54
61
|
"window_replica_refresh": "Aktualisieren",
|
|
55
62
|
"window_replica_show": "Duplikat anzeigen",
|
|
@@ -258,6 +265,20 @@ germany_word_dict = {
|
|
|
258
265
|
"preset_no_presets": "Noch keine Voreinstellungen gespeichert.",
|
|
259
266
|
"target_monitor_label": "Zielbildschirm",
|
|
260
267
|
"target_monitor_ask": "Nachfragen",
|
|
268
|
+
"settings_menu_preset_schedule": "Geplante Voreinstellung...",
|
|
269
|
+
"preset_schedule_title": "Geplante Voreinstellung",
|
|
270
|
+
"preset_schedule_enable": "Voreinstellung nach Zeitplan anwenden",
|
|
271
|
+
"preset_schedule_preset": "Voreinstellung",
|
|
272
|
+
"preset_schedule_time": "Um",
|
|
273
|
+
"preset_schedule_days": "An",
|
|
274
|
+
"preset_schedule_hint": "Ohne angehakten Tag läuft es täglich. Es löst beim Überschreiten der Uhrzeit einmal aus; ein späterer Start holt es nicht nach.",
|
|
275
|
+
"weekday_monday": "Mo",
|
|
276
|
+
"weekday_tuesday": "Di",
|
|
277
|
+
"weekday_wednesday": "Mi",
|
|
278
|
+
"weekday_thursday": "Do",
|
|
279
|
+
"weekday_friday": "Fr",
|
|
280
|
+
"weekday_saturday": "Sa",
|
|
281
|
+
"weekday_sunday": "So",
|
|
261
282
|
"control_center_hide_all": "Alle ausblenden",
|
|
262
283
|
"control_center_show_all": "Alle anzeigen",
|
|
263
284
|
"control_center_lock_all": "Overlays sperren",
|
|
@@ -50,6 +50,13 @@ italian_word_dict = {
|
|
|
50
50
|
"pet_settle_typing": "Fermo mentre scrivi",
|
|
51
51
|
"target_monitor_span": "Su tutti gli schermi",
|
|
52
52
|
"tools_replicate_window": "Duplica una finestra...",
|
|
53
|
+
"window_replica_region": "Mostra",
|
|
54
|
+
"window_replica_whole": "Tutta la finestra",
|
|
55
|
+
"window_replica_top_half": "Metà superiore",
|
|
56
|
+
"window_replica_bottom_half": "Metà inferiore",
|
|
57
|
+
"window_replica_left_half": "Metà sinistra",
|
|
58
|
+
"window_replica_right_half": "Metà destra",
|
|
59
|
+
"window_replica_centre": "Centro",
|
|
53
60
|
"window_replica_title": "Duplica una finestra",
|
|
54
61
|
"window_replica_refresh": "Aggiorna",
|
|
55
62
|
"window_replica_show": "Mostra il duplicato",
|
|
@@ -258,6 +265,20 @@ italian_word_dict = {
|
|
|
258
265
|
"preset_no_presets": "Nessuna preimpostazione salvata finora.",
|
|
259
266
|
"target_monitor_label": "Schermo di destinazione",
|
|
260
267
|
"target_monitor_ask": "Chiedi",
|
|
268
|
+
"settings_menu_preset_schedule": "Preimpostazione pianificata...",
|
|
269
|
+
"preset_schedule_title": "Preimpostazione pianificata",
|
|
270
|
+
"preset_schedule_enable": "Applica una preimpostazione a orario",
|
|
271
|
+
"preset_schedule_preset": "Preimpostazione",
|
|
272
|
+
"preset_schedule_time": "Alle",
|
|
273
|
+
"preset_schedule_days": "Nei giorni",
|
|
274
|
+
"preset_schedule_hint": "Senza giorni selezionati vale tutti i giorni. Scatta nel momento in cui l'ora viene superata: avviare FrontEngine dopo non la recupera.",
|
|
275
|
+
"weekday_monday": "Lun",
|
|
276
|
+
"weekday_tuesday": "Mar",
|
|
277
|
+
"weekday_wednesday": "Mer",
|
|
278
|
+
"weekday_thursday": "Gio",
|
|
279
|
+
"weekday_friday": "Ven",
|
|
280
|
+
"weekday_saturday": "Sab",
|
|
281
|
+
"weekday_sunday": "Dom",
|
|
261
282
|
"control_center_hide_all": "Nascondi tutto",
|
|
262
283
|
"control_center_show_all": "Mostra tutto",
|
|
263
284
|
"control_center_lock_all": "Blocca gli overlay",
|
|
@@ -50,6 +50,13 @@ russian_word_dict = {
|
|
|
50
50
|
"pet_settle_typing": "Не двигаться при наборе текста",
|
|
51
51
|
"target_monitor_span": "На все экраны",
|
|
52
52
|
"tools_replicate_window": "Копия окна...",
|
|
53
|
+
"window_replica_region": "Показывать",
|
|
54
|
+
"window_replica_whole": "Всё окно",
|
|
55
|
+
"window_replica_top_half": "Верхняя половина",
|
|
56
|
+
"window_replica_bottom_half": "Нижняя половина",
|
|
57
|
+
"window_replica_left_half": "Левая половина",
|
|
58
|
+
"window_replica_right_half": "Правая половина",
|
|
59
|
+
"window_replica_centre": "Центр",
|
|
53
60
|
"window_replica_title": "Копия окна",
|
|
54
61
|
"window_replica_refresh": "Обновить",
|
|
55
62
|
"window_replica_show": "Показать копию",
|
|
@@ -258,6 +265,20 @@ russian_word_dict = {
|
|
|
258
265
|
"preset_no_presets": "Пресеты пока не сохранены.",
|
|
259
266
|
"target_monitor_label": "Целевой экран",
|
|
260
267
|
"target_monitor_ask": "Спрашивать",
|
|
268
|
+
"settings_menu_preset_schedule": "Пресет по расписанию...",
|
|
269
|
+
"preset_schedule_title": "Пресет по расписанию",
|
|
270
|
+
"preset_schedule_enable": "Применять пресет по расписанию",
|
|
271
|
+
"preset_schedule_preset": "Пресет",
|
|
272
|
+
"preset_schedule_time": "В",
|
|
273
|
+
"preset_schedule_days": "По дням",
|
|
274
|
+
"preset_schedule_hint": "Если ни один день не отмечен, срабатывает каждый день. Срабатывает в момент наступления времени: запуск FrontEngine позже не применит его задним числом.",
|
|
275
|
+
"weekday_monday": "Пн",
|
|
276
|
+
"weekday_tuesday": "Вт",
|
|
277
|
+
"weekday_wednesday": "Ср",
|
|
278
|
+
"weekday_thursday": "Чт",
|
|
279
|
+
"weekday_friday": "Пт",
|
|
280
|
+
"weekday_saturday": "Сб",
|
|
281
|
+
"weekday_sunday": "Вс",
|
|
261
282
|
"control_center_hide_all": "Скрыть всё",
|
|
262
283
|
"control_center_show_all": "Показать всё",
|
|
263
284
|
"control_center_lock_all": "Заблокировать слои",
|
{frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/simplified_chinese.py
RENAMED
|
@@ -50,6 +50,13 @@ simplified_chinese_word_dict = {
|
|
|
50
50
|
"pet_settle_typing": "打字时安分",
|
|
51
51
|
"target_monitor_span": "横跨所有屏幕",
|
|
52
52
|
"tools_replicate_window": "窗口副本⋯",
|
|
53
|
+
"window_replica_region": "显示范围",
|
|
54
|
+
"window_replica_whole": "整个窗口",
|
|
55
|
+
"window_replica_top_half": "上半部",
|
|
56
|
+
"window_replica_bottom_half": "下半部",
|
|
57
|
+
"window_replica_left_half": "左半部",
|
|
58
|
+
"window_replica_right_half": "右半部",
|
|
59
|
+
"window_replica_centre": "中央",
|
|
53
60
|
"window_replica_title": "窗口副本",
|
|
54
61
|
"window_replica_refresh": "刷新",
|
|
55
62
|
"window_replica_show": "显示副本",
|
|
@@ -258,6 +265,20 @@ simplified_chinese_word_dict = {
|
|
|
258
265
|
"preset_no_presets": "还没有储存任何预设。",
|
|
259
266
|
"target_monitor_label": "目标萤幕",
|
|
260
267
|
"target_monitor_ask": "每次询问",
|
|
268
|
+
"settings_menu_preset_schedule": "排程预设⋯",
|
|
269
|
+
"preset_schedule_title": "排程预设",
|
|
270
|
+
"preset_schedule_enable": "按计划自动套用预设",
|
|
271
|
+
"preset_schedule_preset": "预设",
|
|
272
|
+
"preset_schedule_time": "时间",
|
|
273
|
+
"preset_schedule_days": "星期",
|
|
274
|
+
"preset_schedule_hint": "没有勾任何一天就是每天都跑。它是在时间点跨过去的那一刻触发一次,所以在那之后才打开 FrontEngine 不会补套用。",
|
|
275
|
+
"weekday_monday": "一",
|
|
276
|
+
"weekday_tuesday": "二",
|
|
277
|
+
"weekday_wednesday": "三",
|
|
278
|
+
"weekday_thursday": "四",
|
|
279
|
+
"weekday_friday": "五",
|
|
280
|
+
"weekday_saturday": "六",
|
|
281
|
+
"weekday_sunday": "日",
|
|
261
282
|
"control_center_hide_all": "全部隐藏",
|
|
262
283
|
"control_center_show_all": "全部显示",
|
|
263
284
|
"control_center_lock_all": "锁定覆盖层",
|
{frontengine-1.0.70 → frontengine-1.0.72}/frontengine/utils/multi_language/traditional_chinese.py
RENAMED
|
@@ -50,6 +50,13 @@ traditional_chinese_word_dict = {
|
|
|
50
50
|
"pet_settle_typing": "打字時安分",
|
|
51
51
|
"target_monitor_span": "橫跨所有螢幕",
|
|
52
52
|
"tools_replicate_window": "視窗複本⋯",
|
|
53
|
+
"window_replica_region": "顯示範圍",
|
|
54
|
+
"window_replica_whole": "整個視窗",
|
|
55
|
+
"window_replica_top_half": "上半部",
|
|
56
|
+
"window_replica_bottom_half": "下半部",
|
|
57
|
+
"window_replica_left_half": "左半部",
|
|
58
|
+
"window_replica_right_half": "右半部",
|
|
59
|
+
"window_replica_centre": "中央",
|
|
53
60
|
"window_replica_title": "視窗複本",
|
|
54
61
|
"window_replica_refresh": "重新整理",
|
|
55
62
|
"window_replica_show": "顯示複本",
|
|
@@ -259,6 +266,20 @@ traditional_chinese_word_dict = {
|
|
|
259
266
|
# Target monitor / control center
|
|
260
267
|
"target_monitor_label": "目標螢幕",
|
|
261
268
|
"target_monitor_ask": "詢問",
|
|
269
|
+
"settings_menu_preset_schedule": "排程預設集⋯",
|
|
270
|
+
"preset_schedule_title": "排程預設集",
|
|
271
|
+
"preset_schedule_enable": "依排程自動套用預設集",
|
|
272
|
+
"preset_schedule_preset": "預設集",
|
|
273
|
+
"preset_schedule_time": "時間",
|
|
274
|
+
"preset_schedule_days": "星期",
|
|
275
|
+
"preset_schedule_hint": "沒有勾任何一天就是每天都跑。它是在時間點跨過去的那一刻觸發一次,所以在那之後才開啟 FrontEngine 不會補套用。",
|
|
276
|
+
"weekday_monday": "一",
|
|
277
|
+
"weekday_tuesday": "二",
|
|
278
|
+
"weekday_wednesday": "三",
|
|
279
|
+
"weekday_thursday": "四",
|
|
280
|
+
"weekday_friday": "五",
|
|
281
|
+
"weekday_saturday": "六",
|
|
282
|
+
"weekday_sunday": "日",
|
|
262
283
|
"control_center_hide_all": "全部隱藏",
|
|
263
284
|
"control_center_show_all": "全部顯示",
|
|
264
285
|
"control_center_lock_all": "鎖定覆蓋層",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
|
-
from typing import Any, Callable, Dict, Optional
|
|
4
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
5
5
|
|
|
6
6
|
from PySide6.QtCore import QObject, QTimer, Signal
|
|
7
7
|
|
|
@@ -9,14 +9,53 @@ from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
|
9
9
|
|
|
10
10
|
# 預設的排程設定(預設停用)
|
|
11
11
|
# Default preset-schedule config (disabled by default).
|
|
12
|
+
# 星期用 0=週一 … 6=週日(和 datetime.weekday() 一致,省得多一層換算)。
|
|
13
|
+
# 空清單代表「每天」——沒有勾任何一天卻期待它每天觸發,比什麼都不做合理;
|
|
14
|
+
# 真的不想要就把整個排程關掉。
|
|
15
|
+
# Days are 0=Monday … 6=Sunday, matching datetime.weekday() so nothing has to be
|
|
16
|
+
# converted. An empty list means every day: someone who ticked no days but left
|
|
17
|
+
# the schedule on meant "every day" far more likely than "never" - and "never"
|
|
18
|
+
# is what switching the schedule off is for.
|
|
19
|
+
ALL_DAYS = (0, 1, 2, 3, 4, 5, 6)
|
|
20
|
+
|
|
12
21
|
DEFAULT_PRESET_SCHEDULE: Dict[str, Any] = {
|
|
13
22
|
"enabled": False,
|
|
14
23
|
"preset": "",
|
|
15
24
|
"hour": 9,
|
|
16
25
|
"minute": 0,
|
|
26
|
+
"days": [],
|
|
17
27
|
}
|
|
18
28
|
|
|
19
29
|
|
|
30
|
+
def normalize_days(value: Any) -> List[int]:
|
|
31
|
+
"""
|
|
32
|
+
把設定裡的星期整理成排序過、不重複、0..6 的清單。手動編過的設定檔可能塞進
|
|
33
|
+
字串、負數或 99,這裡一律丟掉而不是讓排程在半夜炸掉。
|
|
34
|
+
Tidy the configured days into a sorted, unique 0..6 list. A hand-edited
|
|
35
|
+
settings file may hold strings, negatives or 99; those are dropped rather
|
|
36
|
+
than left to break the schedule in the middle of the night.
|
|
37
|
+
"""
|
|
38
|
+
if value is None:
|
|
39
|
+
return []
|
|
40
|
+
if isinstance(value, (str, bytes)) or not isinstance(value, (list, tuple, set)):
|
|
41
|
+
return []
|
|
42
|
+
days = set()
|
|
43
|
+
for item in value:
|
|
44
|
+
try:
|
|
45
|
+
day = int(item)
|
|
46
|
+
except (TypeError, ValueError):
|
|
47
|
+
continue
|
|
48
|
+
if 0 <= day <= 6:
|
|
49
|
+
days.add(day)
|
|
50
|
+
return sorted(days)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def runs_today(config: Any, weekday: int) -> bool:
|
|
54
|
+
"""今天是不是該跑。沒有指定星期就是每天都跑。"""
|
|
55
|
+
days = normalize_days((config or {}).get("days") if isinstance(config, dict) else None)
|
|
56
|
+
return not days or weekday in days
|
|
57
|
+
|
|
58
|
+
|
|
20
59
|
def _coerce_int(value: Any, default: int, modulo: int) -> int:
|
|
21
60
|
try:
|
|
22
61
|
return int(value) % modulo
|
|
@@ -86,6 +125,14 @@ class PresetScheduleService(QObject):
|
|
|
86
125
|
now = self._now_provider()
|
|
87
126
|
target = _coerce_int(config.get("hour"), 9, 24) * 60 + _coerce_int(config.get("minute"), 0, 60)
|
|
88
127
|
current = now.hour * 60 + now.minute
|
|
128
|
+
# 不該跑的日子仍要記下目前時間,否則隔天第一次輪詢會把「上次」當成
|
|
129
|
+
# 未知而錯過當天的觸發點。
|
|
130
|
+
# Days that do not run still record the current minute: otherwise the
|
|
131
|
+
# first poll of the next day has no previous value and misses the
|
|
132
|
+
# crossing entirely.
|
|
133
|
+
if not runs_today(config, now.weekday()):
|
|
134
|
+
self._prev_minutes = current
|
|
135
|
+
return
|
|
89
136
|
except Exception as error: # pragma: no cover - defensive boundary
|
|
90
137
|
front_engine_logger.warning(f"[PresetSchedule] poll error: {error!r}")
|
|
91
138
|
return
|