Skip to content
11 changes: 6 additions & 5 deletions src/common/utility_mac_sandbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@ namespace Utility {
[[nodiscard]] QByteArray createSecurityScopedBookmarkData(const QString &localPath);

/**
* @brief Get the real user home directory path
* @brief Get the logged-in user's home directory path
*
* In sandboxed macOS apps, QStandardPaths::HomeLocation returns the sandbox
* container directory, not the actual user home directory. This function uses
* NSHomeDirectory() to retrieve the real home directory path.
* In sandboxed macOS apps, QStandardPaths::HomeLocation and NSHomeDirectory()
* return the app's sandbox container. This function resolves the logged-in
* user's home directory instead.
*
* @return The real user home directory path
* @return The logged-in user's home directory path, or an empty string if it
* cannot be resolved
*/
[[nodiscard]] QString getRealHomeDirectory();

Expand Down
6 changes: 5 additions & 1 deletion src/common/utility_mac_sandbox.mm
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ QByteArray result(reinterpret_cast<const char *>([bookmarkData bytes]),
QString getRealHomeDirectory()
{
@autoreleasepool {
NSString *homeDir = NSHomeDirectory();
NSString * const homeDir = NSHomeDirectoryForUser(NSUserName());
if (!homeDir) {
qCWarning(lcMacSandboxUtility) << "Failed to resolve the logged-in user's home directory";
return {};
}
return QString::fromNSString(homeDir);
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ endif()
configure_file(${CMAKE_SOURCE_DIR}/theme.qrc.in ${CMAKE_SOURCE_DIR}/theme.qrc)
set(theme_dir ${CMAKE_SOURCE_DIR}/theme)

#NMC customization: needed to find the ui file in a different location than the header file
set(CMAKE_AUTOUIC_SEARCH_PATHS "${CMAKE_SOURCE_DIR}/src/gui")

set(client_UI_SRCS
accountsettings.ui
conflictdialog.ui
Expand Down Expand Up @@ -259,6 +262,10 @@ set(client_SRCS
integration/fileactionsmodel.cpp
)

file(GLOB NMC_FILES "nmcgui/*")
set(NMC_SRCS ${NMC_FILES})
list(APPEND client_SRCS ${NMC_SRCS})

if (NOT DISABLE_ACCOUNT_MIGRATION)
list(APPEND client_SRCS
legacyaccountselectiondialog.h
Expand Down
2 changes: 0 additions & 2 deletions src/gui/folderwizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,6 @@ void FolderWizardLocalPath::slotChooseLocalFolder()
QString sf;

#ifdef Q_OS_MACOS
// On macOS with app sandbox, QStandardPaths returns the sandbox container directory,
// not the actual user home directory. Use NSHomeDirectory() to get the real path.
sf = Utility::getRealHomeDirectory();
#else
sf = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
Expand Down
162 changes: 162 additions & 0 deletions src/gui/nmcgui/nmcflow2authwidget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* Copyright (C) by Eugen Fischer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

#include "nmcflow2authwidget.h"

#include <QCoreApplication>
#include <QDesktopServices>
#include <QIcon>
#include <QLabel>
#include <QPainter>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>

#include "QProgressIndicator.h"
#include "theme.h"

namespace OCC {

NMCFlow2AuthWidget::NMCFlow2AuthWidget(QWidget *parent)
: Flow2AuthWidget(parent)
{
// Bestehende UI-Elemente ausblenden
if (getUi().logoLabel) {
getUi().logoLabel->hide();
getUi().logoLabel->setFixedSize(0, 0);
}
if (getUi().label) {
getUi().label->hide();
getUi().label->setFixedSize(0, 0);
}
if (getUi().copyLinkButton) {
getUi().copyLinkButton->hide();
}
if (getUi().openLinkButton) {
getUi().openLinkButton->hide();
}
if (auto *progressInd = getProgressIndicator()) {
progressInd->setVisible(false);
progressInd->setFixedSize(0, 0);
}
if (getUi().statusLabel) {
getUi().statusLabel->setVisible(false);
getUi().statusLabel->setFixedSize(0, 0);
}

// Bestehendes Layout und Child-Widgets entfernen
if (auto *oldLayout = layout()) {
QLayoutItem *item;
while ((item = oldLayout->takeAt(0)) != nullptr) {
if (auto *widget = item->widget()) {
widget->setParent(nullptr);
}
delete item;

Check failure on line 65 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rewrite the code so that you no longer need this "delete".

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzqt&open=AZ-Io3S5b3P67Tsgkzqt&pullRequest=424
}
delete oldLayout;

Check failure on line 67 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rewrite the code so that you no longer need this "delete".

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzqs&open=AZ-Io3S5b3P67Tsgkzqs&pullRequest=424
}

// Login-Button
auto loginButton = new QPushButton(QCoreApplication::translate("", "LOGIN"));

Check failure on line 71 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace the use of "new" with an operation that automatically manages the memory.

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzqu&open=AZ-Io3S5b3P67Tsgkzqu&pullRequest=424
loginButton->setFocusPolicy(Qt::NoFocus);
loginButton->setFixedSize(130, 32);
loginButton->setStyleSheet(
"QPushButton { font-size: 15px; border: none; border-radius: 4px; background-color: #E20074; color: white; }"
"QPushButton:hover { background-color: #c00063; }"
);
connect(loginButton, &QPushButton::clicked, this, &NMCFlow2AuthWidget::slotOpenBrowser);

// Logo + Titel
auto logoLabel = new QLabel(this);
logoLabel->setPixmap(QIcon(":/client/theme/NMCIcons/tlogocarrier.svg").pixmap(36, 36));
logoLabel->setFixedSize(36, 36);

auto titleLabel = new QLabel(tr("MagentaCLOUD"), this);
titleLabel->setStyleSheet("font-weight: bold; font-size: 15px;");

auto logoTitleLayout = new QHBoxLayout;

Check failure on line 88 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace the use of "new" with an operation that automatically manages the memory.

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzqv&open=AZ-Io3S5b3P67Tsgkzqv&pullRequest=424
logoTitleLayout->setSpacing(8);
logoTitleLayout->addWidget(logoLabel);
logoTitleLayout->addWidget(titleLabel);
logoTitleLayout->addStretch();

// Überschrift
auto headerLabel = new QLabel(QCoreApplication::translate("", "SETUP_HEADER_TEXT_1"));

Check failure on line 95 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace the use of "new" with an operation that automatically manages the memory.

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzqw&open=AZ-Io3S5b3P67Tsgkzqw&pullRequest=424
headerLabel->setStyleSheet("font-size: 24px; font-weight: normal;");
headerLabel->setWordWrap(true);
headerLabel->setFixedWidth(282);

// Anweisungs-Label
auto label = new QLabel(tr("Wechseln Sie bitte zu Ihrem Browser und melden Sie sich dort an, um Ihr Konto zu verbinden."), this);
label->setStyleSheet("font-size: 14px;");
label->setWordWrap(true);
label->setFixedWidth(282);

// Linke Seite
auto leftLayout = new QVBoxLayout;

Check failure on line 107 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace the use of "new" with an operation that automatically manages the memory.

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzqx&open=AZ-Io3S5b3P67Tsgkzqx&pullRequest=424
leftLayout->addLayout(logoTitleLayout);
leftLayout->addSpacing(24);
leftLayout->addWidget(headerLabel);
leftLayout->addSpacing(16);
leftLayout->addWidget(label);
leftLayout->addSpacing(24);
leftLayout->addWidget(loginButton);
leftLayout->addStretch();

// Rechtes Logo
auto bigLogoLabel = new QLabel(this);
bigLogoLabel->setPixmap(QIcon(":/client/theme/NMCIcons/applicationLogo.svg").pixmap(175, 175));
bigLogoLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
bigLogoLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

auto rightLayout = new QVBoxLayout;

Check failure on line 123 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace the use of "new" with an operation that automatically manages the memory.

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzqy&open=AZ-Io3S5b3P67Tsgkzqy&pullRequest=424
rightLayout->addStretch();
rightLayout->addWidget(bigLogoLabel);
rightLayout->addStretch();

// Hauptlayout
auto mainLayout = new QHBoxLayout;

Check failure on line 129 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace the use of "new" with an operation that automatically manages the memory.

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzqz&open=AZ-Io3S5b3P67Tsgkzqz&pullRequest=424
mainLayout->setContentsMargins(16, 16, 16, 16);
mainLayout->setSpacing(24);
mainLayout->addLayout(leftLayout);
mainLayout->addStretch();
mainLayout->addLayout(rightLayout);

// Fehlerlabel wieder einfügen
if (getUi().errorLabel) {
mainLayout->addWidget(getUi().errorLabel);
}
setLayout(mainLayout);
}

// Styling bewusst ignorieren
void NMCFlow2AuthWidget::customizeStyle() {}

Check failure on line 144 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add a nested comment explaining why this method is empty, or complete the implementation.

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzq0&open=AZ-Io3S5b3P67Tsgkzq0&pullRequest=424

// Spinner einblenden / ungenutzt
void NMCFlow2AuthWidget::startSpinner() {}

Check failure on line 147 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add a nested comment explaining why this method is empty, or complete the implementation.

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzq1&open=AZ-Io3S5b3P67Tsgkzq1&pullRequest=424

// Spinner ausblenden / ungenutzt
void NMCFlow2AuthWidget::stopSpinner(bool showStatusLabel)
{
Q_UNUSED(showStatusLabel);

Check warning on line 152 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzq2&open=AZ-Io3S5b3P67Tsgkzq2&pullRequest=424
}

// Statusänderung unterdrücken
void NMCFlow2AuthWidget::slotStatusChanged(Flow2Auth::PollStatus status, int secondsLeft)
{
Q_UNUSED(status);

Check warning on line 158 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzq3&open=AZ-Io3S5b3P67Tsgkzq3&pullRequest=424
Q_UNUSED(secondsLeft);

Check warning on line 159 in src/gui/nmcgui/nmcflow2authwidget.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=nextmcloud_desktop&issues=AZ-Io3S5b3P67Tsgkzq4&open=AZ-Io3S5b3P67Tsgkzq4&pullRequest=424
}

} // namespace OCC
77 changes: 77 additions & 0 deletions src/gui/nmcgui/nmcflow2authwidget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (C) by Eugen Fischer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

/*
* Copyright (C) by Eugen Fischer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

#ifndef NMCFLOW2AUTHWIDGET_H
#define NMCFLOW2AUTHWIDGET_H

#include "wizard/flow2authwidget.h"

namespace OCC {

class NMCFlow2AuthWidget : public Flow2AuthWidget
{
Q_OBJECT

public:
/**
* @brief Constructs an NMCFlow2AuthWidget object.
* @param parent The parent widget (default is nullptr).
*/
explicit NMCFlow2AuthWidget(QWidget *parent = nullptr);

/**
* @brief Destructor for NMCFlow2AuthWidget.
*/
~NMCFlow2AuthWidget() override = default;

protected:
/**
* @brief Reimplemented from Flow2AuthWidget.
* Customizes the style of the widget.
*/
void customizeStyle() override;

/**
* @brief Optionally reimplemented: controls spinner visibility/start.
*/
void startSpinner() override;

/**
* @brief Optionally reimplemented: stops spinner and optionally shows label.
*/
void stopSpinner(bool showStatusLabel) override;

/**
* @brief Optionally reimplemented: handles status updates during auth.
*/
void slotStatusChanged(Flow2Auth::PollStatus status, int secondsLeft) override;
};

} // namespace OCC

#endif // NMCFLOW2AUTHWIDGET_H
Loading