currentaccountcombobox.cpp 14.6 KB
Newer Older
1
/***************************************************************************
2
 * Copyright (C) 2019-2019 by Savoir-faire Linux                                *
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * Author: Isa Nanic <isa.nanic@savoirfairelinux.com>                      *
 * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>          *
 *                                                                         *
 * 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 3 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.                            *
 *                                                                         *
 * You should have received a copy of the GNU General Public License       *
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
 **************************************************************************/

#include "currentaccountcombobox.h"

22 23
#include "accountitemdelegate.h"
#include "pixbufmanipulator.h"
24 25 26
#include "utils.h"
#include "ringthemeutils.h"
#include "lrcinstance.h"
27
#include "mainwindow.h"
28

29 30 31 32
#include <QPixmap>
#include <QMessageBox>
#include <QMouseEvent>

33 34 35 36 37 38
#undef REGISTERED

CurrentAccountComboBox::CurrentAccountComboBox(QWidget* parent)
{
    Q_UNUSED(parent);

39 40
    setMouseTracking(true);
    gearLabel_.setMouseTracking(true);
41 42 43
    voicemailButton_.setMouseTracking(true);
    voicemailButton_.setNeedToShowNotify(false);
    voicemailButton_.setEnabled(false);
44

45
    accountListUpdate();
Andreas Traczyk's avatar
Andreas Traczyk committed
46
    accountItemDelegate_ = new AccountItemDelegate(this);
47 48 49 50 51
    this->setItemDelegate(accountItemDelegate_);

    // combobox index changed and so must the avatar
    connect(this, QOverload<int>::of(&QComboBox::currentIndexChanged),
            [=](const int& index) {
52
                setCurrentIndex(index);
53 54 55 56 57 58 59 60 61 62 63 64
            });

    // account added to combobox
    connect(&LRCInstance::accountModel(),
            &lrc::api::NewAccountModel::accountAdded,
            [this](const std::string& accountId) {
                auto accountList = LRCInstance::accountModel().getAccountList();
                auto it = std::find(accountList.begin(), accountList.end(), accountId);
                if (it != accountList.end()) {
                    this->setCurrentIndex(std::distance(accountList.begin(), it));
                }
            });
65

66
    // voicemail received
67 68 69 70 71 72 73 74
    if (LRCInstance::accountModel().getAccountList().size()) {
        connectVoiceMail();
    }

    connect(&LRCInstance::instance(),
            &LRCInstance::accountListChanged,
            this, &CurrentAccountComboBox::connectVoiceMail,
            Qt::UniqueConnection);
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102

    connect(&voicemailButton_, &QAbstractButton::clicked,
            [this] {
                auto currentAccountId = LRCInstance::accountModel().getAccountList()[currentIndex()];
                auto &accInfo = LRCInstance::accountModel().getAccountInfo(currentAccountId);
                auto conversationModel = accInfo.conversationModel.get();
                auto confProps = LRCInstance::accountModel().getAccountConfig(currentAccountId);

                auto possibleConv = LRCInstance::getConversationFromPeerUri(confProps.mailbox);
                if (possibleConv.uid.empty()) {
                    if (confProps.mailbox.empty()) {
                        QMessageBox::information(0, "Voicemail", "Voicemail dial code is empty");
                    }
                    // construct new contact
                    lrc::api::profile::Type type{ lrc::api::profile::Type::SIP };
                    lrc::api::contact::Info contactInfo{ {{confProps.mailbox}, {} , {"Voicemail"}, type }, {} };

                    Utils::oneShotConnect(this, &CurrentAccountComboBox::placeAudioOnlyCall,
                        [this, conversationModel] (const std::string& convUid) {
                            conversationModel->placeAudioOnlyCall(convUid);
                        });
                    accInfo.contactModel->addContact(contactInfo);
                } else {
                    // contact existed
                    conversationModel->placeAudioOnlyCall(possibleConv.uid);
                }
            });

103
    gearLabel_.setPixmap(QPixmap(":/images/icons/round-settings-24px.svg"));
104 105
    gearLabel_.setParent(this);
    gearLabel_.setStyleSheet("background: transparent;");
106
    setupSettingsButton();
107 108 109 110 111

    voicemailButton_.setIcon(QIcon(QPixmap(":/images/icons/ic_voicemail_black_24dp_2x_.png")));
    voicemailButton_.setParent(this);
    voicemailButton_.setStyleSheet("background: transparent;");
    setupVoicemailButton();
112 113 114 115 116 117 118 119 120 121 122 123
}

CurrentAccountComboBox::~CurrentAccountComboBox()
{
    delete accountItemDelegate_;
}

void
CurrentAccountComboBox::paintEvent(QPaintEvent* e)
{
    Q_UNUSED(e);

124
    QPoint avatarTopLeft(16, 8);
125
    QPainter painter(this);
126
    painter.setRenderHints((QPainter::Antialiasing | QPainter::TextAntialiasing), true);
127 128 129

    QStyleOption opt;
    opt.init(this);
130
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter);
131 132

    // define and set the two fonts
133
    QFont fontPrimary = QFont(QStringLiteral("Segoe UI Emoji"));
134 135
    QFont fontSecondary = painter.font();
    fontPrimary.setWeight(QFont::ExtraLight);
136
    auto scalingRatio = MainWindow::instance().getCurrentScalingRatio();
137 138
    fontPrimary.setPointSize(scalingRatio > 1.0 ? 10 : 11);
    fontSecondary.setPointSize(scalingRatio > 1.0 ? 9 : 10);
139 140 141 142

    QFontMetrics fontMetricPrimary(fontPrimary);
    QFontMetrics fontMetricSecondary(fontSecondary);

143
    painter.drawPixmap(avatarTopLeft, currentAccountAvatarImage_);
144

145 146
    auto& accInfo = LRCInstance::getCurrentAccountInfo();

147
    // fill in presence indicator if account is registered
148
    auto accountStatus = accInfo.status;
149 150 151
    if (accountStatus == lrc::api::account::Status::REGISTERED) {
        // paint the presence indicator circle
        QPainterPath outerCircle, innerCircle;
152 153
        QPointF presenceCenter(avatarSize_ + avatarTopLeft.x() - 9, avatarSize_ - 3);
        qreal outerCircleRadius = avatarSize_ / 6;
154
        qreal innerCircleRadius = outerCircleRadius * 0.75;
155 156 157 158 159 160
        outerCircle.addEllipse(presenceCenter, outerCircleRadius, outerCircleRadius);
        innerCircle.addEllipse(presenceCenter, innerCircleRadius, innerCircleRadius);
        painter.fillPath(outerCircle, Qt::white);
        painter.fillPath(innerCircle, RingTheme::presenceGreen_);
    }

161
    QRect comboBoxRect(
162 163 164 165
        avatarSize_ + avatarTopLeft.x() + 10 + 2,
        8,
        this->width() - avatarSize_,
        avatarSize_ - 10); // [screen awareness]
166

167
    // write primary and secondary account identifiers to combobox label
168
    QString primaryAccountID = QString::fromStdString(Utils::bestNameForAccount(accInfo));
169 170
    painter.setFont(fontPrimary);
    painter.setPen(RingTheme::lightBlack_);
171
    primaryAccountID = fontMetricPrimary.elidedText(primaryAccountID, Qt::ElideRight,
172
        comboBoxRect.width() - elidConst - (popupPresent ? 0 : 2 * gearSize_ + 2 * voicemailSize_));
173 174
    painter.drawText(comboBoxRect, Qt::AlignLeft, primaryAccountID);

175
    QString secondaryAccountID = QString::fromStdString(Utils::secondBestNameForAccount(accInfo));
176
    secondaryAccountID = fontMetricSecondary.elidedText(secondaryAccountID, Qt::ElideRight,
177
                                                        comboBoxRect.width() - elidConst - 2 - (popupPresent ? 0 : 2 * gearSize_ + 2 * voicemailSize_)); // [screen awareness]
178 179 180 181 182 183

    if (secondaryAccountID.length()) { // if secondary accound id exists
        painter.setFont(fontSecondary);
        painter.setPen(Qt::lightGray);
        painter.drawText(comboBoxRect, (Qt::AlignBottom | Qt::AlignLeft), secondaryAccountID);
    }
Andreas Traczyk's avatar
Andreas Traczyk committed
184 185

    if (QWidget* popupWidget = this->findChild<QFrame*>()) {
186
        popupWidget->setStyleSheet("QFrame{border: 0px;border-bottom: 1px solid #f0f0f0;border-right: 1px solid #f0f0f0; }");
Andreas Traczyk's avatar
Andreas Traczyk committed
187
    }
188
}
189

190
void CurrentAccountComboBox::resizeEvent(QResizeEvent* event)
191
{
192
    Q_UNUSED(event);
193
    setupSettingsButton();
194
    setupVoicemailButton();
195
}
196

197 198 199
void
CurrentAccountComboBox::setupSettingsButton()
{
200
    gearPoint_.setX(this->width() - gearSize_ - 5 * gearBorder_ - 1);
201
    gearPoint_.setY(this->height() / 2 - gearLabel_.height() / 2 - 2 * gearBorder_ + 8);
202 203 204 205
    gearLabel_.setGeometry(
        gearPoint_.x(), gearPoint_.y(),
        gearSize_ + 2 * gearBorder_,
        gearSize_ + 2 * gearBorder_);
206
    gearLabel_.setMargin(gearBorder_);
207 208
}

209 210 211 212 213 214 215 216 217 218 219
void
CurrentAccountComboBox::setupVoicemailButton()
{
    voicemailPoint_.setX(this->width() - gearSize_ - voicemailSize_ - 6 * voicemailBorder_ - 5 * gearBorder_ - 1);
    voicemailPoint_.setY(this->height() / 2 - voicemailButton_.height() / 2 - 2 * voicemailBorder_ + 8);
    voicemailButton_.setGeometry(
        voicemailPoint_.x(), voicemailPoint_.y(),
        voicemailSize_ + 2 * voicemailBorder_,
        voicemailSize_ + 2 * voicemailBorder_);
}

220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
void
CurrentAccountComboBox::connectVoiceMail()
{
    connect(LRCInstance::getCurrentCallModel(), &lrc::api::NewCallModel::voiceMailNotify,
        [this](const std::string& accountId, int newCount, int oldCount, int urgentCount) {
            Q_UNUSED(urgentCount);
            voicemailMap_[accountId] = std::make_pair(newCount, oldCount);
            if (LRCInstance::accountModel().getAccountList()[currentIndex()] == accountId) {
                if (newCount == 0 && oldCount == 0) {
                    voicemailButton_.setNeedToShowNotify(false);
                    voicemailButton_.setEnabled(false);
                    return;
                }
                if (newCount == 0) {
                    voicemailButton_.setNotifyNumber(oldCount);
                    voicemailButton_.setGreyStyleNotification(true);
                } else {
                    voicemailButton_.setNotifyNumber(newCount);
                    voicemailButton_.setGreyStyleNotification(false);
                }
                voicemailButton_.setNeedToShowNotify(true);
                voicemailButton_.setEnabled(true);
            }
        });
}

246 247
// import account background account pixmap and scale pixmap to fit in label
void
248
CurrentAccountComboBox::importLabelPhoto(int index)
249
{
250 251 252 253 254
    currentAccountAvatarImage_ = accountListModel_->data(
            accountListModel_->index(index, 0),
            AccountListModel::Role::Picture)
        .value<QPixmap>()
        .scaledToHeight(avatarSize_ - 4, Qt::SmoothTransformation);
255 256 257 258 259
}

void
CurrentAccountComboBox::setCurrentIndex(int index)
{
Andreas Traczyk's avatar
Andreas Traczyk committed
260
    auto accountListSize = LRCInstance::accountModel().getAccountList().size();
261

Andreas Traczyk's avatar
Andreas Traczyk committed
262 263 264 265 266
    if (index == accountListSize) {
        emit newAccountClicked();
    } else if (index < accountListSize) {
        importLabelPhoto(index);
        QComboBox::setCurrentIndex(index);
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

        auto accountId = LRCInstance::accountModel().getAccountList()[index];
        auto& info = LRCInstance::accountModel().getAccountInfo(accountId);
        if (!(info.profileInfo.type == lrc::api::profile::Type::SIP)) {
            voicemailButton_.setNeedToShowNotify(false);
            voicemailButton_.setEnabled(false);
        } else {
            if (voicemailMap_.find(accountId) != voicemailMap_.end()) {
                int newVoiceMail = voicemailMap_[accountId].first;
                int oldVoiceMail = voicemailMap_[accountId].second;

                if (newVoiceMail == 0 && oldVoiceMail == 0) {
                    voicemailButton_.setNeedToShowNotify(false);
                    voicemailButton_.setEnabled(false);
                    return;
                }
                if (newVoiceMail == 0) {
                    voicemailButton_.setNotifyNumber(oldVoiceMail);
                    voicemailButton_.setGreyStyleNotification(true);
                } else {
                    voicemailButton_.setNotifyNumber(newVoiceMail);
                    voicemailButton_.setGreyStyleNotification(false);
                }
                voicemailButton_.setNeedToShowNotify(true);
                voicemailButton_.setEnabled(true);
                return;
            }
            voicemailButton_.setNeedToShowNotify(false);
            voicemailButton_.setEnabled(false);
        }
Andreas Traczyk's avatar
Andreas Traczyk committed
297
    }
298 299 300 301 302 303 304 305
}

void
CurrentAccountComboBox::accountListUpdate()
{
    accountListModel_.reset(new AccountListModel());
    this->setModel(accountListModel_.get());
}
306

307 308 309 310
// if gearLabel is clicked
void
CurrentAccountComboBox::mousePressEvent(QMouseEvent* mouseEvent)
{
311
    if (gearLabel_.frameGeometry().contains(mouseEvent->localPos().toPoint())) {
312
        emit settingsButtonClicked();
313 314
    } else {
        QComboBox::mousePressEvent(mouseEvent);
315 316 317 318 319 320 321 322 323
    }
}

// if gear label is hovered over
void
CurrentAccountComboBox::mouseMoveEvent(QMouseEvent* mouseEvent)
{
    if (gearLabel_.frameGeometry().contains(mouseEvent->x(), mouseEvent->y())) {
        QComboBox::mouseMoveEvent(mouseEvent);
324
        gearLabel_.setStyleSheet("background: rgb(237, 237, 237); border-width: 0px; border-radius: 15px;");
325
        return;
326 327 328 329
    } else if (voicemailButton_.geometry().contains(mouseEvent->localPos().toPoint())) {
        QComboBox::mouseMoveEvent(mouseEvent);
        voicemailButton_.setStyleSheet("background: rgb(237, 237, 237); border-width: 0px; border-radius: 15px;");
        return;
330 331
    }

332
    voicemailButton_.setStyleSheet("background: transparent;");
333 334 335 336 337 338
    gearLabel_.setStyleSheet("background: transparent;");
}

void
CurrentAccountComboBox::showPopup()
{
339 340
    voicemailButton_.setNeedToShowNotify(false);
    voicemailButton_.setEnabled(false);
341
    gearLabel_.hide();
342 343 344 345 346 347 348
    popupPresent = true;
    QComboBox::showPopup();
}

void
CurrentAccountComboBox::hidePopup()
{
349 350 351 352 353 354 355
    auto accountId { LRCInstance::getCurrAccId() };
    auto& info = LRCInstance::accountModel().getAccountInfo(accountId);
    if (info.profileInfo.type == lrc::api::profile::Type::SIP
        && voicemailMap_.find(accountId) != voicemailMap_.end()) {
        voicemailButton_.setNeedToShowNotify(true);
        voicemailButton_.setEnabled(true);
    }
356
    gearLabel_.show();
357 358 359 360 361 362 363
    popupPresent = false;
    QComboBox::hidePopup();
}

void
CurrentAccountComboBox::leaveEvent(QEvent* event)
{
364
    voicemailButton_.setStyleSheet("background: transparent;");
365 366
    gearLabel_.setStyleSheet("background: transparent;");
    QComboBox::leaveEvent(event);
367 368 369 370 371
}

void
CurrentAccountComboBox::updateComboBoxDisplay()
{
372 373 374 375
    auto currAccIndex = LRCInstance::getCurrentAccountIndex();
    if (currAccIndex != currentIndex())
        setCurrentIndex(currAccIndex);
    importLabelPhoto(currAccIndex);
376
}