#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include "QtQmlIntegration/qqmlintegration.h" #include "qtmetamacros.h" #include "sharing/attachment_container.h" #include "sharing/linux/nearby_noop_analytics_recorder.h" #include "sharing/linux/platform/linux_sharing_platform.h" #include "sharing/nearby_sharing_service.h" #include "sharing/share_target.h" #include "sharing/share_target_discovered_callback.h" #include "sharing/transfer_metadata.h" #include "sharing/transfer_update_callback.h" class ShareTargetModel : public QAbstractListModel { Q_OBJECT public: using ShareTarget = nearby::sharing::ShareTarget; enum Role { IdRole = Qt::UserRole + 1, DeviceNameRole, TypeRole, }; explicit ShareTargetModel(QObject* parent = nullptr); int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role) const override; QHash roleNames() const override; void ApplyTarget(const ShareTarget& target); void RemoveTarget(int64_t target_id); void Clear(); std::optional FindTarget(int64_t target_id) const; private: int IndexOf(int64_t target_id) const; std::vector targets_; }; class ShareTransferModel : public QAbstractListModel { Q_OBJECT public: using ShareTarget = nearby::sharing::ShareTarget; using TransferMetadata = nearby::sharing::TransferMetadata; enum Role { IdRole = Qt::UserRole + 1, DirectionRole, DeviceNameRole, StatusRole, ProgressRole, TransferredBytesRole, TotalBytesRole, TotalAttachmentsCountRole, TransferredAttachmentsCountRole, IsFinalStatusRole, AwaitingLocalConfirmationRole, LocalPathRole, }; explicit ShareTransferModel(QObject* parent = nullptr); int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role) const override; QHash roleNames() const override; void ApplyTarget(const ShareTarget& target); void ApplyTransfer(bool receive_mode, const ShareTarget& target, const TransferMetadata& transfer, int64_t total_bytes); void PrepareOutgoingTransfer(int64_t target_id, const QString& local_path, const std::optional& target); private: struct Row { int64_t id = 0; bool receive_mode = false; std::optional target; std::optional transfer; int64_t total_bytes = 0; QString local_path; }; int IndexOf(int64_t target_id) const; QVariant DataForRow(const Row& row, int role) const; void EmitRowChanged(int row); std::vector transfers_; }; class Backend : public QObject, public nearby::sharing::ShareTargetDiscoveredCallback { Q_OBJECT QML_ELEMENT Q_PROPERTY(QString hostname READ hostname CONSTANT) Q_PROPERTY(QAbstractListModel* targets READ targets CONSTANT) Q_PROPERTY(QAbstractListModel* transfers READ transfers CONSTANT) public: explicit Backend(QObject* parent = nullptr); ~Backend() override; QString hostname() const; QAbstractListModel* targets() { return &targets_; } QAbstractListModel* transfers() { return &transfers_; } Q_INVOKABLE void startReceive(); Q_INVOKABLE void startDiscovery(); Q_INVOKABLE bool sendFile(qint64 share_target_id, const QString& path); Q_INVOKABLE void accept(qint64 share_target_id); Q_INVOKABLE void reject(qint64 share_target_id); Q_INVOKABLE void cancel(qint64 share_target_id); void shutdown(); signals: void incomingTransfer(qint64 share_target_id); void incomingOffer(qint64 share_target_id, QString device_name, int attachment_count, qint64 total_bytes); void incomingOfferResolved(qint64 share_target_id); void transferFinished(qint64 share_target_id, bool receive_mode, QString device_name, QString status); void outgoingTransferStartFailed(qint64 share_target_id); private: friend class BackendTestPeer; using NearbySharingService = nearby::sharing::NearbySharingService; using ShareTarget = nearby::sharing::ShareTarget; using TransferMetadata = nearby::sharing::TransferMetadata; class TransferCallback final : public nearby::sharing::TransferUpdateCallback { public: TransferCallback(Backend& backend, bool receive_mode) : backend_(backend), receive_mode_(receive_mode) {} void OnTransferUpdate( const ShareTarget& share_target, const nearby::sharing::AttachmentContainer& attachment_container, const TransferMetadata& transfer_metadata) override; private: Backend& backend_; bool receive_mode_; }; enum class Mode { kNone, kReceive, kDiscovery, }; Backend(NearbySharingService& service, nearby::api::FastInitiationManager& fast_init_manager, int receive_timeout_milliseconds, QObject* parent); void OnShareTargetDiscovered(const ShareTarget& target) override; void OnShareTargetUpdated(const ShareTarget& target) override; void OnShareTargetLost(const ShareTarget& target) override; void OnTransferUpdate(bool receive_mode, const ShareTarget& target, const nearby::sharing::AttachmentContainer& attachments, const TransferMetadata& transfer); void SetDesiredMode(Mode mode); void DriveMode(); void OnModeStopped(Mode mode, NearbySharingService::StatusCodes status); void OnModeStarted(Mode mode, NearbySharingService::StatusCodes status); void StartFastInitiationMonitoring(); void MaybeStartFastInitiationScanning(); void StopFastInitiationScanningForDiscovery(); void OnFastInitiationScanningStoppedForDiscovery(); void OnFastInitiationDevicesDiscovered(); void OnFastInitiationDevicesNotDiscovered(); void OnFastInitiationScanningError( nearby::api::FastInitiationManager::Error error); void OpenReceiveWindow(bool fallback); void OnReceiveTimeout(); void StartIncomingOfferTimer(qint64 share_target_id); void ResolveIncomingOffer(qint64 share_target_id); void OnIncomingOfferTimeout(qint64 share_target_id); std::function StatusCallback( QString operation); void ReportStatus(const QString& operation, NearbySharingService::StatusCodes status); ShareTargetModel targets_; ShareTransferModel transfers_; nearby::sharing::linux::NoOpAnalyticsRecorder analytics_recorder_; std::unique_ptr platform_; nearby::api::FastInitiationManager* fast_init_manager_ = nullptr; NearbySharingService* service_ = nullptr; TransferCallback send_transfer_callback_; TransferCallback receive_transfer_callback_; QTimer receive_timeout_timer_; QHash incoming_offer_timers_; QSet finished_transfer_ids_; Mode active_mode_ = Mode::kNone; Mode desired_mode_ = Mode::kNone; bool initialized_ = false; bool mode_operation_in_flight_ = false; bool monitoring_requested_ = true; bool fast_init_scan_stop_in_flight_ = false; bool sender_present_ = false; bool receive_trigger_armed_ = true; bool receive_window_pending_ = false; bool receive_offer_received_ = false; bool fallback_receive_window_ = false; bool fallback_receive_used_ = false; bool shutting_down_ = false; };