diff --git a/qtox.pro b/qtox.pro index 3c95c22ba..450978f61 100644 --- a/qtox.pro +++ b/qtox.pro @@ -33,7 +33,8 @@ FORMS += \ src/widget/form/settings/privacysettings.ui \ src/widget/form/loadhistorydialog.ui \ src/widget/form/setpassworddialog.ui \ - src/widget/form/settings/advancedsettings.ui + src/widget/form/settings/advancedsettings.ui \ + src/android.ui CONFIG += c++11 diff --git a/src/android.ui b/src/android.ui new file mode 100644 index 000000000..1c22c54b4 --- /dev/null +++ b/src/android.ui @@ -0,0 +1,905 @@ + + + Android + + + + 0 + 0 + 320 + 480 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + 0 + 0 + + + + + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 5 + 20 + + + + + + + + 0 + + + + + true + + + + 1 + 0 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 240 + 240 + 240 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 11 + 75 + true + + + + Your name + + + + + + + + 1 + 0 + + + + + + + + + 193 + 193 + 193 + + + + + + + 193 + 193 + 193 + + + + + + + + + 193 + 193 + 193 + + + + + + + 193 + 193 + 193 + + + + + + + + + 14 + 14 + 14 + + + + + + + 14 + 14 + 14 + + + + + + + + + 8 + + + + Your status + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + Qt::NoFocus + + + + + + + 10 + 10 + + + + false + + + false + + + false + + + true + + + + + + + + + + + + + 0 + 0 + + + + Qt::LeftToRight + + + true + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 320 + 385 + + + + + + + + + + true + + + + 0 + 0 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 55 + 35 + + + + + 55 + 35 + + + + Qt::NoFocus + + + Add friends + + + false + + + + + + + + + + :/img/add.png:/img/add.png + + + false + + + false + + + false + + + + + + + + 55 + 35 + + + + Qt::NoFocus + + + Create a group chat + + + false + + + + + + + :/img/group_button.png:/img/group_button.png + + + true + + + + + + + + 55 + 35 + + + + + 55 + 35 + + + + Qt::NoFocus + + + View completed file transfers + + + + + + + :/img/transfer.png:/img/transfer.png + + + true + + + + + + + + 55 + 35 + + + + + 55 + 35 + + + + Qt::NoFocus + + + Change your settings + + + + + + + :/img/settings.png:/img/settings.png + + + true + + + + + + + + + + + + + + AdjustingScrollArea + QScrollArea +
src/widget/adjustingscrollarea.h
+ 1 +
+ + CroppingLabel + QLabel +
src/widget/croppinglabel.h
+
+
+ + + + +
diff --git a/src/nexus.cpp b/src/nexus.cpp index 9c80bcfcd..6a56f8bd6 100644 --- a/src/nexus.cpp +++ b/src/nexus.cpp @@ -72,7 +72,21 @@ void Nexus::start() GUI::getInstance(); // Connections -#ifndef Q_OS_ANDROID +#ifdef Q_OS_ANDROID + connect(core, &Core::connected, androidgui, &AndroidGUI::onConnected); + connect(core, &Core::disconnected, androidgui, &AndroidGUI::onDisconnected); + //connect(core, &Core::failedToStart, androidgui, &AndroidGUI::onFailedToStartCore); + //connect(core, &Core::badProxy, androidgui, &AndroidGUI::onBadProxyCore); + connect(core, &Core::statusSet, androidgui, &AndroidGUI::onStatusSet); + connect(core, &Core::usernameSet, androidgui, &AndroidGUI::setUsername); + connect(core, &Core::statusMessageSet, androidgui, &AndroidGUI::setStatusMessage); + connect(core, &Core::selfAvatarChanged, androidgui, &AndroidGUI::onSelfAvatarLoaded); + + connect(androidgui, &AndroidGUI::statusSet, core, &Core::setStatus); + //connect(androidgui, &AndroidGUI::friendRequested, core, &Core::requestFriendship); + //connect(androidgui, &AndroidGUI::friendRequestAccepted, core, &Core::acceptFriendRequest); + //connect(androidgui, &AndroidGUI::changeProfile, core, &Core::switchConfiguration); +#else connect(core, &Core::connected, widget, &Widget::onConnected); connect(core, &Core::disconnected, widget, &Widget::onDisconnected); connect(core, &Core::failedToStart, widget, &Widget::onFailedToStartCore); diff --git a/src/widget/androidgui.cpp b/src/widget/androidgui.cpp index 7ae41d983..8dd2b7a9d 100644 --- a/src/widget/androidgui.cpp +++ b/src/widget/androidgui.cpp @@ -1,13 +1,169 @@ #include "androidgui.h" +#include "ui_android.h" +#include "friendlistwidget.h" +#include "maskablepixmapwidget.h" +#include "src/core.h" +#include "src/friend.h" +#include "src/friendlist.h" +#include "src/group.h" +#include "src/grouplist.h" +#include "src/misc/settings.h" +#include "src/misc/style.h" +#include "src/nexus.h" +#include "src/widget/friendwidget.h" +#include "src/widget/groupwidget.h" #include +#include AndroidGUI::AndroidGUI(QWidget *parent) : - QWidget(parent) + QWidget(parent), + ui{new Ui::Android} { - l = new QLabel("qTox Android", this); + ui->setupUi(this); + + ui->friendList->setStyleSheet(Style::resolve(Style::getStylesheet(":ui/friendList/friendList.css"))); + + profilePicture = new MaskablePixmapWidget(this, QSize(40, 40), ":/img/avatar_mask.png"); + profilePicture->setPixmap(QPixmap(":/img/contact_dark.png")); + profilePicture->setClickable(true); + ui->myProfile->insertWidget(0, profilePicture); + ui->myProfile->insertSpacing(1, 7); + + ui->tooliconsZone->setStyleSheet(Style::resolve("QPushButton{background-color:@themeDark;border:none;}QPushButton:hover{background-color:@themeMediumDark;border:none;}")); + ui->statusHead->setStyleSheet(Style::getStylesheet(":/ui/window/statusPanel.css")); + + contactListWidget = new FriendListWidget(); + ui->friendList->setWidget(contactListWidget); + ui->friendList->setLayoutDirection(Qt::RightToLeft); + + ui->nameLabel->setEditable(true); + ui->statusLabel->setEditable(true); + + ui->statusPanel->setStyleSheet(Style::getStylesheet(":/ui/window/statusPanel.css")); + + QMenu *statusButtonMenu = new QMenu(ui->statusButton); + QAction* setStatusOnline = statusButtonMenu->addAction(AndroidGUI::tr("Online","Button to set your status to 'Online'")); + setStatusOnline->setIcon(QIcon(":ui/statusButton/dot_online.png")); + QAction* setStatusAway = statusButtonMenu->addAction(AndroidGUI::tr("Away","Button to set your status to 'Away'")); + setStatusAway->setIcon(QIcon(":ui/statusButton/dot_idle.png")); + QAction* setStatusBusy = statusButtonMenu->addAction(AndroidGUI::tr("Busy","Button to set your status to 'Busy'")); + setStatusBusy->setIcon(QIcon(":ui/statusButton/dot_busy.png")); + ui->statusButton->setMenu(statusButtonMenu); + + ui->statusButton->setProperty("status", "offline"); + Style::repolish(ui->statusButton); + + // Disable some widgets until we're connected to the DHT + ui->statusButton->setEnabled(false); + + Style::setThemeColor(Settings::getInstance().getThemeColor()); + Style::setThemeColor(1); + reloadTheme(); + + connect(ui->nameLabel, &CroppingLabel::textChanged, this, &AndroidGUI::onUsernameChanged); + connect(ui->statusLabel, &CroppingLabel::textChanged, this, &AndroidGUI::onStatusMessageChanged); } AndroidGUI::~AndroidGUI() { - delete l; + delete profilePicture; + delete contactListWidget; } + +void AndroidGUI::reloadTheme() +{ + QString statusPanelStyle = Style::getStylesheet(":/ui/window/statusPanel.css"); + ui->tooliconsZone->setStyleSheet(Style::resolve("QPushButton{background-color:@themeDark;border:none;}QPushButton:hover{background-color:@themeMediumDark;border:none;}")); + ui->statusPanel->setStyleSheet(statusPanelStyle); + ui->statusHead->setStyleSheet(statusPanelStyle); + ui->friendList->setStyleSheet(Style::getStylesheet(":ui/friendList/friendList.css")); + ui->statusButton->setStyleSheet(Style::getStylesheet(":ui/statusButton/statusButton.css")); + + for (Friend* f : FriendList::getAllFriends()) + f->getFriendWidget()->reloadTheme(); + + for (Group* g : GroupList::getAllGroups()) + g->getGroupWidget()->reloadTheme(); +} + +void AndroidGUI::onSelfAvatarLoaded(const QPixmap& pic) +{ + profilePicture->setPixmap(pic); +} + +void AndroidGUI::onConnected() +{ + ui->statusButton->setEnabled(true); + if (beforeDisconnect == Status::Offline) + emit statusSet(Status::Online); + else + emit statusSet(beforeDisconnect); +} + +void AndroidGUI::onDisconnected() +{ + QString stat = ui->statusButton->property("status").toString(); + if (stat == "online") + beforeDisconnect = Status::Online; + else if (stat == "busy") + beforeDisconnect = Status::Busy; + else if (stat == "away") + beforeDisconnect = Status::Away; + else + beforeDisconnect = Status::Offline; + + ui->statusButton->setEnabled(false); + emit statusSet(Status::Offline); +} + +void AndroidGUI::onUsernameChanged(const QString& newUsername, const QString& oldUsername) +{ + setUsername(oldUsername); // restore old username until Core tells us to set it + Nexus::getCore()->setUsername(newUsername); +} + +void AndroidGUI::setUsername(const QString& username) +{ + ui->nameLabel->setText(username); + ui->nameLabel->setToolTip(username); // for overlength names + QString sanename = username; + sanename.remove(QRegExp("[\\t\\n\\v\\f\\r\\x0000]")); + nameMention = QRegExp("\\b" + QRegExp::escape(username) + "\\b", Qt::CaseInsensitive); + sanitizedNameMention = QRegExp("\\b" + QRegExp::escape(sanename) + "\\b", Qt::CaseInsensitive); +} + +void AndroidGUI::onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage) +{ + ui->statusLabel->setText(oldStatusMessage); // restore old status message until Core tells us to set it + ui->statusLabel->setToolTip(oldStatusMessage); // for overlength messsages + Nexus::getCore()->setStatusMessage(newStatusMessage); +} + +void AndroidGUI::setStatusMessage(const QString &statusMessage) +{ + ui->statusLabel->setText(statusMessage); + ui->statusLabel->setToolTip(statusMessage); // for overlength messsages +} + +void AndroidGUI::onStatusSet(Status status) +{ + //We have to use stylesheets here, there's no way to + //prevent the button icon from moving when pressed otherwise + switch (status) + { + case Status::Online: + ui->statusButton->setProperty("status" ,"online"); + break; + case Status::Away: + ui->statusButton->setProperty("status" ,"away"); + break; + case Status::Busy: + ui->statusButton->setProperty("status" ,"busy"); + break; + case Status::Offline: + ui->statusButton->setProperty("status" ,"offline"); + break; + } + Style::repolish(ui->statusButton); +} + diff --git a/src/widget/androidgui.h b/src/widget/androidgui.h index 853483ce2..c820bb878 100644 --- a/src/widget/androidgui.h +++ b/src/widget/androidgui.h @@ -1,9 +1,15 @@ #ifndef ANDROIDGUI_H #define ANDROIDGUI_H +#include "src/corestructs.h" #include -class QLabel; +class MaskablePixmapWidget; +class FriendListWidget; + +namespace Ui { +class Android; +} class AndroidGUI : public QWidget { @@ -12,8 +18,35 @@ public: explicit AndroidGUI(QWidget *parent = 0); ~AndroidGUI(); +public slots: + void onConnected(); + void onDisconnected(); + void onStatusSet(Status status); + void onSelfAvatarLoaded(const QPixmap &pic); + void setUsername(const QString& username); + void setStatusMessage(const QString &statusMessage); + +signals: + void friendRequestAccepted(const QString& userId); + void friendRequested(const QString& friendAddress, const QString& message); + void statusSet(Status status); + void statusSelected(Status status); + void usernameChanged(const QString& username); + void statusMessageChanged(const QString& statusMessage); + private: - QLabel* l; + void reloadTheme(); + +private slots: + void onUsernameChanged(const QString& newUsername, const QString& oldUsername); + void onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage); + +private: + Ui::Android* ui; + MaskablePixmapWidget* profilePicture; + FriendListWidget* contactListWidget; + Status beforeDisconnect = Status::Offline; + QRegExp nameMention, sanitizedNameMention; }; #endif // ANDROIDGUI_H diff --git a/src/widget/gui.cpp b/src/widget/gui.cpp index d6b8a7dc0..12515fc3c 100644 --- a/src/widget/gui.cpp +++ b/src/widget/gui.cpp @@ -73,6 +73,19 @@ void GUI::reloadTheme() } } +void GUI::showInfo(const QString& title, const QString& msg) +{ + if (QThread::currentThread() == qApp->thread()) + { + getInstance()._showInfo(title, msg); + } + else + { + QMetaObject::invokeMethod(&getInstance(), "_showInfo", Qt::BlockingQueuedConnection, + Q_ARG(const QString&, title), Q_ARG(const QString&, msg)); + } +} + void GUI::showWarning(const QString& title, const QString& msg) { if (QThread::currentThread() == qApp->thread()) @@ -86,15 +99,15 @@ void GUI::showWarning(const QString& title, const QString& msg) } } -void GUI::showInfo(const QString& title, const QString& msg) +void GUI::showError(const QString& title, const QString& msg) { if (QThread::currentThread() == qApp->thread()) { - getInstance()._showInfo(title, msg); + getInstance()._showError(title, msg); } else { - QMetaObject::invokeMethod(&getInstance(), "_showInfo", Qt::BlockingQueuedConnection, + QMetaObject::invokeMethod(&getInstance(), "_showError", Qt::BlockingQueuedConnection, Q_ARG(const QString&, title), Q_ARG(const QString&, msg)); } } @@ -182,14 +195,19 @@ void GUI::_reloadTheme() #endif } +void GUI::_showInfo(const QString& title, const QString& msg) +{ + QMessageBox::information(getMainWidget(), title, msg); +} + void GUI::_showWarning(const QString& title, const QString& msg) { QMessageBox::warning(getMainWidget(), title, msg); } -void GUI::_showInfo(const QString& title, const QString& msg) +void GUI::_showError(const QString& title, const QString& msg) { - QMessageBox::information(getMainWidget(), title, msg); + QMessageBox::critical(getMainWidget(), title, msg); } bool GUI::_askQuestion(const QString& title, const QString& msg, diff --git a/src/widget/gui.h b/src/widget/gui.h index 70cc73a7c..926685467 100644 --- a/src/widget/gui.h +++ b/src/widget/gui.h @@ -23,10 +23,12 @@ public: static void setWindowTitle(const QString& title); /// Reloads the application theme and redraw the window static void reloadTheme(); - /// Show a warning to the user, for example in a message box - static void showWarning(const QString& title, const QString& msg); /// Show some text to the user, for example in a message box static void showInfo(const QString& title, const QString& msg); + /// Show a warning to the user, for example in a message box + static void showWarning(const QString& title, const QString& msg); + /// Show an error to the user, for example in a message box + static void showError(const QString& title, const QString& msg); /// Asks the user a question, for example in a message box. /// If warning is true, we will use a special warning style. /// Returns the answer. @@ -57,8 +59,9 @@ private slots: void _setEnabled(bool state); void _setWindowTitle(const QString& title); void _reloadTheme(); - void _showWarning(const QString& title, const QString& msg); void _showInfo(const QString& title, const QString& msg); + void _showWarning(const QString& title, const QString& msg); + void _showError(const QString& title, const QString& msg); bool _askQuestion(const QString& title, const QString& msg, bool defaultAns = false, bool warning = true); QString _itemInputDialog(QWidget * parent, const QString & title, diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 3868e1ece..f6cd0ab6f 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -1133,8 +1133,10 @@ void Widget::clearAllReceipts() void Widget::reloadTheme() { + QString statusPanelStyle = Style::getStylesheet(":/ui/window/statusPanel.css"); ui->tooliconsZone->setStyleSheet(Style::resolve("QPushButton{background-color:@themeDark;border:none;}QPushButton:hover{background-color:@themeMediumDark;border:none;}")); - ui->statusPanel->setStyleSheet(Style::getStylesheet(":/ui/window/statusPanel.css")); + ui->statusPanel->setStyleSheet(statusPanelStyle); + ui->statusHead->setStyleSheet(statusPanelStyle); ui->friendList->setStyleSheet(Style::getStylesheet(":ui/friendList/friendList.css")); ui->statusButton->setStyleSheet(Style::getStylesheet(":ui/statusButton/statusButton.css")); diff --git a/ui/window/statusPanel.css b/ui/window/statusPanel.css index 2c9b77d7a..536c50918 100644 --- a/ui/window/statusPanel.css +++ b/ui/window/statusPanel.css @@ -12,12 +12,19 @@ QLineEdit background-color: @themeDark; } +#statusPanel > #statusHead +{ + background-color: @themeDark; +} + #statusPanel > #statusHead > #nameLabel { + background-color: @themeDark; font: @extraBig; color: @white; } #statusPanel > #statusHead > #statusLabel { + background-color: @themeDark; font: @medium; color: @lightGrey; }