diff --git a/yin_yang/position.py b/yin_yang/position.py index 79fc891..328a497 100644 --- a/yin_yang/position.py +++ b/yin_yang/position.py @@ -1,13 +1,48 @@ import logging -from time import sleep import requests -from PySide6.QtCore import QObject -from PySide6.QtPositioning import QGeoPositionInfoSource, QGeoCoordinate, QGeoPositionInfo +from PySide6.QtCore import QObject, Slot +from PySide6.QtPositioning import ( + QGeoPositionInfoSource, + QGeoCoordinate, + QGeoPositionInfo, +) logger = logging.getLogger(__name__) +class QTPositionReceiver(QObject): + """Small handler for QT positioning service.""" + + def __init__(self): + super().__init__() + + # Create the position service and hook it to us + self._positionSource = QGeoPositionInfoSource.createSource( + "geoclue2", {"desktopId": "Yin-Yang"}, self + ) + self._positionSource.positionUpdated.connect(self.handlePosition) + + # Start the position service. + # This will only work after the app calls `exec()`. + self._positionSource.startUpdates() + + # Get the initial last position. + self._lastPosition = self._positionSource.lastKnownPosition() + + @Slot(QGeoPositionInfo) + def handlePosition(self, position: QGeoPositionInfo): + """Track the position provided by the service.""" + self._lastPosition = position + + def lastKnownPosition(self): + """Return the last known position, if valid.""" + return self._lastPosition + + +position_handler = QTPositionReceiver() + + def get_current_location() -> QGeoCoordinate: try: return get_qt_position() @@ -19,32 +54,23 @@ def get_current_location() -> QGeoCoordinate: except TypeError as e: logger.warning(e) - raise TypeError('Unable to get current location') - - -parent = QObject() -location_source = QGeoPositionInfoSource.createDefaultSource(parent) + raise TypeError("Unable to get current location") def get_qt_position() -> QGeoCoordinate: - if location_source is None: - raise TypeError('Location source is none') - - pos: QGeoPositionInfo = location_source.lastKnownPosition() - if pos is None: - location_source.requestUpdate(10) - tries = 0 - while pos is None and tries < 10: - pos = location_source.lastKnownPosition() - tries += 1 - sleep(1) + """Get the position via QT service""" + # Fetch the last known position + global position_handler + pos: QGeoPositionInfo = position_handler.lastKnownPosition() + coordinate = pos.coordinate() if not coordinate.isValid(): - raise TypeError('Coordinates are not valid') + raise TypeError("Coordinates are not valid") return coordinate + # there is a freedesktop portal for getting the location, # but it's not implemented by KDE, so I have no use for it @@ -52,20 +78,20 @@ def get_qt_position() -> QGeoCoordinate: def get_ipinfo_position() -> QGeoCoordinate: # use the old method as a fallback try: - response = requests.get('https://www.ipinfo.io/loc') + response = requests.get("https://www.ipinfo.io/loc") except Exception as e: logger.error(e) - raise TypeError('Error while sending a request to get location') + raise TypeError("Error while sending a request to get location") if not response.ok: - raise TypeError('Failed to get location from ipinfo.io') + raise TypeError("Failed to get location from ipinfo.io") - loc_response = response.text.removesuffix('\n').split(',') + loc_response = response.text.removesuffix("\n").split(",") loc: [float] = [float(coordinate) for coordinate in loc_response] - assert len(loc) == 2, 'The returned location should have exactly 2 values.' + assert len(loc) == 2, "The returned location should have exactly 2 values." coordinate = QGeoCoordinate(loc[0], loc[1]) if not coordinate.isValid(): - raise TypeError('Coordinates are not valid') + raise TypeError("Coordinates are not valid") return coordinate