1.0.0 Release

This commit is contained in:
Jerico Thomas
2025-07-25 15:31:22 -04:00
parent 6c5f8c399e
commit 805524b78c
19 changed files with 1323 additions and 95 deletions

153
src/options_dialog.py Normal file
View File

@@ -0,0 +1,153 @@
from PyQt5 import QtWidgets, QtCore, QtGui
import logging
from logging_config import get_logger
from launch_agent import get_launch_agent_manager
class OptionsDialog(QtWidgets.QDialog):
"""Options dialog for configuring HereIAm settings"""
def __init__(self, current_wait_time=240, current_start_enabled=True, current_log_level="INFO", current_move_px=10, current_launch_at_startup=False, parent=None):
super().__init__(parent)
self.logger = get_logger(__name__)
# Store current values
self.wait_time = current_wait_time
self.start_enabled = current_start_enabled
self.log_level = current_log_level
self.move_px = current_move_px
self.launch_at_startup = current_launch_at_startup
# Initialize launch agent manager
self.launch_agent_manager = get_launch_agent_manager()
self.setupUI()
self.load_current_values()
def setupUI(self):
"""Setup the dialog UI"""
self.setWindowTitle("HereIAm Options")
self.setModal(True)
self.setFixedSize(400, 220) # Increased height to accommodate new option
# Ensure dialog appears on top and is properly managed
self.setWindowFlags(QtCore.Qt.Dialog | QtCore.Qt.WindowStaysOnTopHint)
# Remove WA_DeleteOnClose to prevent automatic deletion conflicts
# Main layout
layout = QtWidgets.QVBoxLayout(self)
layout.setSpacing(10) # Reduce spacing between elements
# Create form layout
form_layout = QtWidgets.QFormLayout()
form_layout.setVerticalSpacing(8) # Reduce vertical spacing between form rows
form_layout.setHorizontalSpacing(10) # Set horizontal spacing
# Wait Time setting
self.wait_time_spinbox = QtWidgets.QSpinBox()
self.wait_time_spinbox.setRange(10, 3600) # 10 seconds to 1 hour
self.wait_time_spinbox.setSuffix(" seconds")
self.wait_time_spinbox.setToolTip("Time to wait before moving mouse when idle (Range: 10-3600 seconds)")
self.wait_time_spinbox.setKeyboardTracking(True) # Enable keyboard input
self.wait_time_spinbox.setButtonSymbols(QtWidgets.QAbstractSpinBox.UpDownArrows) # Ensure arrows are visible
self.wait_time_spinbox.lineEdit().setReadOnly(False) # Allow typing in the field
form_layout.addRow("Wait Time (10-3600s):", self.wait_time_spinbox)
# Mouse Movement Distance setting
self.move_px_spinbox = QtWidgets.QSpinBox()
self.move_px_spinbox.setRange(1, 100) # 1 to 100 pixels
self.move_px_spinbox.setSuffix(" pixels")
self.move_px_spinbox.setToolTip("Distance to move mouse in pixels (Range: 1-100 pixels)")
self.move_px_spinbox.setKeyboardTracking(True) # Enable keyboard input
self.move_px_spinbox.setButtonSymbols(QtWidgets.QAbstractSpinBox.UpDownArrows) # Ensure arrows are visible
self.move_px_spinbox.lineEdit().setReadOnly(False) # Allow typing in the field
form_layout.addRow("Movement Distance (1-100px):", self.move_px_spinbox)
# Start Enabled setting
self.start_enabled_checkbox = QtWidgets.QCheckBox()
self.start_enabled_checkbox.setToolTip("Start HereIAm enabled when application launches")
form_layout.addRow("Start Enabled:", self.start_enabled_checkbox)
# Launch at Startup setting
self.launch_at_startup_checkbox = QtWidgets.QCheckBox()
self.launch_at_startup_checkbox.setToolTip("Automatically launch HereIAm when you log in to macOS")
form_layout.addRow("Launch at Startup:", self.launch_at_startup_checkbox)
# Log Level setting
self.log_level_combo = QtWidgets.QComboBox()
self.log_level_combo.addItems(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"])
self.log_level_combo.setToolTip("Set the logging level for the application")
form_layout.addRow("Log Level:", self.log_level_combo)
layout.addLayout(form_layout)
# Button box
button_box = QtWidgets.QDialogButtonBox(
QtWidgets.QDialogButtonBox.Save | QtWidgets.QDialogButtonBox.Cancel
)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
layout.addWidget(button_box)
# Center the dialog on screen
self.center_on_screen()
def center_on_screen(self):
"""Center the dialog on the screen"""
screen = QtWidgets.QApplication.primaryScreen()
if screen:
screen_geometry = screen.geometry()
dialog_geometry = self.geometry()
x = (screen_geometry.width() - dialog_geometry.width()) // 2
y = (screen_geometry.height() - dialog_geometry.height()) // 2
self.move(x, y)
def showEvent(self, event):
"""Called when dialog is shown"""
super().showEvent(event)
self.raise_()
self.activateWindow()
def closeEvent(self, event):
"""Called when dialog is closed"""
self.logger.debug("Options dialog closing")
super().closeEvent(event)
def load_current_values(self):
"""Load current values into the form"""
self.wait_time_spinbox.setValue(self.wait_time)
self.move_px_spinbox.setValue(self.move_px)
self.start_enabled_checkbox.setChecked(self.start_enabled)
# Check current startup status from the system
current_startup_enabled = self.launch_agent_manager.is_startup_enabled()
self.launch_at_startup_checkbox.setChecked(current_startup_enabled)
# Set log level
index = self.log_level_combo.findText(self.log_level)
if index >= 0:
self.log_level_combo.setCurrentIndex(index)
def get_values(self):
"""Get the values from the form"""
try:
return {
'wait_time': self.wait_time_spinbox.value(),
'move_px': self.move_px_spinbox.value(),
'start_enabled': self.start_enabled_checkbox.isChecked(),
'launch_at_startup': self.launch_at_startup_checkbox.isChecked(),
'log_level': self.log_level_combo.currentText()
}
except AttributeError as e:
# If widgets are already destroyed, return None
self.logger.error(f"Error getting dialog values: {e}")
return None
@staticmethod
def get_options(current_wait_time=240, current_start_enabled=True, current_log_level="INFO", current_move_px=10, current_launch_at_startup=False, parent=None):
"""Static method to show the dialog and return values"""
dialog = OptionsDialog(current_wait_time, current_start_enabled, current_log_level, current_move_px, current_launch_at_startup, parent)
if dialog.exec_() == QtWidgets.QDialog.Accepted:
return dialog.get_values(), True
return None, False