removed TUI and dbus service

This commit is contained in:
Lasan Mahaliyana
2026-07-18 19:01:16 +05:30
parent 0afaffdec4
commit 27b635dac8
52 changed files with 481 additions and 3309 deletions
-1
View File
@@ -26,7 +26,6 @@ refresh_compile_commands(
targets = {
":fast_init": "",
":nearby_sharing_cli": "",
"//sharing/linux/tui:tui": "",
},
# No need to add flags already in .bazelrc. They're automatically picked up.
# If you don't need flags, a list of targets is also okay, as is a single target string.
+1 -16
View File
@@ -18,20 +18,12 @@ RowLayout {
Connections {
target: backend
function onStatusTextChanged() {
console.log(backend.statusText);
}
function onIncomingTransfer(share_target_id, device_name, status) {
function onIncomingTransfer(share_target_id) {
console.log("Getting incoming share");
console.log("selected transfer: " + share_target_id)
selectedTransferId = share_target_id;
currentIndex = 2;
}
function onTransferUpdate(share_target_id, device_name, status, progress) {
if (selectedTransferId === share_target_id) {
currentIndex = 2;
}
}
}
Connections {
@@ -47,7 +39,6 @@ RowLayout {
return;
}
topLayout.selectedTransferId = shareTargetId;
backend.prepareOutgoingTransfer(shareTargetId, topLayout.pendingPath);
backend.sendFile(shareTargetId, topLayout.pendingPath);
topLayout.currentIndex = 2;
}
@@ -57,20 +48,14 @@ RowLayout {
}
}
Component.onCompleted: {
backend.startReceive();
}
function cancelPendingShare() {
pendingPath = "";
selectedTransferId = 0;
currentIndex = 0;
backend.stopDiscovery();
backend.startReceive();
}
function startSharing() {
backend.stopReceive();
backend.startDiscovery();
currentIndex = 1;
}
+11 -11
View File
@@ -46,7 +46,17 @@ qt_cc_library(
srcs = ["backend.cc"],
hdrs = ["backend.h"],
deps = [
":nearby_sharing_dbus_client",
"//connections/implementation/flags:connections_flags",
"//internal/base:file_path",
"//internal/flags:nearby_flags",
"//sharing:attachments",
"//sharing:nearby_sharing_service",
"//sharing:transfer_metadata",
"//sharing:types",
"//sharing/flags/generated:generated_flags",
"//sharing/linux:linux_sharing_platform",
"//sharing/proto:enums_cc_proto",
"@com_google_absl//absl/time",
"@rules_qt//:qt_core",
"@rules_qt//:qt_hdrs",
"@rules_qt//:qt_qml",
@@ -75,13 +85,3 @@ qt_cc_binary(
"@rules_qt//:qt_widgets",
],
)
cc_library(
name = "nearby_sharing_dbus_client",
srcs = ["nearby_sharing_dbus_client.cc"],
hdrs = ["nearby_sharing_dbus_client.h"],
deps = [
"//sharing/linux/daemon:nearby_sharing_dbus_client_glue",
"@sdbus_cpp",
],
)
+389 -269
View File
@@ -1,48 +1,104 @@
#include "sharing/linux/app/backend.h"
#include <algorithm>
#include <chrono>
#include <condition_variable>
#include <filesystem>
#include <functional>
#include <thread>
#include <mutex>
#include <utility>
#include <QDebug>
#include <QMetaObject>
#include <QPointer>
#include <QUrl>
#include <sdbus-c++/sdbus-c++.h>
#include "absl/time/time.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "internal/base/file_path.h"
#include "internal/flags/nearby_flags.h"
#include "sharing/advertisement.h"
#include "sharing/file_attachment.h"
#include "sharing/flags/generated/nearby_sharing_feature_flags.h"
#include "sharing/nearby_sharing_service_factory.h"
#include "sharing/nearby_sharing_settings.h"
#include "sharing/proto/enums.pb.h"
namespace {
using NearbySharingService = nearby::sharing::NearbySharingService;
constexpr std::chrono::seconds kShutdownTimeout(10);
QString ToQString(const std::string& value) {
return QString::fromStdString(value);
}
QString NormalizeLocalPath(const QString& path) {
const QUrl url(path);
if (url.isValid() && url.isLocalFile()) {
return url.toLocalFile();
}
return path;
return url.isValid() && url.isLocalFile() ? url.toLocalFile() : path;
}
double ProgressFraction(const std::optional<nearby::sharing::linux::app::Transfer>& transfer) {
if (!transfer.has_value()) {
return 0;
}
return std::clamp(transfer->progress / 100.0, 0.0, 1.0);
void ConfigureFlags() {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::sharing::config_package_nearby::nearby_sharing_feature::
kEnableBleForTransfer,
true);
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableBleL2cap,
true);
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kRefactorBleL2cap,
true);
}
bool IsAwaitingLocalConfirmation(
const std::optional<nearby::sharing::linux::app::Transfer>& transfer) {
return transfer.has_value() &&
transfer->status == "kAwaitingLocalConfirmation";
std::unique_ptr<nearby::sharing::AttachmentContainer> CreateFileAttachments(
const std::string& path) {
nearby::sharing::AttachmentContainer::Builder builder;
builder.AddFileAttachment(
nearby::sharing::FileAttachment(nearby::FilePath(path)));
return builder.Build();
}
QString DeviceNameFor(
const std::optional<nearby::sharing::linux::app::ShareTarget>& target) {
if (!target.has_value() || target->device_name.empty()) {
return QStringLiteral("Unknown device");
NearbySharingService::StatusCodes ShutdownService(
NearbySharingService& service) {
struct State {
std::mutex mutex;
std::condition_variable cv;
std::optional<NearbySharingService::StatusCodes> status;
};
auto state = std::make_shared<State>();
service.Shutdown([state](NearbySharingService::StatusCodes status) {
{
std::lock_guard<std::mutex> lock(state->mutex);
state->status = status;
}
state->cv.notify_one();
});
std::unique_lock<std::mutex> lock(state->mutex);
if (!state->cv.wait_for(lock, kShutdownTimeout,
[&] { return state->status.has_value(); })) {
return NearbySharingService::StatusCodes::kError;
}
return ToQString(target->device_name);
return *state->status;
}
void PostStatus(Backend* backend, std::function<void()> callback) {
QPointer<Backend> guarded_backend(backend);
if (!guarded_backend) {
return;
}
QMetaObject::invokeMethod(
guarded_backend,
[guarded_backend, callback = std::move(callback)]() mutable {
if (guarded_backend) {
callback();
}
},
Qt::QueuedConnection);
}
} // namespace
@@ -51,10 +107,7 @@ ShareTargetModel::ShareTargetModel(QObject* parent)
: QAbstractListModel(parent) {}
int ShareTargetModel::rowCount(const QModelIndex& parent) const {
if (parent.isValid()) {
return 0;
}
return static_cast<int>(targets_.size());
return parent.isValid() ? 0 : static_cast<int>(targets_.size());
}
QVariant ShareTargetModel::data(const QModelIndex& index, int role) const {
@@ -70,19 +123,7 @@ QVariant ShareTargetModel::data(const QModelIndex& index, int role) const {
case DeviceNameRole:
return ToQString(target.device_name);
case TypeRole:
return target.type;
case IsIncomingRole:
return target.is_incoming;
case IsKnownRole:
return target.is_known;
case DeviceIdRole:
return ToQString(target.device_id);
case ForSelfShareRole:
return target.for_self_share;
case VendorIdRole:
return target.vendor_id;
case ReceiveDisabledRole:
return target.receive_disabled;
return static_cast<int>(target.type);
default:
return {};
}
@@ -93,12 +134,6 @@ QHash<int, QByteArray> ShareTargetModel::roleNames() const {
{IdRole, "targetId"},
{DeviceNameRole, "deviceName"},
{TypeRole, "type"},
{IsIncomingRole, "isIncoming"},
{IsKnownRole, "isKnown"},
{DeviceIdRole, "deviceId"},
{ForSelfShareRole, "forSelfShare"},
{VendorIdRole, "vendorId"},
{ReceiveDisabledRole, "receiveDisabled"},
};
}
@@ -113,11 +148,7 @@ void ShareTargetModel::ApplyTarget(const ShareTarget& target) {
}
targets_[row] = target;
const QModelIndex changed_index = index(row);
emit dataChanged(changed_index, changed_index,
{IdRole, DeviceNameRole, TypeRole, IsIncomingRole,
IsKnownRole, DeviceIdRole, ForSelfShareRole, VendorIdRole,
ReceiveDisabledRole});
emit dataChanged(index(row), index(row), {IdRole, DeviceNameRole, TypeRole});
}
void ShareTargetModel::RemoveTarget(int64_t target_id) {
@@ -125,25 +156,24 @@ void ShareTargetModel::RemoveTarget(int64_t target_id) {
if (row < 0) {
return;
}
beginRemoveRows(QModelIndex(), row, row);
targets_.erase(targets_.begin() + row);
endRemoveRows();
}
void ShareTargetModel::ResetTargets(const std::vector<ShareTarget>& targets) {
void ShareTargetModel::Clear() {
if (targets_.empty()) {
return;
}
beginResetModel();
targets_ = targets;
targets_.clear();
endResetModel();
}
std::optional<ShareTargetModel::ShareTarget> ShareTargetModel::FindTarget(
int64_t target_id) const {
const int row = IndexOf(target_id);
if (row < 0) {
return std::nullopt;
}
return targets_[row];
return row < 0 ? std::nullopt : std::optional<ShareTarget>(targets_[row]);
}
int ShareTargetModel::IndexOf(int64_t target_id) const {
@@ -159,10 +189,7 @@ ShareTransferModel::ShareTransferModel(QObject* parent)
: QAbstractListModel(parent) {}
int ShareTransferModel::rowCount(const QModelIndex& parent) const {
if (parent.isValid()) {
return 0;
}
return static_cast<int>(transfers_.size());
return parent.isValid() ? 0 : static_cast<int>(transfers_.size());
}
QVariant ShareTransferModel::data(const QModelIndex& index, int role) const {
@@ -178,18 +205,13 @@ QHash<int, QByteArray> ShareTransferModel::roleNames() const {
{IdRole, "transferId"},
{DirectionRole, "direction"},
{DeviceNameRole, "deviceName"},
{TypeRole, "type"},
{StatusRole, "status"},
{ProgressRole, "progress"},
{TransferredBytesRole, "transferredBytes"},
{TotalBytesRole, "totalBytes"},
{TransferSpeedRole, "transferSpeed"},
{EstimatedTimeRemainingRole, "estimatedTimeRemaining"},
{TotalAttachmentsCountRole, "totalAttachmentsCount"},
{TransferredAttachmentsCountRole, "transferredAttachmentsCount"},
{IsFinalStatusRole, "isFinalStatus"},
{HasTargetRole, "hasTarget"},
{HasTransferRole, "hasTransfer"},
{AwaitingLocalConfirmationRole, "awaitingLocalConfirmation"},
{LocalPathRole, "localPath"},
};
@@ -204,21 +226,24 @@ void ShareTransferModel::ApplyTarget(const ShareTarget& target) {
EmitRowChanged(row);
}
void ShareTransferModel::ApplyTransfer(const QString& direction,
void ShareTransferModel::ApplyTransfer(bool receive_mode,
const ShareTarget& target,
const Transfer& transfer) {
const TransferMetadata& transfer,
int64_t total_bytes) {
int row = IndexOf(target.id);
if (row < 0) {
row = static_cast<int>(transfers_.size());
beginInsertRows(QModelIndex(), row, row);
transfers_.push_back(Row{target.id, direction, target, transfer, {}});
transfers_.push_back(
Row{target.id, receive_mode, target, transfer, total_bytes, {}});
endInsertRows();
return;
}
transfers_[row].direction = direction;
transfers_[row].receive_mode = receive_mode;
transfers_[row].target = target;
transfers_[row].transfer = transfer;
transfers_[row].total_bytes = total_bytes;
EmitRowChanged(row);
}
@@ -231,7 +256,6 @@ void ShareTransferModel::PrepareOutgoingTransfer(
beginInsertRows(QModelIndex(), row, row);
Row transfer;
transfer.id = target_id;
transfer.direction = QStringLiteral("send");
transfer.target = target;
transfer.local_path = local_path;
transfers_.push_back(std::move(transfer));
@@ -239,22 +263,12 @@ void ShareTransferModel::PrepareOutgoingTransfer(
return;
}
transfers_[row].direction = QStringLiteral("send");
transfers_[row].receive_mode = false;
transfers_[row].target = target;
transfers_[row].local_path = local_path;
EmitRowChanged(row);
}
void ShareTransferModel::RemoveTransfer(int64_t target_id) {
const int row = IndexOf(target_id);
if (row < 0) {
return;
}
beginRemoveRows(QModelIndex(), row, row);
transfers_.erase(transfers_.begin() + row);
endRemoveRows();
}
int ShareTransferModel::IndexOf(int64_t target_id) const {
for (int i = 0; i < static_cast<int>(transfers_.size()); ++i) {
if (transfers_[i].id == target_id) {
@@ -265,47 +279,43 @@ int ShareTransferModel::IndexOf(int64_t target_id) const {
}
QVariant ShareTransferModel::DataForRow(const Row& row, int role) const {
const Transfer empty_transfer;
const Transfer& transfer = row.transfer.value_or(empty_transfer);
const auto& target = row.target;
const auto& transfer = row.transfer;
switch (role) {
case IdRole:
return QVariant::fromValue<qint64>(row.id);
case DirectionRole:
return row.direction;
return row.receive_mode ? QStringLiteral("receive")
: QStringLiteral("send");
case DeviceNameRole:
return DeviceNameFor(row.target);
case TypeRole:
return row.target.has_value() ? row.target->type : 0;
return target.has_value() && !target->device_name.empty()
? ToQString(target->device_name)
: QStringLiteral("Unknown device");
case StatusRole:
if (row.transfer.has_value()) {
return ToQString(transfer.status);
}
return row.direction == QStringLiteral("send")
? QStringLiteral("kConnecting")
: QStringLiteral("kUnknown");
return transfer.has_value() ? ToQString(TransferMetadata::StatusToString(
transfer->status()))
: QString();
case ProgressRole:
return ProgressFraction(row.transfer);
return transfer.has_value()
? std::clamp(static_cast<double>(transfer->progress()) / 100.0,
0.0, 1.0)
: 0.0;
case TransferredBytesRole:
return QVariant::fromValue<qint64>(transfer.transferred_bytes);
return QVariant::fromValue<qulonglong>(
transfer.has_value() ? transfer->transferred_bytes() : 0);
case TotalBytesRole:
return QVariant::fromValue<qint64>(transfer.total_bytes);
case TransferSpeedRole:
return QVariant::fromValue<qint64>(transfer.transfer_speed);
case EstimatedTimeRemainingRole:
return QVariant::fromValue<qint64>(transfer.estimated_time_remaining);
return QVariant::fromValue<qint64>(row.total_bytes);
case TotalAttachmentsCountRole:
return transfer.total_attachments_count;
return transfer.has_value() ? transfer->total_attachments_count() : 0;
case TransferredAttachmentsCountRole:
return transfer.transferred_attachments_count;
return transfer.has_value() ? transfer->transferred_attachments_count()
: 0;
case IsFinalStatusRole:
return transfer.is_final_status;
case HasTargetRole:
return row.target.has_value();
case HasTransferRole:
return row.transfer.has_value();
return transfer.has_value() && transfer->is_final_status();
case AwaitingLocalConfirmationRole:
return IsAwaitingLocalConfirmation(row.transfer);
return transfer.has_value() &&
transfer->status() ==
TransferMetadata::Status::kAwaitingLocalConfirmation;
case LocalPathRole:
return row.local_path;
default:
@@ -314,202 +324,312 @@ QVariant ShareTransferModel::DataForRow(const Row& row, int role) const {
}
void ShareTransferModel::EmitRowChanged(int row) {
const QModelIndex changed_index = index(row);
emit dataChanged(changed_index, changed_index,
{IdRole, DirectionRole, DeviceNameRole, TypeRole,
StatusRole, ProgressRole, TransferredBytesRole,
TotalBytesRole, TransferSpeedRole,
EstimatedTimeRemainingRole, TotalAttachmentsCountRole,
TransferredAttachmentsCountRole, IsFinalStatusRole,
HasTargetRole, HasTransferRole,
AwaitingLocalConfirmationRole, LocalPathRole});
emit dataChanged(
index(row), index(row),
{IdRole, DirectionRole, DeviceNameRole, StatusRole, ProgressRole,
TransferredBytesRole, TotalBytesRole, TotalAttachmentsCountRole,
TransferredAttachmentsCountRole, IsFinalStatusRole,
AwaitingLocalConfirmationRole, LocalPathRole});
}
void Backend::TransferCallback::OnTransferUpdate(
const ShareTarget& share_target,
const nearby::sharing::AttachmentContainer& attachment_container,
const TransferMetadata& transfer_metadata) {
backend_.OnTransferUpdate(receive_mode_, share_target, attachment_container,
transfer_metadata);
}
Backend::Backend(QObject* parent)
: QObject(parent), targets_(this), transfers_(this) {
try {
client_ = std::make_unique<Client>(this);
SetStatusText(QStringLiteral("Connected to nearby sharing daemon"));
} catch (const sdbus::Error& error) {
SetStatusText(QStringLiteral("D-Bus connection failed: %1")
.arg(QString::fromStdString(error.getMessage())));
: QObject(parent),
targets_(this),
transfers_(this),
send_transfer_callback_(*this, false),
receive_transfer_callback_(*this, true) {
ConfigureFlags();
service_ = nearby::sharing::NearbySharingServiceFactory::GetInstance()
->CreateSharingService(platform_, &analytics_recorder_,
/*event_logger=*/nullptr,
/*supports_file_sync=*/false);
if (service_ == nullptr) {
qCritical() << "Failed to create NearbySharingService";
desired_mode_ = Mode::kNone;
return;
}
service_->GetSettings()->SetDataUsage(
nearby::sharing::proto::WIFI_ONLY_DATA_USAGE);
QPointer<Backend> backend(this);
service_->SetVisibility(
nearby::sharing::proto::DEVICE_VISIBILITY_EVERYONE, absl::ZeroDuration(),
[backend](NearbySharingService::StatusCodes status) mutable {
if (!backend) {
return;
}
PostStatus(backend, [backend, status]() {
if (!backend || backend->shutting_down_) {
return;
}
backend->initialized_ =
status == NearbySharingService::StatusCodes::kOk;
backend->ReportStatus(QStringLiteral("Initialize"), status);
if (backend->initialized_) {
backend->DriveMode();
} else {
backend->desired_mode_ = Mode::kNone;
}
});
});
}
Backend::~Backend() = default;
Backend::~Backend() {
shutdown();
}
void Backend::startReceive() {
RunCommand(QStringLiteral("Start receive"),
[this]() { return client_->StartReceive(); });
}
void Backend::stopReceive() {
RunCommand(QStringLiteral("Stop receive"),
[this]() { return client_->StopReceive(); });
SetDesiredMode(Mode::kReceive);
}
void Backend::startDiscovery() {
RunCommand(QStringLiteral("Start discovery"),
[this]() { return client_->StartDiscovery(); });
}
void Backend::stopDiscovery() {
RunCommand(QStringLiteral("Stop discovery"),
[this]() { return client_->StopDiscovery(); });
SetDesiredMode(Mode::kDiscovery);
}
void Backend::sendFile(qint64 share_target_id, const QString& path) {
if (service_ == nullptr || shutting_down_) {
return;
}
const QString local_path = NormalizeLocalPath(path);
RunCommand(QStringLiteral("Send file"), [this, share_target_id, local_path]() {
return client_->SendFile(share_target_id, local_path.toStdString());
});
}
const std::string native_path = local_path.toStdString();
std::error_code error;
if (!std::filesystem::is_regular_file(native_path, error)) {
qWarning() << "Send file failed: path is not a regular file" << local_path;
return;
}
const auto target = targets_.FindTarget(share_target_id);
if (!target.has_value()) {
qWarning() << "Send file failed: unknown target" << share_target_id;
return;
}
void Backend::prepareOutgoingTransfer(qint64 share_target_id,
const QString& path) {
transfers_.PrepareOutgoingTransfer(share_target_id, NormalizeLocalPath(path),
targets_.FindTarget(share_target_id));
transfers_.PrepareOutgoingTransfer(share_target_id, local_path, target);
service_->SendAttachments(share_target_id, CreateFileAttachments(native_path),
StatusCallback(QStringLiteral("Send file")));
}
void Backend::accept(qint64 share_target_id) {
RunCommand(QStringLiteral("Accept transfer"), [this, share_target_id]() {
return client_->Accept(share_target_id);
});
if (service_ != nullptr && !shutting_down_) {
service_->Accept(share_target_id,
StatusCallback(QStringLiteral("Accept transfer")));
}
}
void Backend::reject(qint64 share_target_id) {
RunCommand(QStringLiteral("Reject transfer"), [this, share_target_id]() {
return client_->Reject(share_target_id);
});
if (service_ != nullptr && !shutting_down_) {
service_->Reject(share_target_id,
StatusCallback(QStringLiteral("Reject transfer")));
}
}
void Backend::cancel(qint64 share_target_id) {
RunCommand(QStringLiteral("Cancel transfer"), [this, share_target_id]() {
return client_->Cancel(share_target_id);
if (service_ != nullptr && !shutting_down_) {
service_->Cancel(share_target_id,
StatusCallback(QStringLiteral("Cancel transfer")));
}
}
void Backend::shutdown() {
if (service_ == nullptr || shutting_down_) {
return;
}
shutting_down_ = true;
desired_mode_ = Mode::kNone;
const auto status = ShutdownService(*service_);
if (status != NearbySharingService::StatusCodes::kOk) {
qWarning() << "Nearby Sharing shutdown failed:"
<< NearbySharingService::StatusCodeToString(status);
}
service_ = nullptr;
}
void Backend::OnShareTargetDiscovered(const ShareTarget& target) {
QPointer<Backend> backend(this);
PostStatus(this, [backend, target]() {
if (!backend || backend->shutting_down_) {
return;
}
backend->targets_.ApplyTarget(target);
backend->transfers_.ApplyTarget(target);
});
}
void Backend::OnTargetDiscovered(const ShareTarget& target) {
QMetaObject::invokeMethod(
this, [this, target]() { ApplyTarget(target); }, Qt::QueuedConnection);
void Backend::OnShareTargetUpdated(const ShareTarget& target) {
OnShareTargetDiscovered(target);
}
void Backend::OnTargetUpdated(const ShareTarget& target) {
QMetaObject::invokeMethod(
this, [this, target]() { ApplyTarget(target); }, Qt::QueuedConnection);
}
void Backend::OnTargetLost(const ShareTarget& target) {
QMetaObject::invokeMethod(
this, [this, target]() { RemoveTarget(target); }, Qt::QueuedConnection);
}
void Backend::OnIncomingTransfer(const std::string& direction,
const ShareTarget& target,
const Transfer& transfer) {
QMetaObject::invokeMethod(
this,
[this, direction, target, transfer]() {
ApplyTarget(target);
transfers_.ApplyTransfer(ToQString(direction), target, transfer);
emit incomingTransfer(target.id, ToQString(target.device_name),
ToQString(transfer.status));
},
Qt::QueuedConnection);
}
void Backend::OnTransferUpdate(const std::string& direction,
const ShareTarget& target,
const Transfer& transfer) {
QMetaObject::invokeMethod(
this,
[this, direction, target, transfer]() {
ApplyTarget(target);
transfers_.ApplyTransfer(ToQString(direction), target, transfer);
emit transferUpdate(target.id, ToQString(target.device_name),
ToQString(transfer.status), transfer.progress);
},
Qt::QueuedConnection);
}
void Backend::OnStatusChanged(const Status& status) {
QMetaObject::invokeMethod(
this, [this, status]() { ApplyStatus(status); }, Qt::QueuedConnection);
}
void Backend::ApplyTarget(const ShareTarget& target) {
targets_.ApplyTarget(target);
transfers_.ApplyTarget(target);
}
void Backend::RemoveTarget(const ShareTarget& target) {
targets_.RemoveTarget(target.id);
}
void Backend::ApplyStatus(const Status& status) {
status_ = status;
targets_.ResetTargets(status.targets);
emit statusChanged();
}
void Backend::ApplyCommandResult(const QString& command,
const std::tuple<bool, std::string>& result) {
const auto& [ok, message] = result;
const QString detail =
message.empty() ? (ok ? QStringLiteral("ok") : QStringLiteral("failed"))
: ToQString(message);
SetStatusText(QStringLiteral("%1: %2").arg(command, detail));
}
void Backend::RunCommand(
const QString& command,
const std::function<std::tuple<bool, std::string>()>& operation) {
if (!client_) {
SetStatusText(QStringLiteral("%1 failed: not connected").arg(command));
return;
}
void Backend::OnShareTargetLost(const ShareTarget& target) {
QPointer<Backend> backend(this);
std::thread([backend, command, operation]() {
try {
auto result = operation();
if (!backend) {
return;
}
QMetaObject::invokeMethod(
backend,
[backend, command, result = std::move(result)]() {
if (!backend) {
return;
}
backend->ApplyCommandResult(command, result);
},
Qt::QueuedConnection);
} catch (const sdbus::Error& error) {
const QString message = QStringLiteral("%1 failed: %2")
.arg(command, QString::fromStdString(
error.getMessage()));
if (!backend) {
return;
}
QMetaObject::invokeMethod(
backend,
[backend, message]() {
if (!backend) {
return;
}
backend->SetStatusText(message);
},
Qt::QueuedConnection);
PostStatus(this, [backend, id = target.id]() {
if (backend && !backend->shutting_down_) {
backend->targets_.RemoveTarget(id);
}
}).detach();
});
}
void Backend::OnTransferUpdate(
bool receive_mode, const ShareTarget& target,
const nearby::sharing::AttachmentContainer& attachments,
const TransferMetadata& transfer) {
const int64_t total_bytes = attachments.GetTotalAttachmentsSize();
QPointer<Backend> backend(this);
PostStatus(this, [backend, receive_mode, target, transfer, total_bytes]() {
if (!backend || backend->shutting_down_) {
return;
}
backend->targets_.ApplyTarget(target);
backend->transfers_.ApplyTransfer(receive_mode, target, transfer,
total_bytes);
if (receive_mode &&
transfer.status() ==
TransferMetadata::Status::kAwaitingLocalConfirmation) {
emit backend->incomingTransfer(target.id);
}
});
}
void Backend::SetStatusText(const QString& text) {
if (status_text_ == text) {
void Backend::SetDesiredMode(Mode mode) {
desired_mode_ = mode;
DriveMode();
}
void Backend::DriveMode() {
if (!initialized_ || service_ == nullptr || shutting_down_ ||
mode_operation_in_flight_ || active_mode_ == desired_mode_) {
return;
}
status_text_ = text;
emit statusTextChanged();
mode_operation_in_flight_ = true;
QPointer<Backend> backend(this);
if (active_mode_ == Mode::kReceive) {
service_->UnregisterReceiveSurface(
&receive_transfer_callback_,
[backend](NearbySharingService::StatusCodes status) mutable {
if (backend) {
PostStatus(backend, [backend, status]() {
if (backend) {
backend->OnModeStopped(Mode::kReceive, status);
}
});
}
});
return;
}
if (active_mode_ == Mode::kDiscovery) {
service_->UnregisterSendSurface(
&send_transfer_callback_,
[backend](NearbySharingService::StatusCodes status) mutable {
if (backend) {
PostStatus(backend, [backend, status]() {
if (backend) {
backend->OnModeStopped(Mode::kDiscovery, status);
}
});
}
});
return;
}
const Mode mode = desired_mode_;
if (mode == Mode::kReceive) {
service_->RegisterReceiveSurface(
&receive_transfer_callback_,
NearbySharingService::ReceiveSurfaceState::kForeground,
nearby::sharing::Advertisement::BlockedVendorId::kNone,
[backend, mode](NearbySharingService::StatusCodes status) mutable {
if (backend) {
PostStatus(backend, [backend, mode, status]() {
if (backend) {
backend->OnModeStarted(mode, status);
}
});
}
});
return;
}
if (mode == Mode::kDiscovery) {
service_->RegisterSendSurface(
&send_transfer_callback_, this,
NearbySharingService::SendSurfaceState::kForeground,
nearby::sharing::Advertisement::BlockedVendorId::kNone,
/*disable_wifi_hotspot=*/false,
[backend, mode](NearbySharingService::StatusCodes status) mutable {
if (backend) {
PostStatus(backend, [backend, mode, status]() {
if (backend) {
backend->OnModeStarted(mode, status);
}
});
}
});
return;
}
mode_operation_in_flight_ = false;
}
void Backend::OnModeStopped(Mode mode,
NearbySharingService::StatusCodes status) {
mode_operation_in_flight_ = false;
if (shutting_down_) {
return;
}
if (status == NearbySharingService::StatusCodes::kOk ||
status == NearbySharingService::StatusCodes::kStatusAlreadyStopped) {
active_mode_ = Mode::kNone;
if (mode == Mode::kDiscovery) {
targets_.Clear();
}
} else {
desired_mode_ = active_mode_;
ReportStatus(QStringLiteral("Stop sharing mode"), status);
}
DriveMode();
}
void Backend::OnModeStarted(Mode mode,
NearbySharingService::StatusCodes status) {
mode_operation_in_flight_ = false;
if (shutting_down_) {
return;
}
if (status == NearbySharingService::StatusCodes::kOk) {
active_mode_ = mode;
} else {
desired_mode_ = Mode::kNone;
ReportStatus(QStringLiteral("Start sharing mode"), status);
}
DriveMode();
}
std::function<void(NearbySharingService::StatusCodes)> Backend::StatusCallback(
QString operation) {
QPointer<Backend> backend(this);
return [backend, operation = std::move(operation)](
NearbySharingService::StatusCodes status) {
if (backend) {
PostStatus(backend, [backend, operation, status]() {
if (backend && !backend->shutting_down_) {
backend->ReportStatus(operation, status);
}
});
}
};
}
void Backend::ReportStatus(const QString& operation,
NearbySharingService::StatusCodes status) {
if (status != NearbySharingService::StatusCodes::kOk) {
qWarning().noquote()
<< operation + QStringLiteral(" failed: ") +
ToQString(NearbySharingService::StatusCodeToString(status));
}
}
+70 -72
View File
@@ -5,7 +5,6 @@
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <vector>
#include <QAbstractListModel>
@@ -14,24 +13,25 @@
#include "QtQmlIntegration/qqmlintegration.h"
#include "qtmetamacros.h"
#include "sharing/linux/app/nearby_sharing_dbus_client.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::linux::app::ShareTarget;
using ShareTarget = nearby::sharing::ShareTarget;
enum Role {
IdRole = Qt::UserRole + 1,
DeviceNameRole,
TypeRole,
IsIncomingRole,
IsKnownRole,
DeviceIdRole,
ForSelfShareRole,
VendorIdRole,
ReceiveDisabledRole,
};
explicit ShareTargetModel(QObject* parent = nullptr);
@@ -42,7 +42,7 @@ class ShareTargetModel : public QAbstractListModel {
void ApplyTarget(const ShareTarget& target);
void RemoveTarget(int64_t target_id);
void ResetTargets(const std::vector<ShareTarget>& targets);
void Clear();
std::optional<ShareTarget> FindTarget(int64_t target_id) const;
private:
@@ -55,25 +55,20 @@ class ShareTransferModel : public QAbstractListModel {
Q_OBJECT
public:
using ShareTarget = nearby::sharing::linux::app::ShareTarget;
using Transfer = nearby::sharing::linux::app::Transfer;
using ShareTarget = nearby::sharing::ShareTarget;
using TransferMetadata = nearby::sharing::TransferMetadata;
enum Role {
IdRole = Qt::UserRole + 1,
DirectionRole,
DeviceNameRole,
TypeRole,
StatusRole,
ProgressRole,
TransferredBytesRole,
TotalBytesRole,
TransferSpeedRole,
EstimatedTimeRemainingRole,
TotalAttachmentsCountRole,
TransferredAttachmentsCountRole,
IsFinalStatusRole,
HasTargetRole,
HasTransferRole,
AwaitingLocalConfirmationRole,
LocalPathRole,
};
@@ -85,18 +80,18 @@ class ShareTransferModel : public QAbstractListModel {
QHash<int, QByteArray> roleNames() const override;
void ApplyTarget(const ShareTarget& target);
void ApplyTransfer(const QString& direction, const ShareTarget& target,
const Transfer& transfer);
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<ShareTarget>& target);
void RemoveTransfer(int64_t target_id);
private:
struct Row {
int64_t id = 0;
QString direction;
bool receive_mode = false;
std::optional<ShareTarget> target;
std::optional<Transfer> transfer;
std::optional<TransferMetadata> transfer;
int64_t total_bytes = 0;
QString local_path;
};
@@ -107,17 +102,10 @@ class ShareTransferModel : public QAbstractListModel {
std::vector<Row> transfers_;
};
class Backend
: public QObject,
public nearby::sharing::linux::app::NearbySharingDbusClient::Observer {
class Backend : public QObject,
public nearby::sharing::ShareTargetDiscoveredCallback {
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString statusText READ statusText NOTIFY statusTextChanged)
Q_PROPERTY(bool receiveRegistered READ receiveRegistered NOTIFY statusChanged)
Q_PROPERTY(
bool discoveryRegistered READ discoveryRegistered NOTIFY statusChanged)
Q_PROPERTY(bool scanning READ scanning NOTIFY statusChanged)
Q_PROPERTY(bool transferring READ transferring NOTIFY statusChanged)
Q_PROPERTY(QAbstractListModel* targets READ targets CONSTANT)
Q_PROPERTY(QAbstractListModel* transfers READ transfers CONSTANT)
@@ -125,63 +113,73 @@ class Backend
explicit Backend(QObject* parent = nullptr);
~Backend() override;
QString statusText() const { return status_text_; }
bool receiveRegistered() const { return status_.receive_registered; }
bool discoveryRegistered() const { return status_.discovery_registered; }
bool scanning() const { return status_.is_scanning; }
bool transferring() const { return status_.is_transferring; }
QAbstractListModel* targets() { return &targets_; }
QAbstractListModel* transfers() { return &transfers_; }
Q_INVOKABLE void startReceive();
Q_INVOKABLE void stopReceive();
Q_INVOKABLE void startDiscovery();
Q_INVOKABLE void stopDiscovery();
Q_INVOKABLE void sendFile(qint64 share_target_id, const QString& path);
Q_INVOKABLE void prepareOutgoingTransfer(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 statusTextChanged();
void statusChanged();
void incomingTransfer(qint64 share_target_id, QString device_name,
QString status);
void transferUpdate(qint64 share_target_id, QString device_name,
QString status, double progress);
void incomingTransfer(qint64 share_target_id);
private:
using Client = nearby::sharing::linux::app::NearbySharingDbusClient;
using ShareTarget = nearby::sharing::linux::app::ShareTarget;
using Status = nearby::sharing::linux::app::Status;
using Transfer = nearby::sharing::linux::app::Transfer;
using NearbySharingService = nearby::sharing::NearbySharingService;
using ShareTarget = nearby::sharing::ShareTarget;
using TransferMetadata = nearby::sharing::TransferMetadata;
void OnTargetDiscovered(const ShareTarget& target) override;
void OnTargetUpdated(const ShareTarget& target) override;
void OnTargetLost(const ShareTarget& target) override;
void OnIncomingTransfer(const std::string& direction,
const ShareTarget& target,
const Transfer& transfer) override;
void OnTransferUpdate(const std::string& direction, const ShareTarget& target,
const Transfer& transfer) override;
void OnStatusChanged(const Status& status) override;
class TransferCallback final
: public nearby::sharing::TransferUpdateCallback {
public:
TransferCallback(Backend& backend, bool receive_mode)
: backend_(backend), receive_mode_(receive_mode) {}
void ApplyTarget(const ShareTarget& target);
void RemoveTarget(const ShareTarget& target);
void ApplyStatus(const Status& status);
void ApplyCommandResult(const QString& command,
const std::tuple<bool, std::string>& result);
void RunCommand(
const QString& command,
const std::function<std::tuple<bool, std::string>()>& operation);
void SetStatusText(const QString& text);
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,
};
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);
std::function<void(NearbySharingService::StatusCodes)> StatusCallback(
QString operation);
void ReportStatus(const QString& operation,
NearbySharingService::StatusCodes status);
QString status_text_;
Status status_;
ShareTargetModel targets_;
ShareTransferModel transfers_;
std::unique_ptr<Client> client_;
bool is_incoming_transfer_ = false;
nearby::sharing::linux::NoOpAnalyticsRecorder analytics_recorder_;
nearby::sharing::linux::LinuxSharingPlatform platform_;
NearbySharingService* service_ = nullptr;
TransferCallback send_transfer_callback_;
TransferCallback receive_transfer_callback_;
Mode active_mode_ = Mode::kNone;
Mode desired_mode_ = Mode::kReceive;
bool initialized_ = false;
bool mode_operation_in_flight_ = false;
bool shutting_down_ = false;
};
+10 -19
View File
@@ -81,19 +81,7 @@ bool RequiresFullReload(const QFileInfo& changed_file) {
return changed_file.fileName() == QStringLiteral("main.qml");
}
void InstallTerminationCleanup(QApplication& app, Backend& backend) {
auto cleanup_done = std::make_shared<bool>(false);
const auto cleanup = [&backend, cleanup_done]() {
if (*cleanup_done) {
return;
}
*cleanup_done = true;
backend.stopDiscovery();
backend.stopReceive();
};
QObject::connect(&app, &QCoreApplication::aboutToQuit, &app, cleanup);
void InstallTerminationCleanup(QApplication& app) {
if (pipe(g_signal_pipe) != 0) {
return;
}
@@ -105,12 +93,11 @@ void InstallTerminationCleanup(QApplication& app, Backend& backend) {
auto* notifier = new QSocketNotifier(g_signal_pipe[0],
QSocketNotifier::Read, &app);
QObject::connect(notifier, &QSocketNotifier::activated, &app,
[&app, notifier, cleanup](int socket) {
[&app, notifier](int socket) {
notifier->setEnabled(false);
char buffer[32];
while (read(socket, buffer, sizeof(buffer)) > 0) {
}
cleanup();
app.quit();
});
@@ -127,9 +114,9 @@ void InstallTerminationCleanup(QApplication& app, Backend& backend) {
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
QQmlApplicationEngine engine;
Backend backend;
InstallTerminationCleanup(app, backend);
QQmlApplicationEngine engine;
InstallTerminationCleanup(app);
const int fontId = QFontDatabase::addApplicationFont(":/googlesans_var.ttf");
@@ -192,7 +179,9 @@ int main(int argc, char* argv[]) {
watcher.addPath(qml_source_dir.absolutePath());
fullReload();
return app.exec();
const int result = app.exec();
backend.shutdown();
return result;
}
engine.rootContext()->setContextProperty("backend", &backend);
@@ -208,5 +197,7 @@ int main(int argc, char* argv[]) {
engine.load(url);
return app.exec();
const int result = app.exec();
backend.shutdown();
return result;
}
@@ -1,214 +0,0 @@
#include "sharing/linux/app/nearby_sharing_dbus_client.h"
#include <utility>
namespace nearby::sharing::linux::app {
namespace {
template <typename T>
T GetField(const DbusDictionary& map, const std::string& key,
T default_value = T{}) {
auto it = map.find(key);
if (it == map.end()) {
return default_value;
}
try {
return it->second.get<T>();
} catch (const sdbus::Error&) {
return default_value;
}
}
template <typename T>
std::optional<T> GetOptionalField(const DbusDictionary& map,
const std::string& key) {
auto it = map.find(key);
if (it == map.end()) {
return std::nullopt;
}
try {
return it->second.get<T>();
} catch (const sdbus::Error&) {
return std::nullopt;
}
}
double GetProgress(const DbusDictionary& map) {
if (auto progress = GetOptionalField<double>(map, "progress")) {
return *progress;
}
if (auto progress = GetOptionalField<int32_t>(map, "progress")) {
return *progress;
}
if (auto progress = GetOptionalField<int64_t>(map, "progress")) {
return *progress;
}
return 0;
}
} // namespace
NearbySharingDbusClient::NearbySharingDbusClient(Observer* observer)
: sdbus::ProxyInterfaces<com::google::nearby::sharing_proxy>(
sdbus::ServiceName("com.google.nearby.sharing"),
sdbus::ObjectPath("/com/google/nearby/sharing")),
observer_(observer) {
registerProxy();
}
NearbySharingDbusClient::~NearbySharingDbusClient() {
unregisterProxy();
}
std::tuple<bool, std::string> NearbySharingDbusClient::StartReceive() {
return com::google::nearby::sharing_proxy::StartReceive();
}
std::tuple<bool, std::string> NearbySharingDbusClient::StopReceive() {
return com::google::nearby::sharing_proxy::StopReceive();
}
std::tuple<bool, std::string> NearbySharingDbusClient::StartDiscovery() {
return com::google::nearby::sharing_proxy::StartDiscovery();
}
std::tuple<bool, std::string> NearbySharingDbusClient::StopDiscovery() {
return com::google::nearby::sharing_proxy::StopDiscovery();
}
std::tuple<bool, std::string> NearbySharingDbusClient::SendFile(
int64_t share_target_id, const std::string& path) {
return com::google::nearby::sharing_proxy::SendFile(share_target_id, path);
}
std::tuple<bool, std::string> NearbySharingDbusClient::Accept(
int64_t share_target_id) {
return com::google::nearby::sharing_proxy::Accept(share_target_id);
}
std::tuple<bool, std::string> NearbySharingDbusClient::Reject(
int64_t share_target_id) {
return com::google::nearby::sharing_proxy::Reject(share_target_id);
}
std::tuple<bool, std::string> NearbySharingDbusClient::Cancel(
int64_t share_target_id) {
return com::google::nearby::sharing_proxy::Cancel(share_target_id);
}
ShareTarget NearbySharingDbusClient::ConvertToShareTarget(
const DbusDictionary& map) {
ShareTarget target;
target.id = GetField<int64_t>(map, "id");
target.device_name = GetField<std::string>(map, "device_name");
target.type = GetField<int32_t>(map, "type");
target.is_incoming = GetField<bool>(map, "is_incoming");
target.is_known = GetField<bool>(map, "is_known");
target.device_id = GetField<std::string>(map, "device_id");
target.for_self_share = GetField<bool>(map, "for_self_share");
target.vendor_id = GetField<int32_t>(map, "vendor_id");
target.receive_disabled = GetField<bool>(map, "receive_disabled");
return target;
}
Transfer NearbySharingDbusClient::ConvertToTransfer(const DbusDictionary& map) {
Transfer transfer;
transfer.status = GetField<std::string>(map, "status");
transfer.progress = GetProgress(map);
transfer.transferred_bytes = GetField<int64_t>(map, "transferred_bytes");
transfer.total_bytes = GetField<int64_t>(map, "total_bytes");
transfer.transfer_speed = GetField<int64_t>(map, "transfer_speed");
transfer.estimated_time_remaining =
GetField<int64_t>(map, "estimated_time_remaining");
transfer.total_attachments_count =
GetField<int32_t>(map, "total_attachments_count");
transfer.transferred_attachments_count =
GetField<int32_t>(map, "transferred_attachments_count");
transfer.is_final_status = GetField<bool>(map, "is_final_status");
transfer.is_self_share = GetField<bool>(map, "is_self_share");
transfer.binding_id = GetField<std::string>(map, "binding_id");
transfer.token = GetOptionalField<std::string>(map, "token");
transfer.in_progress_attachment_id =
GetOptionalField<int64_t>(map, "in_progress_attachment_id");
transfer.in_progress_attachment_transferred_bytes = GetOptionalField<int64_t>(
map, "in_progress_attachment_transferred_bytes");
transfer.in_progress_attachment_total_bytes =
GetOptionalField<int64_t>(map, "in_progress_attachment_total_bytes");
return transfer;
}
Status NearbySharingDbusClient::ConvertToStatus(const DbusDictionary& map) {
Status status;
status.receive_registered = GetField<bool>(map, "receive_registered");
status.discovery_registered = GetField<bool>(map, "discovery_registered");
status.is_transferring = GetField<bool>(map, "is_transferring");
status.is_scanning = GetField<bool>(map, "is_scanning");
status.bluetooth_present = GetField<bool>(map, "bluetooth_present");
status.bluetooth_powered = GetField<bool>(map, "bluetooth_powered");
status.lan_connected = GetField<bool>(map, "lan_connected");
auto raw_targets =
GetOptionalField<std::vector<DbusDictionary>>(map, "targets");
if (raw_targets.has_value()) {
status.targets.reserve(raw_targets->size());
for (const auto& target : *raw_targets) {
status.targets.push_back(ConvertToShareTarget(target));
}
}
return status;
}
void NearbySharingDbusClient::onTargetDiscovered(
const DbusDictionary& share_target) {
if (observer_ == nullptr) {
return;
}
observer_->OnTargetDiscovered(ConvertToShareTarget(share_target));
}
void NearbySharingDbusClient::onTargetUpdated(
const DbusDictionary& share_target) {
if (observer_ == nullptr) {
return;
}
observer_->OnTargetUpdated(ConvertToShareTarget(share_target));
}
void NearbySharingDbusClient::onTargetLost(const DbusDictionary& share_target) {
if (observer_ == nullptr) {
return;
}
observer_->OnTargetLost(ConvertToShareTarget(share_target));
}
void NearbySharingDbusClient::onIncomingTransfer(
const std::string& direction, const DbusDictionary& share_target,
const DbusDictionary& transfer) {
if (observer_ == nullptr) {
return;
}
observer_->OnIncomingTransfer(direction, ConvertToShareTarget(share_target),
ConvertToTransfer(transfer));
}
void NearbySharingDbusClient::onTransferUpdate(
const std::string& direction, const DbusDictionary& share_target,
const DbusDictionary& transfer) {
if (observer_ == nullptr) {
return;
}
observer_->OnTransferUpdate(direction, ConvertToShareTarget(share_target),
ConvertToTransfer(transfer));
}
void NearbySharingDbusClient::onStatusChanged(const DbusDictionary& status) {
if (observer_ == nullptr) {
return;
}
observer_->OnStatusChanged(ConvertToStatus(status));
}
} // namespace nearby::sharing::linux::app
@@ -1,111 +0,0 @@
#pragma once
#include <cstdint>
#include <map>
#include <optional>
#include <string>
#include <tuple>
#include <vector>
#include <sdbus-c++/sdbus-c++.h>
#include "sharing/linux/daemon/nearby_sharing_client.h"
namespace nearby::sharing::linux::app {
using DbusDictionary = std::map<std::string, sdbus::Variant>;
struct ShareTarget {
int64_t id = 0;
std::string device_name;
int32_t type = 0;
bool is_incoming = false;
bool is_known = false;
std::string device_id;
bool for_self_share = false;
int32_t vendor_id = 0;
bool receive_disabled = false;
};
struct Transfer {
std::string status;
double progress = 0;
int64_t transferred_bytes = 0;
int64_t total_bytes = 0;
int64_t transfer_speed = 0;
int64_t estimated_time_remaining = 0;
int32_t total_attachments_count = 0;
int32_t transferred_attachments_count = 0;
bool is_final_status = false;
bool is_self_share = false;
std::string binding_id;
std::optional<std::string> token;
std::optional<int64_t> in_progress_attachment_id;
std::optional<int64_t> in_progress_attachment_transferred_bytes;
std::optional<int64_t> in_progress_attachment_total_bytes;
};
struct Status {
bool receive_registered = false;
bool discovery_registered = false;
bool is_transferring = false;
bool is_scanning = false;
bool bluetooth_present = false;
bool bluetooth_powered = false;
bool lan_connected = false;
std::vector<ShareTarget> targets;
};
class NearbySharingDbusClient
: public sdbus::ProxyInterfaces<com::google::nearby::sharing_proxy> {
public:
struct Observer {
virtual ~Observer() = default;
virtual void OnTargetDiscovered(const ShareTarget& target) {}
virtual void OnTargetUpdated(const ShareTarget& target) {}
virtual void OnTargetLost(const ShareTarget& target) {}
virtual void OnIncomingTransfer(const std::string& direction,
const ShareTarget& target,
const Transfer& transfer) {}
virtual void OnTransferUpdate(const std::string& direction,
const ShareTarget& target,
const Transfer& transfer) {}
virtual void OnStatusChanged(const Status& status) {}
};
explicit NearbySharingDbusClient(Observer* observer);
~NearbySharingDbusClient();
NearbySharingDbusClient(const NearbySharingDbusClient&) = delete;
NearbySharingDbusClient& operator=(const NearbySharingDbusClient&) = delete;
std::tuple<bool, std::string> StartReceive();
std::tuple<bool, std::string> StopReceive();
std::tuple<bool, std::string> StartDiscovery();
std::tuple<bool, std::string> StopDiscovery();
std::tuple<bool, std::string> SendFile(int64_t share_target_id,
const std::string& path);
std::tuple<bool, std::string> Accept(int64_t share_target_id);
std::tuple<bool, std::string> Reject(int64_t share_target_id);
std::tuple<bool, std::string> Cancel(int64_t share_target_id);
static ShareTarget ConvertToShareTarget(const DbusDictionary& map);
static Transfer ConvertToTransfer(const DbusDictionary& map);
static Status ConvertToStatus(const DbusDictionary& map);
private:
void onTargetDiscovered(const DbusDictionary& share_target) override;
void onTargetUpdated(const DbusDictionary& share_target) override;
void onTargetLost(const DbusDictionary& share_target) override;
void onIncomingTransfer(const std::string& direction,
const DbusDictionary& share_target,
const DbusDictionary& transfer) override;
void onTransferUpdate(const std::string& direction,
const DbusDictionary& share_target,
const DbusDictionary& transfer) override;
void onStatusChanged(const DbusDictionary& status) override;
Observer* observer_ = nullptr;
};
} // namespace nearby::sharing::linux::app
-59
View File
@@ -1,59 +0,0 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
cc_binary(
name = "nearby_sharing_daemon",
srcs = ["main.cc"],
deps = [
":nearby_sharing_dbus_service",
"//connections/implementation/flags:connections_flags",
"//internal/flags:nearby_flags",
"//sharing:nearby_sharing_service",
"//sharing/flags/generated:generated_flags",
"//sharing/linux:linux_sharing_platform",
"//sharing/proto:enums_cc_proto",
"@com_google_absl//absl/time",
"@sdbus_cpp",
],
)
cc_library(
name = "nearby_sharing_dbus_client_glue",
hdrs = ["nearby_sharing_client.h"],
visibility = ["//visibility:public"],
deps = ["@sdbus_cpp"],
)
cc_library(
name = "nearby_sharing_dbus_service",
srcs = ["nearby_sharing_dbus_service.cc"],
hdrs = [
"nearby_sharing_dbus_service.h",
"nearby_sharing_server.h",
"nearby_sharing_client.h",
],
deps = [
"//internal/base:file_path",
"//sharing:attachments",
"//sharing:nearby_sharing_service",
"//sharing:transfer_metadata",
"//sharing:types",
"@com_google_absl//absl/synchronization",
"@sdbus_cpp",
],
)
cc_test(
name = "nearby_sharing_dbus_service_test",
srcs = ["nearby_sharing_dbus_service_test.cc"],
deps = [
":nearby_sharing_dbus_service",
"//internal/platform/implementation/linux:linux",
"//sharing:attachments",
"//sharing:transfer_metadata",
"//sharing:types",
"@com_google_googletest//:gtest_main",
"@sdbus_cpp",
],
)
-165
View File
@@ -1,165 +0,0 @@
#include <signal.h>
#include <unistd.h>
#include <atomic>
#include <condition_variable>
#include <cstdlib>
#include <iostream>
#include <mutex>
#include <optional>
#include <string>
#include <sdbus-c++/sdbus-c++.h>
#include "absl/time/time.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "internal/flags/nearby_flags.h"
#include "sharing/flags/generated/nearby_sharing_feature_flags.h"
#include "sharing/linux/daemon/nearby_sharing_dbus_service.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/nearby_sharing_service_factory.h"
#include "sharing/nearby_sharing_settings.h"
#include "sharing/proto/enums.pb.h"
namespace nearby::sharing::linux {
namespace {
std::atomic<bool> g_interrupted = false;
sdbus::IConnection* g_bus = nullptr;
void HandleSignal(int signal) {
static_cast<void>(signal);
g_interrupted = true;
if (g_bus != nullptr) {
g_bus->leaveEventLoop();
}
}
std::string GetHostname() {
char hostname[256] = {};
if (gethostname(hostname, sizeof(hostname)) == 0 && hostname[0] != '\0') {
return std::string(hostname);
}
return "LinuxShare";
}
std::string GetDeviceName(int argc, char** argv) {
for (int i = 1; i < argc; ++i) {
std::string arg = argv[i];
if (arg == "--name" && i + 1 < argc) {
return argv[i + 1];
}
}
const char* env_name = std::getenv("NEARBY_DEVICE_NAME");
if (env_name != nullptr && *env_name != '\0') {
return env_name;
}
return GetHostname();
}
template <typename Invoker>
NearbySharingService::StatusCodes WaitForStatus(Invoker invoker) {
std::mutex mutex;
std::condition_variable cv;
std::optional<NearbySharingService::StatusCodes> status;
invoker([&](NearbySharingService::StatusCodes callback_status) {
{
std::lock_guard<std::mutex> lock(mutex);
status = callback_status;
}
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [&] { return status.has_value(); });
return *status;
}
void ConfigureFlags() {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::sharing::config_package_nearby::nearby_sharing_feature::
kEnableBleForTransfer,
true);
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableBleL2cap,
true);
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kRefactorBleL2cap,
true);
}
bool ConfigureSharingService(NearbySharingService& service,
const std::string& device_name) {
service.GetSettings()->SetDataUsage(proto::WIFI_ONLY_DATA_USAGE);
service.GetSettings()->SetDeviceName(
device_name, [](DeviceNameValidationResult validation_result) {
static_cast<void>(validation_result);
});
auto status = WaitForStatus([&](auto callback) {
service.SetVisibility(proto::DEVICE_VISIBILITY_EVERYONE,
absl::ZeroDuration(), std::move(callback));
});
if (status != NearbySharingService::StatusCodes::kOk) {
std::cerr << "SetVisibility failed: "
<< NearbySharingService::StatusCodeToString(status) << std::endl;
return false;
}
return true;
}
} // namespace
} // namespace nearby::sharing::linux
int main(int argc, char** argv) {
signal(SIGINT, nearby::sharing::linux::HandleSignal);
signal(SIGTERM, nearby::sharing::linux::HandleSignal);
nearby::sharing::linux::ConfigureFlags();
const std::string device_name =
nearby::sharing::linux::GetDeviceName(argc, argv);
auto analytics_recorder = nearby::sharing::linux::NoOpAnalyticsRecorder();
auto linux_platform =
nearby::sharing::linux::LinuxSharingPlatform(device_name);
auto* service =
nearby::sharing::NearbySharingServiceFactory::GetInstance()
->CreateSharingService(linux_platform, &analytics_recorder,
/*event_logger=*/nullptr,
/*supports_file_sync=*/false);
if (service == nullptr) {
std::cerr << "failed to create NearbySharingService" << std::endl;
return 1;
}
if (!nearby::sharing::linux::ConfigureSharingService(*service, device_name)) {
nearby::sharing::linux::WaitForStatus(
[&](auto callback) { service->Shutdown(std::move(callback)); });
return 1;
}
auto bus = sdbus::createSessionBusConnection(
sdbus::ServiceName("com.google.nearby.sharing"));
nearby::sharing::linux::g_bus = bus.get();
auto object = sdbus::createObject(
*bus, sdbus::ObjectPath("/com/google/nearby/sharing"));
nearby::sharing::linux::NearbySharingDbusService dbus_service(
*object, *service, [&bus]() { bus->leaveEventLoop(); });
dbus_service.EmitStatusChanged();
try {
bus->enterEventLoop();
} catch (const sdbus::Error& error) {
std::cerr << "D-Bus event loop failed: " << error.getName() << ": "
<< error.getMessage() << std::endl;
dbus_service.ShutdownService();
nearby::sharing::linux::g_bus = nullptr;
return 1;
}
dbus_service.ShutdownService();
nearby::sharing::linux::g_bus = nullptr;
return nearby::sharing::linux::g_interrupted ? 130 : 0;
}
@@ -1,174 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__sharing_linux_daemon_nearby_sharing_client_h__proxy__H__
#define __sdbuscpp__sharing_linux_daemon_nearby_sharing_client_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace com {
namespace google {
namespace nearby {
class sharing_proxy {
public:
static constexpr const char* INTERFACE_NAME = "com.google.nearby.sharing";
protected:
sharing_proxy(sdbus::IProxy& proxy) : m_proxy(proxy) {}
sharing_proxy(const sharing_proxy&) = delete;
sharing_proxy& operator=(const sharing_proxy&) = delete;
sharing_proxy(sharing_proxy&&) = delete;
sharing_proxy& operator=(sharing_proxy&&) = delete;
~sharing_proxy() = default;
void registerProxy() {
m_proxy.uponSignal("TargetDiscovered")
.onInterface(INTERFACE_NAME)
.call(
[this](const std::map<std::string, sdbus::Variant>& share_target) {
this->onTargetDiscovered(share_target);
});
m_proxy.uponSignal("TargetUpdated")
.onInterface(INTERFACE_NAME)
.call(
[this](const std::map<std::string, sdbus::Variant>& share_target) {
this->onTargetUpdated(share_target);
});
m_proxy.uponSignal("TargetLost")
.onInterface(INTERFACE_NAME)
.call(
[this](const std::map<std::string, sdbus::Variant>& share_target) {
this->onTargetLost(share_target);
});
m_proxy.uponSignal("IncomingTransfer")
.onInterface(INTERFACE_NAME)
.call([this](const std::string& direction,
const std::map<std::string, sdbus::Variant>& share_target,
const std::map<std::string, sdbus::Variant>& transfer) {
this->onIncomingTransfer(direction, share_target, transfer);
});
m_proxy.uponSignal("TransferUpdate")
.onInterface(INTERFACE_NAME)
.call([this](const std::string& direction,
const std::map<std::string, sdbus::Variant>& share_target,
const std::map<std::string, sdbus::Variant>& transfer) {
this->onTransferUpdate(direction, share_target, transfer);
});
m_proxy.uponSignal("StatusChanged")
.onInterface(INTERFACE_NAME)
.call([this](const std::map<std::string, sdbus::Variant>& status) {
this->onStatusChanged(status);
});
}
virtual void onTargetDiscovered(
const std::map<std::string, sdbus::Variant>& share_target) = 0;
virtual void onTargetUpdated(
const std::map<std::string, sdbus::Variant>& share_target) = 0;
virtual void onTargetLost(
const std::map<std::string, sdbus::Variant>& share_target) = 0;
virtual void onIncomingTransfer(
const std::string& direction,
const std::map<std::string, sdbus::Variant>& share_target,
const std::map<std::string, sdbus::Variant>& transfer) = 0;
virtual void onTransferUpdate(
const std::string& direction,
const std::map<std::string, sdbus::Variant>& share_target,
const std::map<std::string, sdbus::Variant>& transfer) = 0;
virtual void onStatusChanged(
const std::map<std::string, sdbus::Variant>& status) = 0;
public:
std::tuple<bool, std::string> StartReceive() {
std::tuple<bool, std::string> result;
m_proxy.callMethod("StartReceive")
.onInterface(INTERFACE_NAME)
.storeResultsTo(result);
return result;
}
std::tuple<bool, std::string> StopReceive() {
std::tuple<bool, std::string> result;
m_proxy.callMethod("StopReceive")
.onInterface(INTERFACE_NAME)
.storeResultsTo(result);
return result;
}
std::tuple<bool, std::string> StartDiscovery() {
std::tuple<bool, std::string> result;
m_proxy.callMethod("StartDiscovery")
.onInterface(INTERFACE_NAME)
.storeResultsTo(result);
return result;
}
std::tuple<bool, std::string> StopDiscovery() {
std::tuple<bool, std::string> result;
m_proxy.callMethod("StopDiscovery")
.onInterface(INTERFACE_NAME)
.storeResultsTo(result);
return result;
}
std::tuple<bool, std::string> SendFile(const int64_t& share_target_id,
const std::string& path) {
std::tuple<bool, std::string> result;
m_proxy.callMethod("SendFile")
.onInterface(INTERFACE_NAME)
.withArguments(share_target_id, path)
.storeResultsTo(result);
return result;
}
std::tuple<bool, std::string> Accept(const int64_t& share_target_id) {
std::tuple<bool, std::string> result;
m_proxy.callMethod("Accept")
.onInterface(INTERFACE_NAME)
.withArguments(share_target_id)
.storeResultsTo(result);
return result;
}
std::tuple<bool, std::string> Reject(const int64_t& share_target_id) {
std::tuple<bool, std::string> result;
m_proxy.callMethod("Reject")
.onInterface(INTERFACE_NAME)
.withArguments(share_target_id)
.storeResultsTo(result);
return result;
}
std::tuple<bool, std::string> Cancel(const int64_t& share_target_id) {
std::tuple<bool, std::string> result;
m_proxy.callMethod("Cancel")
.onInterface(INTERFACE_NAME)
.withArguments(share_target_id)
.storeResultsTo(result);
return result;
}
std::tuple<bool, std::string> Shutdown() {
std::tuple<bool, std::string> result;
m_proxy.callMethod("Shutdown")
.onInterface(INTERFACE_NAME)
.storeResultsTo(result);
return result;
}
private:
sdbus::IProxy& m_proxy;
};
} // namespace nearby
} // namespace google
} // namespace com
#endif
@@ -1,134 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<node name="/com/google/nearby/sharing">
<!--
D-Bus contract for the Linux Nearby Sharing daemon.
The daemon internally exposes a socket-based JSON IPC model with:
- commands: start_receive, stop_receive, start_discovery,
stop_discovery, send_file, accept, reject, cancel, shutdown
- events: target_discovered, target_updated, target_lost,
incoming_transfer, transfer_update, status_changed
This interface preserves that surface with typed D-Bus methods and
signals. Flexible payloads that were JSON objects are represented as
a{sv} dictionaries so the daemon can expose the same field set without
forcing a brittle fixed struct encoding for optional values.
Common dictionary payloads:
- share_target a{sv}
id x
device_name s
type i
is_incoming b
is_known b
device_id s
for_self_share b
vendor_id i
receive_disabled b
- transfer a{sv}
status s
progress i
transferred_bytes x
total_bytes x
transfer_speed x
estimated_time_remaining x
total_attachments_count i
transferred_attachments_count i
is_final_status b
is_self_share b
binding_id s
token s (optional)
in_progress_attachment_id x (optional)
in_progress_attachment_transferred_bytes x (optional)
in_progress_attachment_total_bytes x (optional)
- status a{sv}
receive_registered b
discovery_registered b
is_transferring b
is_scanning b
bluetooth_present b
bluetooth_powered b
lan_connected b
targets aa{sv}
-->
<interface name="com.google.nearby.sharing">
<method name="StartReceive">
<arg name="ok" type="b" direction="out"/>
<arg name="message" type="s" direction="out"/>
</method>
<method name="StopReceive">
<arg name="ok" type="b" direction="out"/>
<arg name="message" type="s" direction="out"/>
</method>
<method name="StartDiscovery">
<arg name="ok" type="b" direction="out"/>
<arg name="message" type="s" direction="out"/>
</method>
<method name="StopDiscovery">
<arg name="ok" type="b" direction="out"/>
<arg name="message" type="s" direction="out"/>
</method>
<method name="SendFile">
<arg name="share_target_id" type="x" direction="in"/>
<arg name="path" type="s" direction="in"/>
<arg name="ok" type="b" direction="out"/>
<arg name="message" type="s" direction="out"/>
</method>
<method name="Accept">
<arg name="share_target_id" type="x" direction="in"/>
<arg name="ok" type="b" direction="out"/>
<arg name="message" type="s" direction="out"/>
</method>
<method name="Reject">
<arg name="share_target_id" type="x" direction="in"/>
<arg name="ok" type="b" direction="out"/>
<arg name="message" type="s" direction="out"/>
</method>
<method name="Cancel">
<arg name="share_target_id" type="x" direction="in"/>
<arg name="ok" type="b" direction="out"/>
<arg name="message" type="s" direction="out"/>
</method>
<method name="Shutdown">
<arg name="ok" type="b" direction="out"/>
<arg name="message" type="s" direction="out"/>
</method>
<signal name="TargetDiscovered">
<arg name="share_target" type="a{sv}"/>
</signal>
<signal name="TargetUpdated">
<arg name="share_target" type="a{sv}"/>
</signal>
<signal name="TargetLost">
<arg name="share_target" type="a{sv}"/>
</signal>
<signal name="IncomingTransfer">
<arg name="direction" type="s"/>
<arg name="share_target" type="a{sv}"/>
<arg name="transfer" type="a{sv}"/>
</signal>
<signal name="TransferUpdate">
<arg name="direction" type="s"/>
<arg name="share_target" type="a{sv}"/>
<arg name="transfer" type="a{sv}"/>
</signal>
<signal name="StatusChanged">
<arg name="status" type="a{sv}"/>
</signal>
</interface>
</node>
@@ -1,441 +0,0 @@
#include "sharing/linux/daemon/nearby_sharing_dbus_service.h"
#include <condition_variable>
#include <filesystem>
#include <memory>
#include <mutex>
#include <optional>
#include <utility>
#include <vector>
#include "internal/base/file_path.h"
#include "sharing/advertisement.h"
#include "sharing/file_attachment.h"
namespace nearby::sharing::linux {
namespace {
std::string StatusCodeToString(NearbySharingService::StatusCodes status) {
return NearbySharingService::StatusCodeToString(status);
}
std::tuple<bool, std::string> StatusResult(
NearbySharingService::StatusCodes status) {
return {status == NearbySharingService::StatusCodes::kOk,
StatusCodeToString(status)};
}
std::unique_ptr<AttachmentContainer> CreateFileAttachments(
const std::string& file_path) {
AttachmentContainer::Builder builder;
builder.AddFileAttachment(FileAttachment(FilePath(file_path)));
return builder.Build();
}
template <typename Invoker>
NearbySharingService::StatusCodes WaitForStatus(Invoker invoker) {
std::mutex mutex;
std::condition_variable cv;
std::optional<NearbySharingService::StatusCodes> status;
invoker([&](NearbySharingService::StatusCodes callback_status) {
{
std::lock_guard<std::mutex> lock(mutex);
status = callback_status;
}
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [&] { return status.has_value(); });
return *status;
}
} // namespace
DbusDictionary ShareTargetToDbus(const ShareTarget& share_target) {
DbusDictionary result;
result.emplace("id", sdbus::Variant(share_target.id));
result.emplace("device_name", sdbus::Variant(share_target.device_name));
result.emplace("type",
sdbus::Variant(static_cast<int32_t>(share_target.type)));
result.emplace("is_incoming", sdbus::Variant(share_target.is_incoming));
result.emplace("is_known", sdbus::Variant(share_target.is_known));
result.emplace("device_id", sdbus::Variant(share_target.device_id));
result.emplace("for_self_share", sdbus::Variant(share_target.for_self_share));
result.emplace("vendor_id",
sdbus::Variant(static_cast<int32_t>(share_target.vendor_id)));
result.emplace("receive_disabled",
sdbus::Variant(share_target.receive_disabled));
return result;
}
DbusDictionary TransferMetadataToDbus(
const TransferMetadata& transfer_metadata,
const AttachmentContainer& attachment_container) {
DbusDictionary result;
result.emplace("status", sdbus::Variant(TransferMetadata::StatusToString(
transfer_metadata.status())));
result.emplace(
"progress",
sdbus::Variant(static_cast<double>(transfer_metadata.progress())));
result.emplace("transferred_bytes",
sdbus::Variant(static_cast<int64_t>(
transfer_metadata.transferred_bytes())));
result.emplace(
"total_bytes",
sdbus::Variant(attachment_container.GetTotalAttachmentsSize()));
result.emplace(
"transfer_speed",
sdbus::Variant(static_cast<int64_t>(transfer_metadata.transfer_speed())));
result.emplace("estimated_time_remaining",
sdbus::Variant(static_cast<int64_t>(
transfer_metadata.estimated_time_remaining())));
result.emplace("total_attachments_count",
sdbus::Variant(transfer_metadata.total_attachments_count()));
result.emplace(
"transferred_attachments_count",
sdbus::Variant(transfer_metadata.transferred_attachments_count()));
result.emplace("is_final_status",
sdbus::Variant(transfer_metadata.is_final_status()));
result.emplace("is_self_share",
sdbus::Variant(transfer_metadata.is_self_share()));
result.emplace("binding_id", sdbus::Variant(transfer_metadata.binding_id()));
if (transfer_metadata.token().has_value()) {
result.emplace("token", sdbus::Variant(*transfer_metadata.token()));
}
if (transfer_metadata.in_progress_attachment_id().has_value()) {
result.emplace(
"in_progress_attachment_id",
sdbus::Variant(*transfer_metadata.in_progress_attachment_id()));
}
if (transfer_metadata.in_progress_attachment_transferred_bytes()
.has_value()) {
result.emplace(
"in_progress_attachment_transferred_bytes",
sdbus::Variant(static_cast<int64_t>(
*transfer_metadata.in_progress_attachment_transferred_bytes())));
}
if (transfer_metadata.in_progress_attachment_total_bytes().has_value()) {
result.emplace(
"in_progress_attachment_total_bytes",
sdbus::Variant(static_cast<int64_t>(
*transfer_metadata.in_progress_attachment_total_bytes())));
}
return result;
}
NearbySharingDbusService::TransferCallback::TransferCallback(
NearbySharingDbusService& service, bool receive_mode)
: service_(service), receive_mode_(receive_mode) {}
void NearbySharingDbusService::TransferCallback::OnTransferUpdate(
const ShareTarget& share_target,
const AttachmentContainer& attachment_container,
const TransferMetadata& transfer_metadata) {
service_.OnTransferUpdate(receive_mode_, share_target, attachment_container,
transfer_metadata);
}
NearbySharingDbusService::NearbySharingDbusService(
sdbus::IObject& object, NearbySharingService& service,
QuitCallback quit_callback)
: sharing_adaptor(object),
service_(service),
quit_callback_(std::move(quit_callback)),
send_transfer_callback_(*this, /*receive_mode=*/false),
receive_transfer_callback_(*this, /*receive_mode=*/true) {
registerAdaptor();
service_.AddObserver(this);
}
NearbySharingDbusService::~NearbySharingDbusService() {
service_.RemoveObserver(this);
ShutdownService();
}
void NearbySharingDbusService::EmitStatusChanged() {
emitStatusChanged(StatusToDbus());
}
void NearbySharingDbusService::ShutdownService() {
bool stop_receive = false;
bool stop_discovery = false;
{
absl::MutexLock lock(lock_);
if (shutdown_) {
return;
}
shutdown_ = true;
stop_receive = receive_registered_;
stop_discovery = discovery_registered_;
receive_registered_ = false;
discovery_registered_ = false;
targets_.clear();
}
if (stop_receive) {
WaitForStatus([&](auto callback) {
service_.UnregisterReceiveSurface(&receive_transfer_callback_,
std::move(callback));
});
}
if (stop_discovery) {
WaitForStatus([&](auto callback) {
service_.UnregisterSendSurface(&send_transfer_callback_,
std::move(callback));
});
}
WaitForStatus([&](auto callback) { service_.Shutdown(std::move(callback)); });
EmitStatusChanged();
}
std::tuple<bool, std::string> NearbySharingDbusService::StartReceive() {
{
absl::MutexLock lock(lock_);
if (receive_registered_) {
return {true, "receive already started"};
}
}
auto result = InvokeStatusCommand([&](auto callback) {
service_.RegisterReceiveSurface(
&receive_transfer_callback_,
NearbySharingService::ReceiveSurfaceState::kForeground,
Advertisement::BlockedVendorId::kNone, std::move(callback));
});
if (std::get<0>(result)) {
{
absl::MutexLock lock(lock_);
receive_registered_ = true;
}
EmitStatusChanged();
}
return result;
}
std::tuple<bool, std::string> NearbySharingDbusService::StopReceive() {
{
absl::MutexLock lock(lock_);
if (!receive_registered_) {
return {true, "receive already stopped"};
}
}
auto result = InvokeStatusCommand([&](auto callback) {
service_.UnregisterReceiveSurface(&receive_transfer_callback_,
std::move(callback));
});
if (std::get<0>(result)) {
{
absl::MutexLock lock(lock_);
receive_registered_ = false;
}
EmitStatusChanged();
}
return result;
}
std::tuple<bool, std::string> NearbySharingDbusService::StartDiscovery() {
{
absl::MutexLock lock(lock_);
if (discovery_registered_) {
return {true, "discovery already started"};
}
}
auto result = InvokeStatusCommand([&](auto callback) {
service_.RegisterSendSurface(
&send_transfer_callback_, this,
NearbySharingService::SendSurfaceState::kForeground,
Advertisement::BlockedVendorId::kNone,
/*disable_wifi_hotspot=*/false, std::move(callback));
});
if (std::get<0>(result)) {
{
absl::MutexLock lock(lock_);
discovery_registered_ = true;
}
EmitStatusChanged();
}
return result;
}
std::tuple<bool, std::string> NearbySharingDbusService::StopDiscovery() {
{
absl::MutexLock lock(lock_);
if (!discovery_registered_) {
return {true, "discovery already stopped"};
}
}
auto result = InvokeStatusCommand([&](auto callback) {
service_.UnregisterSendSurface(&send_transfer_callback_,
std::move(callback));
});
if (std::get<0>(result)) {
{
absl::MutexLock lock(lock_);
discovery_registered_ = false;
targets_.clear();
}
EmitStatusChanged();
}
return result;
}
std::tuple<bool, std::string> NearbySharingDbusService::SendFile(
const int64_t& share_target_id, const std::string& path) {
std::error_code file_error;
if (!std::filesystem::is_regular_file(path, file_error)) {
return {false, "path is not a regular file"};
}
{
absl::MutexLock lock(lock_);
if (targets_.find(share_target_id) == targets_.end()) {
return {false, "unknown share_target_id"};
}
}
auto attachments = CreateFileAttachments(path);
return InvokeStatusCommand([&](auto callback) {
service_.SendAttachments(share_target_id, std::move(attachments),
std::move(callback));
});
}
std::tuple<bool, std::string> NearbySharingDbusService::Accept(
const int64_t& share_target_id) {
return InvokeStatusCommand([&](auto callback) {
service_.Accept(share_target_id, std::move(callback));
});
}
std::tuple<bool, std::string> NearbySharingDbusService::Reject(
const int64_t& share_target_id) {
return InvokeStatusCommand([&](auto callback) {
service_.Reject(share_target_id, std::move(callback));
});
}
std::tuple<bool, std::string> NearbySharingDbusService::Cancel(
const int64_t& share_target_id) {
return InvokeStatusCommand([&](auto callback) {
service_.Cancel(share_target_id, std::move(callback));
});
}
std::tuple<bool, std::string> NearbySharingDbusService::Shutdown() {
ShutdownService();
if (quit_callback_) {
quit_callback_();
}
return {true, "daemon service shut down"};
}
std::tuple<bool, std::string> NearbySharingDbusService::InvokeStatusCommand(
std::function<void(std::function<void(NearbySharingService::StatusCodes)>)>
invoker) {
return StatusResult(WaitForStatus(std::move(invoker)));
}
DbusDictionary NearbySharingDbusService::StatusToDbus() const {
std::vector<DbusDictionary> targets;
bool receive_registered = false;
bool discovery_registered = false;
{
absl::MutexLock lock(lock_);
receive_registered = receive_registered_;
discovery_registered = discovery_registered_;
targets.reserve(targets_.size());
for (const auto& [id, target] : targets_) {
static_cast<void>(id);
targets.push_back(ShareTargetToDbus(target));
}
}
DbusDictionary status;
status.emplace("receive_registered", sdbus::Variant(receive_registered));
status.emplace("discovery_registered", sdbus::Variant(discovery_registered));
status.emplace("is_transferring", sdbus::Variant(service_.IsTransferring()));
status.emplace("is_scanning", sdbus::Variant(service_.IsScanning()));
status.emplace("bluetooth_present",
sdbus::Variant(service_.IsBluetoothPresent()));
status.emplace("bluetooth_powered",
sdbus::Variant(service_.IsBluetoothPowered()));
status.emplace("lan_connected", sdbus::Variant(service_.IsLanConnected()));
status.emplace("targets", sdbus::Variant(targets));
return status;
}
void NearbySharingDbusService::OnTransferUpdate(
bool receive_mode, const ShareTarget& share_target,
const AttachmentContainer& attachment_container,
const TransferMetadata& transfer_metadata) {
const std::string direction = receive_mode ? "receive" : "send";
const DbusDictionary target = ShareTargetToDbus(share_target);
const DbusDictionary transfer =
TransferMetadataToDbus(transfer_metadata, attachment_container);
if (receive_mode &&
transfer_metadata.status() ==
TransferMetadata::Status::kAwaitingLocalConfirmation) {
emitIncomingTransfer(direction, target, transfer);
} else {
emitTransferUpdate(direction, target, transfer);
}
EmitStatusChanged();
}
void NearbySharingDbusService::OnShareTargetDiscovered(
const ShareTarget& share_target) {
{
absl::MutexLock lock(lock_);
targets_[share_target.id] = share_target;
}
emitTargetDiscovered(ShareTargetToDbus(share_target));
EmitStatusChanged();
}
void NearbySharingDbusService::OnShareTargetLost(
const ShareTarget& share_target) {
{
absl::MutexLock lock(lock_);
targets_.erase(share_target.id);
}
emitTargetLost(ShareTargetToDbus(share_target));
EmitStatusChanged();
}
void NearbySharingDbusService::OnShareTargetUpdated(
const ShareTarget& share_target) {
{
absl::MutexLock lock(lock_);
targets_[share_target.id] = share_target;
}
emitTargetUpdated(ShareTargetToDbus(share_target));
EmitStatusChanged();
}
void NearbySharingDbusService::OnHighVisibilityChanged(
bool in_high_visibility) {
static_cast<void>(in_high_visibility);
EmitStatusChanged();
}
void NearbySharingDbusService::OnBluetoothStatusChanged(AdapterState state) {
static_cast<void>(state);
EmitStatusChanged();
}
void NearbySharingDbusService::OnLanStatusChanged(AdapterState state) {
static_cast<void>(state);
EmitStatusChanged();
}
void NearbySharingDbusService::OnIrrecoverableHardwareErrorReported() {
EmitStatusChanged();
}
} // namespace nearby::sharing::linux
@@ -1,105 +0,0 @@
#ifndef SHARING_LINUX_DAEMON_NEARBY_SHARING_DBUS_SERVICE_H_
#define SHARING_LINUX_DAEMON_NEARBY_SHARING_DBUS_SERVICE_H_
#include <cstdint>
#include <functional>
#include <map>
#include <string>
#include <tuple>
#include <unordered_map>
#include <sdbus-c++/sdbus-c++.h>
#include "absl/synchronization/mutex.h"
#include "sharing/attachment_container.h"
#include "sharing/linux/daemon/nearby_sharing_server.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"
namespace nearby::sharing::linux {
using DbusDictionary = std::map<std::string, sdbus::Variant>;
DbusDictionary ShareTargetToDbus(const ShareTarget& share_target);
DbusDictionary TransferMetadataToDbus(
const TransferMetadata& transfer_metadata,
const AttachmentContainer& attachment_container);
class NearbySharingDbusService final
: public com::google::nearby::sharing_adaptor,
public ShareTargetDiscoveredCallback,
public NearbySharingService::Observer {
public:
using QuitCallback = std::function<void()>;
NearbySharingDbusService(sdbus::IObject& object,
NearbySharingService& service,
QuitCallback quit_callback);
~NearbySharingDbusService() override;
NearbySharingDbusService(const NearbySharingDbusService&) = delete;
NearbySharingDbusService& operator=(const NearbySharingDbusService&) = delete;
void EmitStatusChanged();
void ShutdownService();
void OnShareTargetDiscovered(const ShareTarget& share_target) override;
void OnShareTargetLost(const ShareTarget& share_target) override;
void OnShareTargetUpdated(const ShareTarget& share_target) override;
void OnHighVisibilityChanged(bool in_high_visibility) override;
void OnBluetoothStatusChanged(AdapterState state) override;
void OnLanStatusChanged(AdapterState state) override;
void OnIrrecoverableHardwareErrorReported() override;
private:
class TransferCallback final : public TransferUpdateCallback {
public:
TransferCallback(NearbySharingDbusService& service, bool receive_mode);
void OnTransferUpdate(const ShareTarget& share_target,
const AttachmentContainer& attachment_container,
const TransferMetadata& transfer_metadata) override;
private:
NearbySharingDbusService& service_;
bool receive_mode_;
};
std::tuple<bool, std::string> StartReceive() override;
std::tuple<bool, std::string> StopReceive() override;
std::tuple<bool, std::string> StartDiscovery() override;
std::tuple<bool, std::string> StopDiscovery() override;
std::tuple<bool, std::string> SendFile(const int64_t& share_target_id,
const std::string& path) override;
std::tuple<bool, std::string> Accept(const int64_t& share_target_id) override;
std::tuple<bool, std::string> Reject(const int64_t& share_target_id) override;
std::tuple<bool, std::string> Cancel(const int64_t& share_target_id) override;
std::tuple<bool, std::string> Shutdown() override;
std::tuple<bool, std::string> InvokeStatusCommand(
std::function<
void(std::function<void(NearbySharingService::StatusCodes)>)>
invoker);
DbusDictionary StatusToDbus() const;
void OnTransferUpdate(bool receive_mode, const ShareTarget& share_target,
const AttachmentContainer& attachment_container,
const TransferMetadata& transfer_metadata);
NearbySharingService& service_;
QuitCallback quit_callback_;
TransferCallback send_transfer_callback_;
TransferCallback receive_transfer_callback_;
mutable absl::Mutex lock_;
std::unordered_map<int64_t, ShareTarget> targets_;
bool receive_registered_ = false;
bool discovery_registered_ = false;
bool shutdown_ = false;
};
} // namespace nearby::sharing::linux
#endif // SHARING_LINUX_DAEMON_NEARBY_SHARING_DBUS_SERVICE_H_
@@ -1,89 +0,0 @@
#include "sharing/linux/daemon/nearby_sharing_dbus_service.h"
#include <cstdint>
#include <string>
#include <gtest/gtest.h>
#include "sharing/attachment_container.h"
#include "sharing/common/nearby_share_enums.h"
#include "sharing/share_target.h"
#include "sharing/transfer_metadata.h"
#include "sharing/transfer_metadata_builder.h"
namespace nearby::sharing::linux {
namespace {
ShareTarget MakeShareTarget() {
ShareTarget target;
target.id = 42;
target.device_name = "Pixel";
target.type = ShareTargetType::kPhone;
target.is_incoming = true;
target.is_known = true;
target.device_id = "device-id";
target.for_self_share = true;
target.vendor_id = 7;
target.receive_disabled = true;
return target;
}
TEST(NearbySharingDbusServiceTest, ShareTargetToDbusMapsNearbyFields) {
DbusDictionary result = ShareTargetToDbus(MakeShareTarget());
EXPECT_EQ(result.at("id").get<int64_t>(), 42);
EXPECT_EQ(result.at("device_name").get<std::string>(), "Pixel");
EXPECT_EQ(result.at("type").get<int32_t>(),
static_cast<int32_t>(ShareTargetType::kPhone));
EXPECT_TRUE(result.at("is_incoming").get<bool>());
EXPECT_TRUE(result.at("is_known").get<bool>());
EXPECT_EQ(result.at("device_id").get<std::string>(), "device-id");
EXPECT_TRUE(result.at("for_self_share").get<bool>());
EXPECT_EQ(result.at("vendor_id").get<int32_t>(), 7);
EXPECT_TRUE(result.at("receive_disabled").get<bool>());
}
TEST(NearbySharingDbusServiceTest, TransferMetadataToDbusMapsNearbyFields) {
AttachmentContainer::Builder attachments_builder;
auto attachments = attachments_builder.Build();
TransferMetadata metadata =
TransferMetadataBuilder()
.set_status(TransferMetadata::Status::kInProgress)
.set_progress(25)
.set_token(std::string("1234"))
.set_is_self_share(true)
.set_transferred_bytes(1024)
.set_transfer_speed(256)
.set_estimated_time_remaining(4)
.set_total_attachments_count(2)
.set_transferred_attachments_count(1)
.set_in_progress_attachment_id(99)
.set_in_progress_attachment_transferred_bytes(512)
.set_in_progress_attachment_total_bytes(2048)
.set_binding_id("binding")
.build();
DbusDictionary result = TransferMetadataToDbus(metadata, *attachments);
EXPECT_EQ(result.at("status").get<std::string>(), "kInProgress");
EXPECT_EQ(result.at("progress").get<double>(), 25);
EXPECT_EQ(result.at("transferred_bytes").get<int64_t>(), 1024);
EXPECT_EQ(result.at("total_bytes").get<int64_t>(), 0);
EXPECT_EQ(result.at("transfer_speed").get<int64_t>(), 256);
EXPECT_EQ(result.at("estimated_time_remaining").get<int64_t>(), 4);
EXPECT_EQ(result.at("total_attachments_count").get<int>(), 2);
EXPECT_EQ(result.at("transferred_attachments_count").get<int>(), 1);
EXPECT_FALSE(result.at("is_final_status").get<bool>());
EXPECT_TRUE(result.at("is_self_share").get<bool>());
EXPECT_EQ(result.at("binding_id").get<std::string>(), "binding");
EXPECT_EQ(result.at("token").get<std::string>(), "1234");
EXPECT_EQ(result.at("in_progress_attachment_id").get<int64_t>(), 99);
EXPECT_EQ(
result.at("in_progress_attachment_transferred_bytes").get<int64_t>(),
512);
EXPECT_EQ(result.at("in_progress_attachment_total_bytes").get<int64_t>(),
2048);
}
} // namespace
} // namespace nearby::sharing::linux
@@ -1,168 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__sharing_linux_daemon_nearby_sharing_server_h__adaptor__H__
#define __sdbuscpp__sharing_linux_daemon_nearby_sharing_server_h__adaptor__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace com {
namespace google {
namespace nearby {
class sharing_adaptor {
public:
static constexpr const char* INTERFACE_NAME = "com.google.nearby.sharing";
protected:
sharing_adaptor(sdbus::IObject& object) : m_object(object) {}
sharing_adaptor(const sharing_adaptor&) = delete;
sharing_adaptor& operator=(const sharing_adaptor&) = delete;
sharing_adaptor(sharing_adaptor&&) = delete;
sharing_adaptor& operator=(sharing_adaptor&&) = delete;
~sharing_adaptor() = default;
void registerAdaptor() {
m_object
.addVTable(
sdbus::registerMethod("StartReceive")
.withOutputParamNames("ok", "message")
.implementedAs([this]() { return this->StartReceive(); }),
sdbus::registerMethod("StopReceive")
.withOutputParamNames("ok", "message")
.implementedAs([this]() { return this->StopReceive(); }),
sdbus::registerMethod("StartDiscovery")
.withOutputParamNames("ok", "message")
.implementedAs([this]() { return this->StartDiscovery(); }),
sdbus::registerMethod("StopDiscovery")
.withOutputParamNames("ok", "message")
.implementedAs([this]() { return this->StopDiscovery(); }),
sdbus::registerMethod("SendFile")
.withInputParamNames("share_target_id", "path")
.withOutputParamNames("ok", "message")
.implementedAs([this](const int64_t& share_target_id,
const std::string& path) {
return this->SendFile(share_target_id, path);
}),
sdbus::registerMethod("Accept")
.withInputParamNames("share_target_id")
.withOutputParamNames("ok", "message")
.implementedAs([this](const int64_t& share_target_id) {
return this->Accept(share_target_id);
}),
sdbus::registerMethod("Reject")
.withInputParamNames("share_target_id")
.withOutputParamNames("ok", "message")
.implementedAs([this](const int64_t& share_target_id) {
return this->Reject(share_target_id);
}),
sdbus::registerMethod("Cancel")
.withInputParamNames("share_target_id")
.withOutputParamNames("ok", "message")
.implementedAs([this](const int64_t& share_target_id) {
return this->Cancel(share_target_id);
}),
sdbus::registerMethod("Shutdown")
.withOutputParamNames("ok", "message")
.implementedAs([this]() { return this->Shutdown(); }),
sdbus::registerSignal("TargetDiscovered")
.withParameters<std::map<std::string, sdbus::Variant>>(
"share_target"),
sdbus::registerSignal("TargetUpdated")
.withParameters<std::map<std::string, sdbus::Variant>>(
"share_target"),
sdbus::registerSignal("TargetLost")
.withParameters<std::map<std::string, sdbus::Variant>>(
"share_target"),
sdbus::registerSignal("IncomingTransfer")
.withParameters<std::string,
std::map<std::string, sdbus::Variant>,
std::map<std::string, sdbus::Variant>>(
"direction", "share_target", "transfer"),
sdbus::registerSignal("TransferUpdate")
.withParameters<std::string,
std::map<std::string, sdbus::Variant>,
std::map<std::string, sdbus::Variant>>(
"direction", "share_target", "transfer"),
sdbus::registerSignal("StatusChanged")
.withParameters<std::map<std::string, sdbus::Variant>>(
"status"))
.forInterface(INTERFACE_NAME);
}
public:
void emitTargetDiscovered(
const std::map<std::string, sdbus::Variant>& share_target) {
m_object.emitSignal("TargetDiscovered")
.onInterface(INTERFACE_NAME)
.withArguments(share_target);
}
void emitTargetUpdated(
const std::map<std::string, sdbus::Variant>& share_target) {
m_object.emitSignal("TargetUpdated")
.onInterface(INTERFACE_NAME)
.withArguments(share_target);
}
void emitTargetLost(
const std::map<std::string, sdbus::Variant>& share_target) {
m_object.emitSignal("TargetLost")
.onInterface(INTERFACE_NAME)
.withArguments(share_target);
}
void emitIncomingTransfer(
const std::string& direction,
const std::map<std::string, sdbus::Variant>& share_target,
const std::map<std::string, sdbus::Variant>& transfer) {
m_object.emitSignal("IncomingTransfer")
.onInterface(INTERFACE_NAME)
.withArguments(direction, share_target, transfer);
}
void emitTransferUpdate(
const std::string& direction,
const std::map<std::string, sdbus::Variant>& share_target,
const std::map<std::string, sdbus::Variant>& transfer) {
m_object.emitSignal("TransferUpdate")
.onInterface(INTERFACE_NAME)
.withArguments(direction, share_target, transfer);
}
void emitStatusChanged(const std::map<std::string, sdbus::Variant>& status) {
m_object.emitSignal("StatusChanged")
.onInterface(INTERFACE_NAME)
.withArguments(status);
}
private:
virtual std::tuple<bool, std::string> StartReceive() = 0;
virtual std::tuple<bool, std::string> StopReceive() = 0;
virtual std::tuple<bool, std::string> StartDiscovery() = 0;
virtual std::tuple<bool, std::string> StopDiscovery() = 0;
virtual std::tuple<bool, std::string> SendFile(const int64_t& share_target_id,
const std::string& path) = 0;
virtual std::tuple<bool, std::string> Accept(
const int64_t& share_target_id) = 0;
virtual std::tuple<bool, std::string> Reject(
const int64_t& share_target_id) = 0;
virtual std::tuple<bool, std::string> Cancel(
const int64_t& share_target_id) = 0;
virtual std::tuple<bool, std::string> Shutdown() = 0;
private:
sdbus::IObject& m_object;
};
} // namespace nearby
} // namespace google
} // namespace com
#endif
-113
View File
@@ -1,113 +0,0 @@
load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands")
refresh_compile_commands(
name = "refresh_compile_commands",
# Specify the targets of interest.
# For example, specify a dict of targets and any flags required to build.
targets = {
":tui" : "",
},
# No need to add flags already in .bazelrc. They're automatically picked up.
# If you don't need flags, a list of targets is also okay, as is a single target string.
# Wildcard patterns, like //... for everything, *are* allowed here, just like a build.
# As are additional targets (+) and subtractions (-), like in bazel query https://docs.bazel.build/versions/main/query.html#expressions
# And if you're working on a header-only library, specify a test or binary target that compiles it.
)
cc_binary(
name = "tui",
srcs = [
"main.cc",
],
deps = [
#":app",
"nearby_sharing_dbus_client"
]
)
cc_library(
name ="nearby_sharing_dbus_client",
hdrs = [
'nearby_sharing_dbus_client.h'
],
srcs = [
'nearby_sharing_dbus_client.cc'
],
deps = [
"//sharing/linux/daemon:nearby_sharing_daemon",
"@sdbus_cpp",
]
)
cc_library(
name = "app",
srcs = [
"app.cc",
],
hdrs = [
"app.h",
],
deps = [
":file_picker",
":page",
"//sharing/linux/tui/ui:home_screen",
"@ftxui//:ftxui",
],
)
cc_library(
name = "page",
hdrs = [
"page.h",
],
)
cc_library(
name = "ipc_client",
srcs = [
"ipc_client.cc",
],
hdrs = [
"ipc_client.h",
],
deps = [
"@nlohmann_json//:json",
],
)
cc_test(
name = "ipc_client_test",
srcs = [
"ipc_client_test.cc",
],
deps = [
":ipc_client",
"@com_google_googletest//:gtest_main",
"@nlohmann_json//:json",
],
)
cc_library(
name = "file_picker",
srcs = [
"file_picker.cc",
],
hdrs = [
"file_picker.h",
],
)
cc_library(
name = "palette",
hdrs = [
"palette.h",
],
deps = [
"@ftxui//:ftxui",
]
)
-74
View File
@@ -1,74 +0,0 @@
#include "sharing/linux/tui/app.h"
#include <unistd.h>
#include <string>
#include "ftxui/component/component.hpp"
#include "sharing/linux/tui/ui/home_screen.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
namespace {
std::string GetHostname() {
char hostname[256] = {};
gethostname(hostname, sizeof(hostname));
return hostname;
}
} // namespace
TuiApp::TuiApp() : screen_(ScreenInteractive::Fullscreen()) {
hostname_ = GetHostname();
screen_.TrackMouse(true);
}
int TuiApp::Run() {
auto component = HomeScreen({
.hostname = hostname_,
.current_page = &current_page_,
.selected_file = &selected_file_,
.file_picker = &file_picker_,
.on_file_selected =
[this](std::string path) {
selected_file_ = path;
current_page_ = Page::Sharing;
},
.incoming_share_device_name = incoming_share_device_name_,
.incoming_share_device_type = incoming_share_device_type_,
.on_incoming_share_accept =
[this]() { current_page_ = Page::FilePicker; },
.on_incoming_share_decline =
[this]() { current_page_ = Page::FilePicker; },
});
auto app =
CatchEvent(component, [this](Event event) { return HandleEvent(event); });
screen_.Loop(app);
return 0;
}
bool TuiApp::HandleEvent(Event event) {
if (event == Event::Character('q') || event == Event::Escape) {
screen_.ExitLoopClosure()();
return true;
}
if (event == Event::Backspace) {
if (current_page_ == Page::Sharing) {
current_page_ = Page::FilePicker;
selected_file_.clear();
return true;
}
if (current_page_ == Page::IncomingShare) {
current_page_ = Page::FilePicker;
return true;
}
}
return false;
}
} // namespace nearby::sharing::linux_tui
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#include <string>
#include "ftxui/component/screen_interactive.hpp"
#include "sharing/linux/tui/components/share_target.h"
#include "sharing/linux/tui/file_picker.h"
#include "sharing/linux/tui/page.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
class TuiApp {
public:
TuiApp();
int Run();
private:
ScreenInteractive screen_;
ZenityFilePicker file_picker_;
std::string hostname_;
std::string selected_file_;
};
} // namespace nearby::sharing::linux_tui
-68
View File
@@ -1,68 +0,0 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
cc_library(
name = "icons",
srcs = [
"file_icon.cc",
"brand.cc",
"laptop_icon.cc",
"phone_icon.cc",
"tablet_icon.cc",
],
hdrs = [
"file_icon.h",
"brand.h",
"laptop_icon.h",
"phone_icon.h",
"tablet_icon.h",
],
deps = [
"@ftxui//:ftxui",
],
)
cc_library(
name = "share_target",
srcs = [
"share_target.cc",
],
hdrs = [
"share_target.h",
],
deps = [
"@ftxui//:ftxui",
"//sharing/linux/tui:palette",
":icons",
],
)
cc_library(
name = "incoming_share_card",
srcs = [
"incoming_share_card.cc",
],
hdrs = [
"incoming_share_card.h",
],
deps = [
":share_target",
"//sharing/linux/tui:palette",
"@ftxui//:ftxui",
],
)
cc_library(
name = "file_picker_card",
srcs = [
"file_picker_card.cc",
],
hdrs = [
"file_picker_card.h",
],
deps = [
":icons",
"//sharing/linux/tui:file_picker",
"//sharing/linux/tui:palette",
"@ftxui//:ftxui",
],
)
-15
View File
@@ -1,15 +0,0 @@
#include "sharing/linux/tui/components/brand.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element Brand() {
return vbox({
text(" ___ _ _ ___ _ "),
text(" / _ \\ _ _(_)__| |__ / __| |_ __ _ _ _ ___ "),
text(" | (_) | || | / _| / / \\__ \\ ' \\/ _` | '_/ -_)"),
text(" \\__\\_\\\\_,_|_\\__|_\\_\\ |___/_||_\\__,_|_| \\___|"),
text(" "),
});
}
} // namespace nearby::sharing::linux_tui
-10
View File
@@ -1,10 +0,0 @@
#pragma once
#include "ftxui/dom/elements.hpp"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element Brand();
} // namespace nearby::sharing::linux_tui
-30
View File
@@ -1,30 +0,0 @@
#include "sharing/linux/tui/components/file_icon.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element FileIcon(FileIconSize size) {
if (size == FileIconSize::Small) {
return vbox({
text(" ______ ") | center,
text(" / | | ") | center,
text(" /__| | ") | center,
text(" | ----- | ") | center,
text(" | ----- | ") | center,
text(" |_______| ") | center,
});
}
return vbox({
text(" __________ ") | center,
text(" / | | ") | center,
text(" /__| | ") | center,
text(" | --------- | ") | center,
text(" | --------- | ") | center,
text(" | --------- | ") | center,
text(" | --------- | ") | center,
text(" |___________| ") | center,
});
}
} // namespace nearby::sharing::linux_tui
-15
View File
@@ -1,15 +0,0 @@
#pragma once
#include "ftxui/dom/elements.hpp"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
enum class FileIconSize {
Large,
Small,
};
Element FileIcon(FileIconSize size);
} // namespace nearby::sharing::linux_tui
@@ -1,67 +0,0 @@
#include "sharing/linux/tui/components/file_picker_card.h"
#include <memory>
#include "ftxui/dom/elements.hpp"
#include "ftxui/component/event.hpp"
#include "ftxui/screen/box.hpp"
#include "sharing/linux/tui/components/file_icon.h"
#include "sharing/linux/tui/palette.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Component FilePickerCard(FilePickerCardOptions options) {
auto picker_box = std::make_shared<Box>();
auto hovered = std::make_shared<bool>(false);
auto card = Renderer([picker_box, hovered] {
auto picker_card =
vbox({
FileIcon(FileIconSize::Large) | color(Palette::secondary),
separatorEmpty(),
text("Select file to share") | bold | center,
}) |
borderStyled(*hovered ? Palette::primary : Palette::secondary) |
size(WIDTH, GREATER_THAN, 33) | size(HEIGHT, EQUAL, 13) |
reflect(*picker_box);
return vbox({
filler(),
hbox({
filler(),
picker_card,
filler(),
}),
filler(),
}) |
flex;
});
return CatchEvent(card, [picker_box, hovered, options](Event event) {
if (!event.is_mouse()) {
return false;
}
auto mouse = event.mouse();
bool inside_picker =
mouse.x >= picker_box->x_min && mouse.x <= picker_box->x_max &&
mouse.y >= picker_box->y_min && mouse.y <= picker_box->y_max;
*hovered = inside_picker;
if (!inside_picker || mouse.button != Mouse::Left ||
mouse.motion != Mouse::Pressed || options.file_picker == nullptr) {
return false;
}
std::string path = options.file_picker->PickFile();
if (!path.empty() && options.on_file_selected) {
options.on_file_selected(path);
}
return true;
});
}
} // namespace nearby::sharing::linux_tui
@@ -1,19 +0,0 @@
#pragma once
#include <functional>
#include <string>
#include "ftxui/component/component.hpp"
#include "sharing/linux/tui/file_picker.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
struct FilePickerCardOptions {
FilePicker* file_picker = nullptr;
std::function<void(std::string)> on_file_selected;
};
Component FilePickerCard(FilePickerCardOptions options);
} // namespace nearby::sharing::linux_tui
@@ -1,44 +0,0 @@
#include "sharing/linux/tui/components/incoming_share_card.h"
#include "ftxui/component/component.hpp"
#include "ftxui/dom/elements.hpp"
#include "sharing/linux/tui/components/share_target.h"
#include "sharing/linux/tui/palette.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Component IncomingShareCard(IncomingShareCardOptions options) {
auto accept_button = Button("Accept", [options] {
if (options.on_accept) {
options.on_accept();
}
});
auto decline_button = Button("Decline", [options] {
if (options.on_decline) {
options.on_decline();
}
});
auto controls = Container::Horizontal({accept_button, decline_button});
return Renderer(controls, [accept_button, decline_button, options] {
return vbox({
window(text(" Incoming share ") | center,
vbox({
paragraph("Do you want to accept this share?") |
bold | center,
separator(),
ShareTarget(options.device_name, options.device_type),
separator(),
hbox({
accept_button->Render() | flex,
separator(),
decline_button->Render() | flex,
}),
})),
}) |
borderStyled(Palette::border) | bgcolor(Palette::surface) |
size(WIDTH, GREATER_THAN, 40);
});
}
} // namespace nearby::sharing::linux_tui
@@ -1,21 +0,0 @@
#pragma once
#include <functional>
#include <string>
#include "ftxui/component/component.hpp"
#include "sharing/linux/tui/components/share_target.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
struct IncomingShareCardOptions {
std::string device_name;
ShareTargetType device_type = ShareTargetType::kUnknown;
std::function<void()> on_accept;
std::function<void()> on_decline;
};
Component IncomingShareCard(IncomingShareCardOptions options);
} // namespace nearby::sharing::linux_tui
@@ -1,15 +0,0 @@
#include "sharing/linux/tui/components/laptop_icon.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element Laptop() {
return vbox({
text(" +========+ ") | center,
text(" | | ") | center,
text(" |________| ") | center,
text(" /--------\\ ") | center,
text("/__________\\") | center,
});
}
} // namespace nearby::sharing::linux_tui
@@ -1,10 +0,0 @@
#pragma once
#include "ftxui/dom/elements.hpp"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element Laptop();
} // namespace nearby::sharing::linux_tui
@@ -1,15 +0,0 @@
#include "sharing/linux/tui/components/phone_icon.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element Phone() {
return vbox({
text("______") | center,
text("| |") | center,
text("| |") | center,
text("| |") | center,
text("|____|") | center,
});
}
} // namespace nearby::sharing::linux_tui
-10
View File
@@ -1,10 +0,0 @@
#pragma once
#include "ftxui/dom/elements.hpp"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element Phone();
} // namespace nearby::sharing::linux_tui
@@ -1,32 +0,0 @@
#include "ftxui/dom/elements.hpp"
#include "sharing/linux/tui/components/share_target.h"
#include "sharing/linux/tui/components/laptop_icon.h"
#include "sharing/linux/tui/components/phone_icon.h"
#include "sharing/linux/tui/components/tablet_icon.h"
#include "sharing/linux/tui/palette.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element ShareTarget(std::string device_name, ShareTargetType device_type) {
Element icon;
switch (device_type) {
case ShareTargetType::kPhone:
icon = Phone();
break;
case ShareTargetType::kTablet:
icon = Tablet();
break;
default:
icon = Laptop();
break;
}
return vbox(
{icon, separatorLight() | dim,
paragraph(device_name) | color(Palette::secondary) | bold | center
}) |bgcolor(Palette::surface)|
size(WIDTH, EQUAL, 14) | borderStyled(Palette::border);
};
} // namespace nearby::sharing::linux_tui
@@ -1,30 +0,0 @@
#pragma once
#include "ftxui/dom/elements.hpp"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
enum class ShareTargetType {
// Unknown device type.
kUnknown = 0,
// A phone.
kPhone = 1,
// A tablet.
kTablet = 2,
// A laptop.
kLaptop = 3,
// A car.
kCar = 4,
// A foldable.
kFoldable = 5,
// An XR device.
kXR = 6,
};
Element ShareTarget(
std::string device_name,
ShareTargetType device_type
);
} // namespace nearby::sharing::linux_tui
@@ -1,15 +0,0 @@
#include "sharing/linux/tui/components/tablet_icon.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element Tablet() {
return vbox({
text("____________") | center,
text("| |") | center,
text("| |") | center,
text("|__________|") | center,
text(" ") | center,
});
}
} // namespace nearby::sharing::linux_tui
@@ -1,10 +0,0 @@
#pragma once
#include "ftxui/dom/elements.hpp"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element Tablet();
} // namespace nearby::sharing::linux_tui
-30
View File
@@ -1,30 +0,0 @@
#include "sharing/linux/tui/file_picker.h"
#include <cstdio>
#include <string>
namespace nearby::sharing::linux_tui {
std::string ZenityFilePicker::PickFile() {
FILE* pipe = popen("zenity --file-selection 2>/dev/null", "r");
if (pipe == nullptr) {
return {};
}
char buffer[4096];
std::string result;
if (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
result = buffer;
}
pclose(pipe);
if (!result.empty() && result.back() == '\n') {
result.pop_back();
}
return result;
}
} // namespace nearby::sharing::linux_tui
-19
View File
@@ -1,19 +0,0 @@
#pragma once
#include <string>
namespace nearby::sharing::linux_tui {
class FilePicker {
public:
virtual ~FilePicker() = default;
virtual std::string PickFile() = 0;
};
class ZenityFilePicker final : public FilePicker {
public:
std::string PickFile() override;
};
} // namespace nearby::sharing::linux_tui
-15
View File
@@ -1,15 +0,0 @@
#include "nearby_sharing_dbus_client.h"
#include <sdbus-c++/IConnection.h>
int main() {
auto sharing =
NearbySharingService(sdbus::ServiceName("com.google.nearby.sharing"),
sdbus::ObjectPath("/com/google/nearby/sharing"));
sharing.StartReceive();
sleep(10);
sharing.StopReceive();
// nearby::sharing::linux_tui::TuiApp app;
// return app.Run();
return 0;
}
@@ -1,143 +0,0 @@
#include "sharing/linux/tui/nearby_sharing_dbus_client.h"
// Helper to extract a value from the map with a fallback if missing or type
// mismatches
template <typename T>
T get_field(const std::map<std::string, sdbus::Variant>& map,
const std::string& key, T default_value = T{}) {
auto it = map.find(key);
if (it != map.end()) {
try {
return it->second.get<T>();
} catch (const sdbus::Error& e) {
// Log type mismatch error if necessary
}
}
return default_value;
}
// Helper for optional fields
template <typename T>
std::optional<T> get_optional_field(
const std::map<std::string, sdbus::Variant>& map, const std::string& key) {
auto it = map.find(key);
if (it != map.end()) {
try {
return it->second.get<T>();
} catch (const sdbus::Error& e) {
// Log type mismatch error if necessary
}
}
return std::nullopt;
}
// Converter: Map -> ShareTarget
ShareTarget convertToShareTarget(
const std::map<std::string, sdbus::Variant>& map) {
ShareTarget target;
target.id = get_field<int64_t>(map, "id");
target.device_name = get_field<std::string>(map, "device_name");
target.type = get_field<int32_t>(map, "type");
target.is_incoming = get_field<bool>(map, "is_incoming");
target.is_known = get_field<bool>(map, "is_known");
target.device_id = get_field<std::string>(map, "device_id");
target.for_self_share = get_field<bool>(map, "for_self_share");
target.vendor_id = get_field<int32_t>(map, "vendor_id");
target.receive_disabled = get_field<bool>(map, "receive_disabled");
return target;
}
// Converter: Map -> Transfer
Transfer convertToTransfer(const std::map<std::string, sdbus::Variant>& map) {
Transfer transfer;
transfer.status = get_field<std::string>(map, "status");
transfer.progress = get_field<int32_t>(map, "progress");
transfer.transferred_bytes = get_field<int64_t>(map, "transferred_bytes");
transfer.total_bytes = get_field<int64_t>(map, "total_bytes");
transfer.transfer_speed = get_field<int64_t>(map, "transfer_speed");
transfer.estimated_time_remaining =
get_field<int64_t>(map, "estimated_time_remaining");
transfer.total_attachments_count =
get_field<int32_t>(map, "total_attachments_count");
transfer.transferred_attachments_count =
get_field<int32_t>(map, "transferred_attachments_count");
transfer.is_final_status = get_field<bool>(map, "is_final_status");
transfer.is_self_share = get_field<bool>(map, "is_self_share");
transfer.binding_id = get_field<std::string>(map, "binding_id");
// Optional fields
transfer.token = get_optional_field<std::string>(map, "token");
transfer.in_progress_attachment_id =
get_optional_field<int64_t>(map, "in_progress_attachment_id");
transfer.in_progress_attachment_transferred_bytes =
get_optional_field<int64_t>(map,
"in_progress_attachment_transferred_bytes");
transfer.in_progress_attachment_total_bytes =
get_optional_field<int64_t>(map, "in_progress_attachment_total_bytes");
return transfer;
}
// Converter: Map -> Status
Status convertToStatus(const std::map<std::string, sdbus::Variant>& map) {
Status status;
status.receive_registered = get_field<bool>(map, "receive_registered");
status.discovery_registered = get_field<bool>(map, "discovery_registered");
status.is_transferring = get_field<bool>(map, "is_transferring");
status.is_scanning = get_field<bool>(map, "is_scanning");
status.bluetooth_present = get_field<bool>(map, "bluetooth_present");
status.bluetooth_powered = get_field<bool>(map, "bluetooth_powered");
status.lan_connected = get_field<bool>(map, "lan_connected");
// Unpack aa{sv} (vector of maps) into vector of ShareTarget structs
auto it = map.find("targets");
if (it != map.end()) {
try {
auto raw_targets =
it->second.get<std::vector<std::map<std::string, sdbus::Variant>>>();
for (const auto& target_map : raw_targets) {
status.targets.push_back(convertToShareTarget(target_map));
}
} catch (const sdbus::Error& e) {
// Handle type mismatch for targets array
}
}
return status;
}
void NearbySharingService::onTargetDiscovered(
const std::map<std::string, sdbus::Variant>& share_target) {
auto target = convertToShareTarget(share_target);
targets_[target.id] = target;
};
void NearbySharingService::onTargetUpdated(
const std::map<std::string, sdbus::Variant>& share_target) {
auto target = convertToShareTarget(share_target);
targets_[target.id] = target;
};
void NearbySharingService::onTargetLost(
const std::map<std::string, sdbus::Variant>& share_target) {
auto target = convertToShareTarget(share_target);
if (targets_.find(target.id) != targets_.end()) {
targets_.erase(target.id);
}
};
void NearbySharingService::onIncomingTransfer(
const std::string& direction,
const std::map<std::string, sdbus::Variant>& share_target,
const std::map<std::string, sdbus::Variant>& transfer) {
auto target = convertToShareTarget(share_target);
auto incoming_transfer = convertToTransfer(transfer);
incoming_transfer_ = incoming_transfer;
};
void NearbySharingService::onTransferUpdate(
const std::string& direction,
const std::map<std::string, sdbus::Variant>& share_target,
const std::map<std::string, sdbus::Variant>& transfer) {};
void NearbySharingService::onStatusChanged(
const std::map<std::string, sdbus::Variant>& share_target) {};
@@ -1,78 +0,0 @@
#include "sharing/linux/daemon/nearby_sharing_client.h"
struct ShareTarget {
int64_t id;
std::string device_name;
int32_t type;
bool is_incoming;
bool is_known;
std::string device_id;
bool for_self_share;
int32_t vendor_id;
bool receive_disabled;
};
struct Transfer {
std::string status;
int32_t progress;
int64_t transferred_bytes;
int64_t total_bytes;
int64_t transfer_speed;
int64_t estimated_time_remaining;
int32_t total_attachments_count;
int32_t transferred_attachments_count;
bool is_final_status;
bool is_self_share;
std::string binding_id;
std::optional<std::string> token;
std::optional<int64_t> in_progress_attachment_id;
std::optional<int64_t> in_progress_attachment_transferred_bytes;
std::optional<int64_t> in_progress_attachment_total_bytes;
};
struct Status {
bool receive_registered;
bool discovery_registered;
bool is_transferring;
bool is_scanning;
bool bluetooth_present;
bool bluetooth_powered;
bool lan_connected;
// aa{sv} maps to a vector of ShareTarget structs
std::vector<ShareTarget> targets;
};
class NearbySharingService
: public sdbus::ProxyInterfaces<com::google::nearby::sharing_proxy> {
public:
NearbySharingService(sdbus::ServiceName dest, sdbus::ObjectPath objectPath)
: ProxyInterfaces(std::move(dest), std::move(objectPath)) {
registerProxy();
}
~NearbySharingService() { unregisterProxy(); }
void onTargetDiscovered(
const std::map<std::string, sdbus::Variant>& share_target) override;
void onTargetUpdated(
const std::map<std::string, sdbus::Variant>& share_target) override;
void onTargetLost(
const std::map<std::string, sdbus::Variant>& share_target) override;
void onIncomingTransfer(
const std::string& direction,
const std::map<std::string, sdbus::Variant>& share_target,
const std::map<std::string, sdbus::Variant>& transfer) override;
void onTransferUpdate(
const std::string& direction,
const std::map<std::string, sdbus::Variant>& share_target,
const std::map<std::string, sdbus::Variant>& transfer) override;
void onStatusChanged(
const std::map<std::string, sdbus::Variant>& status) override;
private:
Status status_;
std::map<int, ShareTarget> targets_;
Transfer outgoing_transfer_;
Transfer incoming_transfer_;
};
-11
View File
@@ -1,11 +0,0 @@
#pragma once
namespace nearby::sharing::linux_tui {
enum class Page {
FilePicker,
Sharing,
IncomingShare,
};
} // namespace nearby::sharing::linux_tui
-46
View File
@@ -1,46 +0,0 @@
#pragma once
#include "ftxui/screen/color.hpp"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
struct Palette {
// === Core Typography & Brand ===
// Primary light text for high-contrast readability against dark backgrounds
inline static const Color primary = Color::RGB(0xF1, 0xF9, 0xF6); // Off-white mint tint
// Secondary text, inactive states, or subtle accents
inline static const Color secondary = Color::RGB(0x8A, 0xAF, 0xA4); // Muted sage gray
// Main brand accent, focused element backgrounds, or prominent icons (Unchanged)
inline static const Color accent = Color::RGB(0xA3, 0xD9, 0xC9); // Original Mint Leaf
// === Surface & Structure ===
// Active menu item highlights, selection cards, or focused component backgrounds
inline static const Color active = Color::RGB(0x23, 0x3D, 0x34); // Deep forest green tint
// Base application window background
inline static const Color base = Color::RGB(0x12, 0x1D, 0x1A); // Near-black deep mint/charcoal
// Explicit component surface background (e.g., sidebars, modals, or inactive cards)
inline static const Color surface = Color::RGB(0x19, 0x2A, 0x25); // Mid-tone dark green
// Standard UI borders, dividers, and subtle grid lines
inline static const Color border = Color::RGB(0x32, 0x52, 0x47); // Defined slate green
// Extremely muted text, placeholders, or disabled options
inline static const Color disabled = Color::RGB(0x56, 0x73, 0x6B); // Ghostly sage green
// === Functional / Status Elements ===
// Critical errors, destructive actions, or alerts (toned down for dark mode)
inline static const Color error = Color::RGB(0xE0, 0x7A, 0x7A); // Soft desaturated coral/red
// Warnings, pending indicators, or high-priority notifications
inline static const Color warning = Color::RGB(0xE6, 0xC2, 0x80); // Soft amber gold
// Success messages, online badges, or completed operations
inline static const Color success = Color::RGB(0x81, 0xC7, 0x9D); // Vibrant spring mint
};
} // namespace nearby::sharing::linux_tui
-66
View File
@@ -1,66 +0,0 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
cc_library(
name = "home_header",
srcs = [
"home_header.cc",
],
hdrs = [
"home_header.h",
],
deps = [
"@ftxui//:ftxui",
"//sharing/linux/tui/components:icons"
],
)
cc_library(
name = "sidebar",
srcs = [
"sidebar.cc",
],
hdrs = [
"sidebar.h",
],
deps = [
"//sharing/linux/tui:palette",
"//sharing/linux/tui/components:icons",
"@ftxui//:ftxui",
],
)
cc_library(
name = "file_selected_screen",
srcs = [
"file_selected_screen.cc",
],
hdrs = [
"file_selected_screen.h",
],
deps = [
"//sharing/linux/tui:palette",
"//sharing/linux/tui/components:share_target",
"@ftxui//:ftxui",
],
)
cc_library(
name = "home_screen",
srcs = [
"home_screen.cc",
],
hdrs = [
"home_screen.h",
],
deps = [
":file_selected_screen",
":home_header",
":sidebar",
"//sharing/linux/tui/components:incoming_share_card",
"//sharing/linux/tui:file_picker",
"//sharing/linux/tui:page",
"//sharing/linux/tui:palette",
"//sharing/linux/tui/components:file_picker_card",
"@ftxui//:ftxui",
],
)
@@ -1,37 +0,0 @@
#include "sharing/linux/tui/ui/file_selected_screen.h"
#include "sharing/linux/tui/components/share_target.h"
#include "sharing/linux/tui/palette.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element FileSelectedScreen(const std::string& selected_file) {
FlexboxConfig config;
config.direction = FlexboxConfig::Direction::Row;
config.wrap = FlexboxConfig::Wrap::Wrap;
config.gap_x = 1;
config.gap_y = 1;
return vbox({
hbox(
{filler(),
flexbox(
{
ShareTarget("Lasan's A55", ShareTargetType::kPhone),
ShareTarget("lasan-laptop", ShareTargetType::kLaptop),
ShareTarget("lasan-laptop", ShareTargetType::kLaptop),
ShareTarget("lasan-laptop", ShareTargetType::kLaptop),
ShareTarget("Lasan's S9+", ShareTargetType::kTablet),
ShareTarget("Lasan's S9+", ShareTargetType::kTablet),
},
config) |
flex
}),
filler(),
}) |
flex;
}
} // namespace nearby::sharing::linux_tui
@@ -1,12 +0,0 @@
#pragma once
#include <string>
#include "ftxui/dom/elements.hpp"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element FileSelectedScreen(const std::string& selected_file);
} // namespace nearby::sharing::linux_tui
-11
View File
@@ -1,11 +0,0 @@
#include "sharing/linux/tui/ui/home_header.h"
#include "sharing/linux/tui/components/brand.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element HomeHeader() {
return Brand();
}
} // namespace nearby::sharing::linux_tui
-10
View File
@@ -1,10 +0,0 @@
#pragma once
#include "ftxui/dom/elements.hpp"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element HomeHeader();
} // namespace nearby::sharing::linux_tui
-60
View File
@@ -1,60 +0,0 @@
#include "sharing/linux/tui/ui/home_screen.h"
#include "ftxui/dom/elements.hpp"
#include "sharing/linux/tui/components/file_picker_card.h"
#include "sharing/linux/tui/components/incoming_share_card.h"
#include "sharing/linux/tui/palette.h"
#include "sharing/linux/tui/ui/file_selected_screen.h"
#include "sharing/linux/tui/ui/home_header.h"
#include "sharing/linux/tui/ui/sidebar.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Component HomeScreen(HomeScreenOptions options) {
auto file_picker_card =
FilePickerCard({.file_picker = options.file_picker,
.on_file_selected = options.on_file_selected});
auto incoming_share_card =
IncomingShareCard({.device_name = options.incoming_share_device_name,
.device_type = options.incoming_share_device_type,
.on_accept = options.on_incoming_share_accept,
.on_decline = options.on_incoming_share_decline});
auto content = Container::Vertical({file_picker_card, incoming_share_card});
return Renderer(content, [file_picker_card, incoming_share_card, options] {
const std::string selected_file =
options.selected_file == nullptr ? "" : *options.selected_file;
const Page current_page = options.current_page == nullptr
? Page::FilePicker
: *options.current_page;
Element main_panel;
switch (current_page) {
case Page::FilePicker:
main_panel = file_picker_card->Render();
break;
case Page::IncomingShare:
main_panel = incoming_share_card->Render();
break;
case Page::Sharing:
main_panel = FileSelectedScreen(selected_file);
break;
}
return vbox({
HomeHeader() | color(Palette::accent),
separator(),
hbox({
Sidebar({.hostname = options.hostname,
.selected_file = selected_file}),
separator() | color(Palette::border),
main_panel | flex,
}) | flex,
}) |
bgcolor(Palette::base) | size(WIDTH, GREATER_THAN, 80) |
size(HEIGHT, GREATER_THAN, 24);
});
}
} // namespace nearby::sharing::linux_tui
-28
View File
@@ -1,28 +0,0 @@
#pragma once
#include <functional>
#include <string>
#include "ftxui/component/component.hpp"
#include "sharing/linux/tui/components/share_target.h"
#include "sharing/linux/tui/file_picker.h"
#include "sharing/linux/tui/page.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
struct HomeScreenOptions {
std::string hostname;
const Page* current_page = nullptr;
const std::string* selected_file = nullptr;
FilePicker* file_picker = nullptr;
std::function<void(std::string)> on_file_selected;
std::string incoming_share_device_name;
ShareTargetType incoming_share_device_type = ShareTargetType::kUnknown;
std::function<void()> on_incoming_share_accept;
std::function<void()> on_incoming_share_decline;
};
Component HomeScreen(HomeScreenOptions options);
} // namespace nearby::sharing::linux_tui
-38
View File
@@ -1,38 +0,0 @@
#include "sharing/linux/tui/ui/sidebar.h"
#include "sharing/linux/tui/components/file_icon.h"
#include "sharing/linux/tui/palette.h"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
Element Sidebar(const SidebarState& state) {
auto visible_as_box =
window(text(" Visible as "), vbox({
text(""),
text(state.hostname) | bold | center,
text(""),
})) |
size(WIDTH, GREATER_THAN, 24) | size(HEIGHT, EQUAL, 5);
if (state.selected_file.empty()) {
return vbox({
visible_as_box,
filler(),
});
}
return vbox({
visible_as_box,
filler(),
window(text(" Selected to share ") | center,
vbox({
FileIcon(FileIconSize::Small) | color(Palette::accent),
text(""),
paragraph(state.selected_file) | dim,
})) |
size(WIDTH, EQUAL, 24),
});
}
} // namespace nearby::sharing::linux_tui
-17
View File
@@ -1,17 +0,0 @@
#pragma once
#include <string>
#include "ftxui/dom/elements.hpp"
namespace nearby::sharing::linux_tui {
using namespace ftxui;
struct SidebarState {
std::string hostname;
std::string selected_file;
};
Element Sidebar(const SidebarState& state);
} // namespace nearby::sharing::linux_tui