/* This file is part of Telegram Desktop, the official desktop version of Telegram messaging app, see https://telegram.org Telegram Desktop 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. It 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. Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE Copyright (c) 2014 John Preston, https://desktop.telegram.org */ #include "stdafx.h" #include "lang.h" #include "passcodebox.h" #include "window.h" #include "localstorage.h" PasscodeBox::PasscodeBox(bool turningOff) : _turningOff(turningOff), _about(st::addContactWidth - st::addContactPadding.left() - st::addContactPadding.right()), _saveButton(this, lang(lng_settings_save), st::btnSelectDone), _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), _oldPasscode(this, st::inpAddContact, lang(lng_passcode_enter_old)), _newPasscode(this, st::inpAddContact, lang(lng_passcode_enter_new)), _reenterPasscode(this, st::inpAddContact, lang(lng_passcode_confirm_new)), a_opacity(0, 1), _hiding(false) { _width = st::addContactWidth; _about.setRichText(st::usernameFont, lang(lng_passcode_about)); int32 aboutHeight = _about.countHeight(_width - st::addContactPadding.left() - st::addContactPadding.right()); _oldPasscode.setEchoMode(QLineEdit::Password); _newPasscode.setEchoMode(QLineEdit::Password); _reenterPasscode.setEchoMode(QLineEdit::Password); if (turningOff) { _oldPasscode.show(); _boxTitle = lang(lng_passcode_remove); _height = st::addContactTitleHeight + st::addContactPadding.top() + 1 * _oldPasscode.height() + st::usernameSkip + aboutHeight + st::addContactPadding.bottom() + _saveButton.height(); } else { if (cHasPasscode()) { _oldPasscode.show(); _boxTitle = lang(lng_passcode_change); _height = st::addContactTitleHeight + st::addContactPadding.top() + 3 * _oldPasscode.height() + st::usernameSkip * 2 + 1 * st::addContactDelta + aboutHeight + st::addContactPadding.bottom() + _saveButton.height(); } else { _oldPasscode.hide(); _boxTitle = lang(lng_passcode_create); _height = st::addContactTitleHeight + st::addContactPadding.top() + 2 * _oldPasscode.height() + st::usernameSkip + 1 * st::addContactDelta + aboutHeight + st::addContactPadding.bottom() + _saveButton.height(); } } _oldPasscode.setGeometry(st::addContactPadding.left(), st::addContactTitleHeight + st::addContactPadding.top(), _width - st::addContactPadding.left() - st::addContactPadding.right(), _oldPasscode.height()); _newPasscode.setGeometry(st::addContactPadding.left(), _oldPasscode.y() + ((turningOff || cHasPasscode()) ? (_oldPasscode.height() + st::usernameSkip) : 0), _oldPasscode.width(), _oldPasscode.height()); _reenterPasscode.setGeometry(st::addContactPadding.left(), _newPasscode.y() + _newPasscode.height() + st::addContactDelta, _newPasscode.width(), _newPasscode.height()); int32 buttonTop = _height - _cancelButton.height(); _cancelButton.move(0, buttonTop); _saveButton.move(_width - _saveButton.width(), buttonTop); connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSave())); connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCancel())); _badOldTimer.setSingleShot(true); connect(&_badOldTimer, SIGNAL(timeout()), this, SLOT(onBadOldPasscode())); connect(&_oldPasscode, SIGNAL(changed()), this, SLOT(onOldChanged())); connect(&_newPasscode, SIGNAL(changed()), this, SLOT(onNewChanged())); connect(&_reenterPasscode, SIGNAL(changed()), this, SLOT(onNewChanged())); resize(_width, _height); showAll(); _cache = myGrab(this, rect()); hideAll(); } void PasscodeBox::hideAll() { _oldPasscode.hide(); _newPasscode.hide(); _reenterPasscode.hide(); _saveButton.hide(); _cancelButton.hide(); } void PasscodeBox::showAll() { if (_turningOff) { _oldPasscode.show(); _newPasscode.hide(); _reenterPasscode.hide(); } else { if (cHasPasscode()) { _oldPasscode.show(); } else { _oldPasscode.hide(); } _newPasscode.show(); _reenterPasscode.show(); } _saveButton.show(); _cancelButton.show(); } void PasscodeBox::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { if (_oldPasscode.hasFocus()) { if (_turningOff) { onSave(); } else { _newPasscode.setFocus(); } } else if (_newPasscode.hasFocus()) { _reenterPasscode.setFocus(); } else if (_reenterPasscode.hasFocus()) { if (cHasPasscode() && _oldPasscode.text().isEmpty()) { _oldPasscode.setFocus(); _oldPasscode.notaBene(); } else if (_newPasscode.text().isEmpty()) { _newPasscode.setFocus(); _newPasscode.notaBene(); } else if (_reenterPasscode.text().isEmpty()) { _reenterPasscode.notaBene(); } else { onSave(); } } } else if (e->key() == Qt::Key_Escape) { onCancel(); } } void PasscodeBox::parentResized() { QSize s = parentWidget()->size(); setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); update(); } void PasscodeBox::paintEvent(QPaintEvent *e) { QPainter p(this); if (_cache.isNull()) { if (!_hiding || a_opacity.current() > 0.01) { // fill bg p.fillRect(QRect(QPoint(0, 0), size()), st::boxBG->b); // paint shadows p.fillRect(0, st::addContactTitleHeight, _width, st::scrollDef.topsh, st::scrollDef.shColor->b); p.fillRect(0, size().height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b); p.setPen(st::usernameColor->p); _about.draw(p, st::addContactPadding.left(), (_turningOff ? _oldPasscode : _reenterPasscode).y() + _oldPasscode.height() + st::usernameSkip, _width - st::addContactPadding.left() - st::addContactPadding.right()); if (!_oldError.isEmpty()) { p.setPen(st::setErrColor->p); p.drawText(QRect(0, _oldPasscode.y() + _oldPasscode.height(), _width, st::usernameSkip), _oldError, style::al_center); } if (!_newError.isEmpty()) { p.setPen(st::setErrColor->p); p.drawText(QRect(0, _reenterPasscode.y() + _reenterPasscode.height(), _width, st::usernameSkip), _newError, style::al_center); } // paint button sep p.fillRect(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); // draw box title / text p.setPen(st::black->p); p.setFont(st::addContactTitleFont->f); p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, _boxTitle); } } else { p.setOpacity(a_opacity.current()); p.drawPixmap(0, 0, _cache); } } void PasscodeBox::animStep(float64 dt) { if (dt >= 1) { a_opacity.finish(); _cache = QPixmap(); if (!_hiding) { showAll(); if (_oldPasscode.isHidden()) { _newPasscode.setFocus(); } else { _oldPasscode.setFocus(); } } } else { a_opacity.update(dt, anim::linear); } update(); } void PasscodeBox::onSave() { QString old = _oldPasscode.text(), pwd = _newPasscode.text(), conf = _reenterPasscode.text(); if (_turningOff || cHasPasscode()) { if (Local::checkPasscode(old.toUtf8())) { if (_turningOff) pwd = conf = QString(); } else { _oldPasscode.setDisabled(true); _newPasscode.setDisabled(true); _reenterPasscode.setDisabled(true); _saveButton.setDisabled(true); _oldError = QString(); update(); _badOldTimer.start(WrongPasscodeTimeout); return; } } if (!_turningOff && pwd.isEmpty()) { _newPasscode.setFocus(); _newPasscode.notaBene(); return; } if (pwd != conf) { _reenterPasscode.setFocus(); _reenterPasscode.notaBene(); if (!conf.isEmpty()) { _newError = lang(lng_passcode_differ); update(); } } else if (!_turningOff && cHasPasscode() && old == pwd) { _newPasscode.setFocus(); _newPasscode.notaBene(); _newError = lang(lng_passcode_is_same); update(); } else { Local::setPasscode(pwd.toUtf8()); App::wnd()->checkAutoLock(); App::wnd()->getTitle()->showUpdateBtn(); emit closed(); } } void PasscodeBox::onBadOldPasscode() { _oldPasscode.setDisabled(false); _newPasscode.setDisabled(false); _reenterPasscode.setDisabled(false); _saveButton.setDisabled(false); _oldPasscode.selectAll(); _oldPasscode.setFocus(); _oldPasscode.notaBene(); _oldError = lang(lng_passcode_wrong); update(); } void PasscodeBox::onOldChanged() { if (!_oldError.isEmpty()) { _oldError = QString(); update(); } } void PasscodeBox::onNewChanged() { if (!_newError.isEmpty()) { _newError = QString(); update(); } } void PasscodeBox::onCancel() { emit closed(); } void PasscodeBox::startHide() { _hiding = true; if (_cache.isNull()) { _cache = myGrab(this, rect()); hideAll(); } a_opacity.start(0); } PasscodeBox::~PasscodeBox() { }