#ifndef PAIRINGUICONTROLLER_H #define PAIRINGUICONTROLLER_H #include #include #include #include #include #include #include "core/controllers/api/pairingController.h" #include "core/controllers/api/subscriptionController.h" #include "core/controllers/serversController.h" #include "core/repositories/secureAppSettingsRepository.h" #include "core/utils/errorCodes.h" class PairingUiController : public QObject { Q_OBJECT Q_PROPERTY(QVariantList tvQrCodes READ tvQrCodes NOTIFY tvQrCodesChanged) Q_PROPERTY(int tvQrCodesCount READ tvQrCodesCount NOTIFY tvQrCodesChanged) Q_PROPERTY(QString tvSessionUuid READ tvSessionUuid NOTIFY tvSessionUuidChanged) Q_PROPERTY(bool tvPairingBusy READ tvPairingBusy NOTIFY tvPairingBusyChanged) Q_PROPERTY(QString tvStatusMessage READ tvStatusMessage NOTIFY tvStatusMessageChanged) Q_PROPERTY(int tvPairingWaitWindowSeconds READ tvPairingWaitWindowSeconds NOTIFY tvQrCodesChanged) Q_PROPERTY(bool phonePairingBusy READ phonePairingBusy NOTIFY phonePairingBusyChanged) Q_PROPERTY(QString phoneStatusMessage READ phoneStatusMessage NOTIFY phoneStatusMessageChanged) Q_PROPERTY(QString pendingPhonePairingUuid READ pendingPhonePairingUuid WRITE setPendingPhonePairingUuid NOTIFY pendingPhonePairingUuidChanged) Q_PROPERTY(QString lastSuccessfulPhonePairingDisplayName READ lastSuccessfulPhonePairingDisplayName NOTIFY lastSuccessfulPhonePairingDisplayNameChanged) Q_PROPERTY(int tvPairingUiPhase READ tvPairingUiPhase NOTIFY tvPairingUiPhaseChanged) Q_PROPERTY(bool embeddedPairingQrCameraActive READ embeddedPairingQrCameraActive WRITE setEmbeddedPairingQrCameraActive NOTIFY embeddedPairingQrCameraActiveChanged) Q_PROPERTY(bool iosNativePairingQrOverlayBuild READ iosNativePairingQrOverlayBuild CONSTANT) Q_PROPERTY(bool androidNativePairingQrOverlayBuild READ androidNativePairingQrOverlayBuild CONSTANT) Q_PROPERTY(qint64 androidPairingReaderCooldownUntilEpochMs READ androidPairingReaderCooldownUntilEpochMs NOTIFY androidPairingReaderCooldownUntilEpochMsChanged) public: PairingUiController(PairingController *pairingController, ServersController *serversController, SubscriptionController *subscriptionController, SecureAppSettingsRepository *appSettingsRepository, QObject *parent = nullptr); ~PairingUiController() override; QVariantList tvQrCodes() const; int tvQrCodesCount() const; QString tvSessionUuid() const; bool tvPairingBusy() const; QString tvStatusMessage() const; int tvPairingWaitWindowSeconds() const; bool phonePairingBusy() const; QString phoneStatusMessage() const; QString pendingPhonePairingUuid() const { return m_pendingPhonePairingUuid; } void setPendingPhonePairingUuid(const QString &uuid); QString lastSuccessfulPhonePairingDisplayName() const { return m_lastSuccessfulPhonePairingDisplayName; } int tvPairingUiPhase() const { return m_tvPairingUiPhase; } bool embeddedPairingQrCameraActive() const { return m_embeddedPairingQrCameraActive; } bool iosNativePairingQrOverlayBuild() const; bool androidNativePairingQrOverlayBuild() const; Q_INVOKABLE void setEmbeddedPairingQrCameraActive(bool active); Q_INVOKABLE void syncIosEmbeddedPairingQrNativeBottomExtra(int extraPt); Q_INVOKABLE void refreshIosEmbeddedPairingQrChrome(); qint64 androidPairingReaderCooldownUntilEpochMs() const { return m_androidPairingReaderCooldownUntilEpochMs; } Q_INVOKABLE void suppressAndroidNativePairingReaderStarts(int ms); Q_INVOKABLE void presentIosPairingQrNativeOverlayScanner(const QString &title = QString(), const QString &subtitle = QString()); Q_INVOKABLE void dismissIosPairingQrNativeOverlayScanner(); Q_INVOKABLE void restartIosPairingQrNativeOverlayCapture(); #if defined(Q_OS_ANDROID) static bool tryConsumeAndroidQrScan(const QString &code); static void notifyAndroidPairingQrCameraClosed(); static void notifyAndroidPairingQrCameraUserDismissed(); #endif public slots: bool canOpenTvQrPairingPage(); void startTvQrSession(); void cancelTvQrSession(); void cancelAllPairingActivity(); void submitPhonePairing(const QString &qrUuid, int serverIndex); void openPairingQrScanner(); Q_INVOKABLE bool isPairingCameraAccessGranted() const; Q_INVOKABLE void requestPairingCameraAccess(); Q_INVOKABLE void openPairingCameraAppSettings(); Q_INVOKABLE void setPairingQrTorchEnabled(bool enabled); bool applyScannedTextAsPairingUuid(const QString &raw); Q_INVOKABLE void clearPendingPhonePairingUuid(); signals: void errorOccurred(amnezia::ErrorCode errorCode); void tvQrCodesChanged(); void tvSessionUuidChanged(); void tvPairingBusyChanged(); void tvStatusMessageChanged(); void phonePairingBusyChanged(); void phoneStatusMessageChanged(); void pendingPhonePairingUuidChanged(); void lastSuccessfulPhonePairingDisplayNameChanged(); void tvPairingConfigReceived(); void phonePairingSucceeded(); void pairingUuidFromScan(const QString &uuid); void tvPairingUiPhaseChanged(); void pairingCameraAccessFinished(bool granted); void embeddedPairingQrCameraActiveChanged(); void androidPairingReaderCooldownUntilEpochMsChanged(); void pairingSendQrScanRejectedInvalidPayload(); void pairingIosNativeQrOverlayBackRequested(); void pairingAndroidNativeQrScannerUserDismissed(); private: void setTvBusy(bool busy); void setPhoneBusy(bool busy); void resetTvQrDisplay(); QString tvFailureMessage(amnezia::ErrorCode code) const; void dispatchTvGenerateQrAttempt(quint64 generation, int retryAttempt); void dispatchPhoneScanQrAttempt(const QString &qrUuid, bool isTestPurchase, const QString &vpnKey, const QJsonObject &serviceInfo, const QJsonArray &supportedProtocols, const QString &apiKey, quint64 generation, int retryAttempt); void setTvPairingUiPhase(int phase); PairingController *m_pairingController {}; ServersController *m_serversController {}; SubscriptionController *m_subscriptionController {}; SecureAppSettingsRepository *m_appSettingsRepository {}; QList m_tvQrCodes; QString m_tvSessionUuid; bool m_tvPairingBusy = false; QString m_tvStatusMessage; QPointer>> m_tvWatcher; QPointer m_tvNetworkReply; quint64 m_tvSessionGeneration { 0 }; int m_tvPairingUiPhase { 0 }; bool m_phonePairingBusy = false; QString m_phoneStatusMessage; QString m_pendingPhonePairingUuid; QString m_lastSuccessfulPhonePairingDisplayName; QPointer>> m_phoneWatcher; QPointer m_phoneNetworkReply; quint64 m_phoneSessionGeneration { 0 }; bool m_embeddedPairingQrCameraActive = false; qint64 m_androidPairingReaderCooldownUntilEpochMs = 0; }; #endif // PAIRINGUICONTROLLER_H