Merge pull request #883 from Nheko-Reborn/qml-usersettings

Port usersettings to qml
pull/900/head
Joseph Donofry 3 years ago committed by GitHub
commit d2ee5d8d43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      resources/qml/ImageButton.qml
  2. 2
      resources/qml/MessageInput.qml
  3. 3
      resources/qml/RoomList.qml
  4. 15
      resources/qml/Root.qml
  5. 2
      resources/qml/ToggleButton.qml
  6. 213
      resources/qml/UserSettingsPage.qml
  7. 1
      resources/qml/components/FlatButton.qml
  8. 8
      resources/qml/dialogs/ImagePackEditorDialog.qml
  9. 2
      resources/qml/dialogs/ImagePackSettingsDialog.qml
  10. 2
      resources/qml/dialogs/RoomSettings.qml
  11. 1
      resources/res.qrc
  12. 36
      src/MainWindow.cpp
  13. 5
      src/MainWindow.h
  14. 1713
      src/UserSettingsPage.cpp
  15. 191
      src/UserSettingsPage.h
  16. 2
      src/Utils.cpp
  17. 4
      src/timeline/TimelineViewManager.cpp

@ -16,6 +16,7 @@ AbstractButton {
property color highlightColor: Nheko.colors.highlight
property color buttonTextColor: Nheko.colors.buttonText
property bool changeColorOnHover: true
property bool ripple: true
focusPolicy: Qt.NoFocus
width: 16
@ -38,6 +39,7 @@ AbstractButton {
}
Ripple {
enabled: button.ripple
color: Qt.rgba(buttonTextColor.r, buttonTextColor.g, buttonTextColor.b, 0.5)
}

@ -194,7 +194,7 @@ Rectangle {
}
room.input.send();
event.accepted = true;
} else if (event.key == Qt.Key_Tab) {
} else if (event.key == Qt.Key_Tab && (event.modifiers == Qt.NoModifier || event.modifiers == Qt.ShiftModifier)) {
event.accepted = true;
if (popup.opened) {
if (event.modifiers & Qt.ShiftModifier)

@ -678,6 +678,7 @@ Page {
visible: !collapsed
Layout.fillWidth: true
hoverEnabled: true
ripple: false
width: 22
height: 22
image: ":/icons/icons/ui/settings.svg"
@ -685,7 +686,7 @@ Page {
ToolTip.delay: Nheko.tooltipDelay
ToolTip.text: qsTr("User settings")
Layout.margins: Nheko.paddingMedium
onClicked: Nheko.showUserSettingsPage()
onClicked: mainWindow.push(userSettingsPage);
}
}

@ -144,6 +144,14 @@ Page {
}
Component {
id: userSettingsPage
UserSettingsPage {
}
}
Shortcut {
sequence: "Ctrl+K"
onActivated: {
@ -353,8 +361,13 @@ Page {
target: UIA
}
ChatPage {
StackView {
id: mainWindow
anchors.fill: parent
initialItem: ChatPage {
//anchors.fill: parent
}
}
}

@ -36,7 +36,7 @@ Switch {
width: parent.height
height: width
radius: width / 2
color: toggleButton.down ? "whitesmoke" : "whitesmoke"
color: toggleButton.enabled ? "whitesmoke" : "#cccccc"
border.color: "#ebebeb"
}

@ -0,0 +1,213 @@
// SPDX-FileCopyrightText: 2021 Nheko Contributors
// SPDX-FileCopyrightText: 2022 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
import "ui"
import Qt.labs.platform 1.1 as Platform
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.2
import QtQuick.Window 2.15
import im.nheko 1.0
Rectangle {
id: userSettingsDialog
property int collapsePoint: 800
property bool collapsed: width < collapsePoint
color: Nheko.colors.window
ScrollView {
id: scroll
palette: Nheko.colors
ScrollBar.horizontal.visible: false
anchors.fill: parent
anchors.margins: Nheko.paddingLarge
contentWidth: availableWidth
Timer {
id: deadTimer
interval: 500
}
Connections {
target: scroll.contentItem
function onContentYChanged() { deadTimer.restart(); }
}
GridLayout {
id: grid
columns: userSettingsDialog.collapsed ? 1 : 2
rowSpacing: Nheko.paddingMedium
columnSpacing: Nheko.paddingMedium
anchors.fill: parent
anchors.leftMargin: userSettingsDialog.collapsed ? Nheko.paddingLarge : (userSettingsDialog.width-userSettingsDialog.collapsePoint) * 0.4
anchors.rightMargin: anchors.leftMargin
Repeater {
model: UserSettingsModel
delegate: Item {
required property var model
id: r
Component.onCompleted: {
while (children.length) {
children[0].parent = grid;
}
}
Label {
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
color: Nheko.colors.text
text: model.name
//Layout.column: 0
Layout.columnSpan: (model.type == UserSettingsModel.SectionTitle && !userSettingsDialog.collapsed) ? 2 : 1
//Layout.row: model.index
Layout.minimumWidth: implicitWidth
Layout.leftMargin: model.type == UserSettingsModel.SectionTitle ? 0 : Nheko.paddingMedium
Layout.topMargin: model.type == UserSettingsModel.SectionTitle ? Nheko.paddingLarge : 0
font.pointSize: 1.1 * fontMetrics.font.pointSize
HoverHandler {
id: hovered
enabled: model.description ?? false
}
ToolTip.visible: hovered.hovered && model.description
ToolTip.text: model.description ?? ""
ToolTip.delay: Nheko.tooltipDelay
}
DelegateChooser {
id: chooser
roleValue: model.type
Layout.alignment: Qt.AlignRight
//Layout.column: model.type == UserSettingsModel.SectionTitle ? 0 : 1
Layout.columnSpan: (model.type == UserSettingsModel.SectionTitle && !userSettingsDialog.collapsed) ? 2 : 1
//Layout.row: model.index
Layout.preferredHeight: child.height
Layout.preferredWidth: Math.min(child.implicitWidth, child.width || 1000)
Layout.fillWidth: model.type == UserSettingsModel.SectionTitle
Layout.rightMargin: model.type == UserSettingsModel.SectionTitle ? 0 : Nheko.paddingMedium
DelegateChoice {
roleValue: UserSettingsModel.Toggle
ToggleButton {
checked: model.value
onCheckedChanged: model.value = checked
enabled: model.enabled
}
}
DelegateChoice {
roleValue: UserSettingsModel.Options
ComboBox {
Layout.preferredWidth: Math.min(200, implicitWidth)
width: Math.min(200, implicitWidth)
model: r.model.values
currentIndex: r.model.value
enabled: !deadTimer.running
onCurrentIndexChanged: r.model.value = currentIndex
}
}
DelegateChoice {
roleValue: UserSettingsModel.Number
SpinBox {
//implicitWidth: 100
enabled: !deadTimer.running && model.enabled
from: model.valueLowerBound
to: model.valueUpperBound
stepSize: model.valueStep
value: model.value
onValueChanged: model.value = value
}
}
DelegateChoice {
roleValue: UserSettingsModel.ReadOnlyText
Text {
color: Nheko.colors.text
text: model.value
}
}
DelegateChoice {
roleValue: UserSettingsModel.SectionTitle
Item {
width: grid.width
height: fontMetrics.lineSpacing
Rectangle {
anchors.topMargin: Nheko.paddingSmall
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
color: Nheko.colors.buttonText
height: 1
}
}
}
DelegateChoice {
roleValue: UserSettingsModel.KeyStatus
Text {
color: model.good ? "green" : Nheko.theme.error
text: model.value ? qsTr("CACHED") : qsTr("NOT CACHED")
}
}
DelegateChoice {
roleValue: UserSettingsModel.SessionKeyImportExport
RowLayout {
Button {
text: qsTr("IMPORT")
onClicked: UserSettingsModel.importSessionKeys()
}
Button {
text: qsTr("EXPORT")
onClicked: UserSettingsModel.exportSessionKeys()
}
}
}
DelegateChoice {
roleValue: UserSettingsModel.XSignKeysRequestDownload
RowLayout {
Button {
text: qsTr("DOWNLOAD")
onClicked: UserSettingsModel.downloadCrossSigningSecrets()
}
Button {
text: qsTr("REQUEST")
onClicked: UserSettingsModel.requestCrossSigningSecrets()
}
}
}
DelegateChoice {
Text {
text: model.value
}
}
}
}
}
}
}
ImageButton {
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: Nheko.paddingMedium
width: Nheko.avatarSize
height: Nheko.avatarSize
image: ":/icons/icons/ui/angle-arrow-left.svg"
ToolTip.visible: hovered
ToolTip.text: qsTr("Back")
onClicked: mainWindow.pop()
}
}

@ -8,6 +8,7 @@ import QtQuick 2.9
import QtQuick.Controls 2.5
import im.nheko 1.0
// FIXME(Nico): Don't use hardcoded colors.
Button {
id: control

@ -213,7 +213,7 @@ ApplicationWindow {
ToggleButton {
checked: imagePack.isEmotePack
onClicked: imagePack.isEmotePack = checked
onCheckedChanged: imagePack.isEmotePack = checked
Layout.alignment: Qt.AlignRight
}
@ -223,7 +223,7 @@ ApplicationWindow {
ToggleButton {
checked: imagePack.isStickerPack
onClicked: imagePack.isStickerPack = checked
onCheckedChanged: imagePack.isStickerPack = checked
Layout.alignment: Qt.AlignRight
}
@ -279,7 +279,7 @@ ApplicationWindow {
ToggleButton {
checked: imagePack.data(imagePack.index(currentImageIndex, 0), SingleImagePackModel.IsEmote)
onClicked: imagePack.setData(imagePack.index(currentImageIndex, 0), checked, SingleImagePackModel.IsEmote)
onCheckedChanged: imagePack.setData(imagePack.index(currentImageIndex, 0), checked, SingleImagePackModel.IsEmote)
Layout.alignment: Qt.AlignRight
}
@ -289,7 +289,7 @@ ApplicationWindow {
ToggleButton {
checked: imagePack.data(imagePack.index(currentImageIndex, 0), SingleImagePackModel.IsSticker)
onClicked: imagePack.setData(imagePack.index(currentImageIndex, 0), checked, SingleImagePackModel.IsSticker)
onCheckedChanged: imagePack.setData(imagePack.index(currentImageIndex, 0), checked, SingleImagePackModel.IsSticker)
Layout.alignment: Qt.AlignRight
}

@ -185,7 +185,7 @@ ApplicationWindow {
ToggleButton {
ToolTip.text: qsTr("Enables this pack to be used in all rooms")
checked: currentPack ? currentPack.isGloballyEnabled : false
onClicked: currentPack.isGloballyEnabled = !currentPack.isGloballyEnabled
onCheckedChanged: currentPack.isGloballyEnabled = checked
Layout.alignment: Qt.AlignRight
}

@ -214,7 +214,7 @@ ApplicationWindow {
id: encryptionToggle
checked: roomSettings.isEncryptionEnabled
onClicked: {
onCheckedChanged: {
if (roomSettings.isEncryptionEnabled) {
checked = true;
return ;

@ -86,6 +86,7 @@
<file>qml/CommunitiesList.qml</file>
<file>qml/RoomList.qml</file>
<file>qml/TimelineView.qml</file>
<file>qml/UserSettingsPage.qml</file>
<file>qml/Avatar.qml</file>
<file>qml/Completer.qml</file>
<file>qml/EncryptionIndicator.qml</file>

@ -56,11 +56,10 @@ MainWindow::MainWindow(QWidget *parent)
trayIcon_ = new TrayIcon(QStringLiteral(":/logos/nheko.svg"), this);
welcome_page_ = new WelcomePage(this);
login_page_ = new LoginPage(this);
register_page_ = new RegisterPage(this);
chat_page_ = new ChatPage(userSettings_, this);
userSettingsPage_ = new UserSettingsPage(userSettings_, this);
welcome_page_ = new WelcomePage(this);
login_page_ = new LoginPage(this);
register_page_ = new RegisterPage(this);
chat_page_ = new ChatPage(userSettings_, this);
// Initialize sliding widget manager.
pageStack_ = new QStackedWidget(this);
@ -68,7 +67,6 @@ MainWindow::MainWindow(QWidget *parent)
pageStack_->addWidget(login_page_);
pageStack_->addWidget(register_page_);
pageStack_->addWidget(chat_page_);
pageStack_->addWidget(userSettingsPage_);
setCentralWidget(pageStack_);
@ -93,13 +91,7 @@ MainWindow::MainWindow(QWidget *parent)
showLoginPage();
});
connect(userSettingsPage_, &UserSettingsPage::moveBack, this, [this]() {
pageStack_->setCurrentWidget(chat_page_);
});
connect(userSettingsPage_, SIGNAL(trayOptionChanged(bool)), trayIcon_, SLOT(setVisible(bool)));
connect(
userSettingsPage_, &UserSettingsPage::themeChanged, chat_page_, &ChatPage::themeChanged);
connect(userSettings_.get(), &UserSettings::trayChanged, trayIcon_, &TrayIcon::setVisible);
connect(trayIcon_,
SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this,
@ -109,8 +101,6 @@ MainWindow::MainWindow(QWidget *parent)
connect(this, &MainWindow::focusChanged, chat_page_, &ChatPage::chatFocusChanged);
connect(chat_page_, &ChatPage::showUserSettingsPage, this, &MainWindow::showUserSettingsPage);
connect(login_page_, &LoginPage::loginOk, this, [this](const mtx::responses::Login &res) {
http::client()->set_user(res.user_id);
showChatPage();
@ -247,14 +237,8 @@ MainWindow::showChatPage()
login_page_->reset();
chat_page_->bootstrap(userid, homeserver, token);
connect(cache::client(),
&Cache::databaseReady,
userSettingsPage_,
&UserSettingsPage::updateSecretStatus);
connect(cache::client(),
&Cache::secretChanged,
userSettingsPage_,
&UserSettingsPage::updateSecretStatus);
connect(cache::client(), &Cache::databaseReady, this, &MainWindow::secretsChanged);
connect(cache::client(), &Cache::secretChanged, this, &MainWindow::secretsChanged);
emit reload();
}
@ -403,9 +387,3 @@ MainWindow::showRegisterPage()
pageStack_->addWidget(register_page_);
pageStack_->setCurrentWidget(register_page_);
}
void
MainWindow::showUserSettingsPage()
{
pageStack_->setCurrentWidget(userSettingsPage_);
}

@ -84,9 +84,6 @@ private slots:
//! Show the register page in the main window.
void showRegisterPage();
//! Show user settings page.
void showUserSettingsPage();
//! Show the chat page and start communicating with the given access token.
void showChatPage();
@ -98,6 +95,7 @@ private slots:
signals:
void focusChanged(const bool focused);
void reload();
void secretsChanged();
private:
void showDialog(QWidget *dialog);
@ -120,7 +118,6 @@ private:
QStackedWidget *pageStack_;
//! The main chat area.
ChatPage *chat_page_;
UserSettingsPage *userSettingsPage_;
QSharedPointer<UserSettings> userSettings_;
//! Tray icon that shows the unread message count.
TrayIcon *trayIcon_;

File diff suppressed because it is too large Load Diff

@ -6,6 +6,7 @@
#pragma once
#include <QAbstractListModel>
#include <QFontDatabase>
#include <QFrame>
#include <QProcessEnvironment>
@ -353,89 +354,125 @@ private:
static QSharedPointer<UserSettings> instance_;
};
class HorizontalLine : public QFrame
class UserSettingsModel : public QAbstractListModel
{
Q_OBJECT
public:
HorizontalLine(QWidget *parent = nullptr);
};
class UserSettingsPage : public QWidget
{
Q_OBJECT
enum Indices
{
GeneralSection,
Theme,
MobileMode,
#ifndef Q_OS_MAC
ScaleFactor,
#endif
Font,
FontSize,
EmojiFont,
AvatarCircles,
UseIdenticon,
PrivacyScreen,
PrivacyScreenTimeout,
TimelineSection,
TimelineMaxWidth,
MessageHoverHighlight,
EnlargeEmojiOnlyMessages,
AnimateImagesOnHover,
TypingNotifications,
ReadReceipts,
ButtonsInTimeline,
Markdown,
SidebarSection,
GroupView,
SortByImportance,
DecryptSidebar,
TraySection,
Tray,
StartInTray,
NotificationsSection,
DesktopNotifications,
AlertOnNotification,
VoipSection,
UseStunServer,
Microphone,
Camera,
CameraResolution,
CameraFrameRate,
Ringtone,
EncryptionSection,
OnlyShareKeysWithVerifiedUsers,
ShareKeysWithTrustedUsers,
SessionKeys,
UseOnlineKeyBackup,
OnlineBackupKey,
SelfSigningKey,
UserSigningKey,
MasterKey,
CrossSigningSecrets,
DeviceId,
DeviceFingerprint,
LoginInfoSection,
UserId,
Homeserver,
Profile,
Version,
Platform,
COUNT,
// hidden for now
AccessToken,
#ifdef Q_OS_MAC
ScaleFactor,
#endif
};
public:
UserSettingsPage(QSharedPointer<UserSettings> settings, QWidget *parent = nullptr);
protected:
void showEvent(QShowEvent *event) override;
void paintEvent(QPaintEvent *event) override;
signals:
void moveBack();
void trayOptionChanged(bool value);
void themeChanged();
void decryptSidebarChanged();
enum Types
{
Toggle,
ReadOnlyText,
Options,
Number,
SectionTitle,
SectionBar,
KeyStatus,
SessionKeyImportExport,
XSignKeysRequestDownload,
};
Q_ENUM(Types);
public slots:
void updateSecretStatus();
enum Roles
{
Name,
Description,
Value,
Type,
ValueLowerBound,
ValueUpperBound,
ValueStep,
Values,
Good,
Enabled,
};
private slots:
void importSessionKeys();
void exportSessionKeys();
UserSettingsModel(QObject *parent = nullptr);
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
(void)parent;
return (int)COUNT;
}
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
private:
// Layouts
QVBoxLayout *topLayout_;
QHBoxLayout *topBarLayout_;
QFormLayout *formLayout_;
// Shared settings object.
QSharedPointer<UserSettings> settings_;
Toggle *trayToggle_;
Toggle *startInTrayToggle_;
Toggle *groupViewToggle_;
Toggle *timelineButtonsToggle_;
Toggle *typingNotifications_;
Toggle *messageHoverHighlight_;
Toggle *enlargeEmojiOnlyMessages_;
Toggle *sortByImportance_;
Toggle *readReceipts_;
Toggle *markdown_;
Toggle *animateImagesOnHover_;
Toggle *desktopNotifications_;
Toggle *alertOnNotification_;
Toggle *avatarCircles_;
Toggle *useIdenticon_;
Toggle *useStunServer_;
Toggle *decryptSidebar_;
Toggle *privacyScreen_;
QSpinBox *privacyScreenTimeout_;
Toggle *shareKeysWithTrustedUsers_;
Toggle *onlyShareKeysWithVerifiedUsers_;
Toggle *useOnlineKeyBackup_;
Toggle *mobileMode_;
QLabel *deviceFingerprintValue_;
QLabel *deviceIdValue_;
QLabel *backupSecretCached;
QLabel *masterSecretCached;
QLabel *selfSigningSecretCached;
QLabel *userSigningSecretCached;
QComboBox *themeCombo_;
QComboBox *scaleFactorCombo_;
QComboBox *fontSizeCombo_;
QFontComboBox *fontSelectionCombo_;
QComboBox *emojiFontSelectionCombo_;
QComboBox *ringtoneCombo_;
QComboBox *microphoneCombo_;
QComboBox *cameraCombo_;
QComboBox *cameraResolutionCombo_;
QComboBox *cameraFrameRateCombo_;
QSpinBox *timelineMaxWidthSpin_;
int sideMargin_ = 0;
Q_INVOKABLE void importSessionKeys();
Q_INVOKABLE void exportSessionKeys();
Q_INVOKABLE void requestCrossSigningSecrets();
Q_INVOKABLE void downloadCrossSigningSecrets();
};

@ -394,7 +394,7 @@ utils::humanReadableFingerprint(const QString &ed25519)
QString fingerprint;
for (int i = 0; i < ed25519.length(); i = i + 4) {
fingerprint.append(QStringView(ed25519).mid(i, 4));
if (i > 0 && i % 16 == 12)
if (i > 0 && i == 20)
fingerprint.append('\n');
else if (i < ed25519.length())
fingerprint.append(' ');

@ -259,6 +259,10 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
"im.nheko", 1, 0, "Nheko", [](QQmlEngine *, QJSEngine *) -> QObject * {
return new Nheko();
});
qmlRegisterSingletonType<UserSettingsModel>(
"im.nheko", 1, 0, "UserSettingsModel", [](QQmlEngine *, QJSEngine *) -> QObject * {
return new UserSettingsModel();
});
qmlRegisterSingletonInstance("im.nheko", 1, 0, "VerificationManager", verificationManager_);
qmlRegisterSingletonInstance("im.nheko", 1, 0, "Presence", presenceEmitter);
qmlRegisterSingletonType<SelfVerificationStatus>(

Loading…
Cancel
Save